<?php
namespace Modules\Invoices\Cashings\Management;

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

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

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

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

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

		$this->actionsCfg['insert'] =	['checkSection' => false, 'checkOption' => false,];
		$this->actionsCfg['update'] =	['checkSection' => false, 'checkOption' => false,];
		$this->actionsCfg['block'] 	=	['checkSection' => false, 'checkOption' => false,];
		$this->actionsCfg['unblock']=	['checkSection' => false, 'checkOption' => false,];

		unset($this->actionsCfg['delete']);

	}


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

		switch($option->getId()) {
			case 'insert':
				$option->determineOperationAvailability(\Entity\InvoiceCashing::insert());

				$filters = $this->loadListingParams([])->getListingParams()->getFilters();
				if ($filters['idInvoice']) {
					$invoiceEntity = \Entity\Invoice::select($filters['idInvoice']);

					// invoice is not issued
					if (!\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('Modules/Invoices/Cashings/Listing-cashInvoiceNotIssued') && !$invoiceEntity->issueTime) {
						$option->setDisabled();
						$option->addMessage('warning', $this->lang['index']['options']['reasons']['cashInvoice']['cantCashNotEmitedInvoice']);
						break;
					}
				}
			break;

			case 'issue':
				// if user has access
				if (!\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('cashingDocumentsManagement')) {
					$option->setDisabled()->addMessage('warning', $this->globalLang['noAccessToOption']);
					break;
				}

				// doc not configured to be generated
				foreach ($selection as $selectedItem) {
					$option->determineIconGeneratedDocuments($selectedItem);
					$docType = \Entity\InvoiceCashing::select($selectedItem)->docType;
					if (!\App\Config\IssueDocuments::getInstance()->getCashingDocsList($docType)) {
						$option->setDisabled()->addMessage('warning', $this->lang['messages']['docNotIssueable']);
						break;
					}
				}
			break;

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

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

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

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

			case 'remoteLoad':
			break;

			case 'transferToCredit':
				$filters = $this->loadListingParams([])->getListingParams()->getFilters();
				if ($filters['idInvoice']) {
					$transferToCredit = new \Modules\Invoices\Cashings\Management\TransferToCredit\Model($filters['idInvoice']);

					try {
						$transferToCredit->isAvailable(false);
					} catch (\App\MessagesException $e) {
						$option->setDisabled()->addMessage('warning', $e->getMessagesCollector()->getMessageBulk());
						break;
					}
				}

			break;

			default:
				return false;
		}

		return true;
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\ListingAbstract::filterOptionsForSections()
	 */
	public function filterOptionsForSections(\App\Mvc\View\Utils\RowOptions\Container\Simple $options, array $sections)
	{
		if (!count($options->getContainer('cashingInsertOptions')->getAllEnabled())) {
			$options->getContainer('cashingInsertOptions')->setHidden();
		}

		return parent::filterOptionsForSections($options, $sections);
	}

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

		$invEnt = \Entity\Invoice::select($R['idInvoice']);

		$formData = [];

		if ($R['typeChanged']) {
			$formData = $R;

			// get doc series
			if (!$R['idImportedDocument']) {
				if (\App\Config\CashingDocuments::getInstance()->getNumber($formData['docType'])=="series") {
					$issueDocs = \App\Config\IssueDocuments::getInstance()->getCashingDocsList($formData['docType']);
					$var = 'defaultDocSeries_'.key($issueDocs); // sets the series of the first issue docs on this doc type
					$formData['idCashingSeries'] = (Int)\App\EntityPreference\User::getInstance()->$var;
				}
			}

		}
		else {

			// FOR NORMAL (MANUAL) DOCUMENT
			if (!$R['idImportedDocument']) {
				// document type
				$formData['docType'] = $this->cfg['addDocument']['docType'];

				// document date
				$formData['docDate'] = TODAY_ISO;

				// document currency
				$formData['docValue']['currency'] = $invEnt->currency;

				// document value
				$formData['docValue']['value'] = \App\Config\CurrencyDecimals::roundPrice($invEnt->printTotal-$invEnt->cashedTotal, $invEnt->currency);

				// get doc series
				if (\App\Config\CashingDocuments::getInstance()->getNumber($formData['docType'])=="series") {
					$issueDocs = \App\Config\IssueDocuments::getInstance()->getCashingDocsList($formData['docType']);
					$var = 'defaultDocSeries_'.key($issueDocs); // sets the series of the first issue docs on this doc type
					$formData['idCashingSeries'] = (Int)\App\EntityPreference\User::getInstance()->$var;
				}

				// document remarks
				$formData['remarks'] = $this->cfg['addDocument']['remarks'];

				// document responsible
				$formData['idOffice']['id'] = CURRENT_ID_OFFICE;
				$formData['idUser']['id'] = CURRENT_ID_USER;

			}
			// FOR IMPORTED DOCUMENT
			else {
				$impDocEnt = \Entity\ImportedDocument::select($R['idImportedDocument']);
				$impDocObj = $impDocEnt->object;

				// document type
				$formData['docType'] = $impDocObj->docType;

				// document date
				$formData['docDate'] = $impDocObj->docDate;

				// document currency - always force the currency to be the same as the imported document's
				$formData['docValue']['currency'] = $impDocObj->currency;

				// get limit processing value
				$limitProcessingValue = ($invEnt->printTotal>0)?PHP_INT_MAX:-PHP_INT_MAX;
				if ($impDocEnt->object->getInvoicesList()) {
					foreach($impDocEnt->object->getInvoicesList() as $clientInvoiceObj) {
						if (in_array($R['idInvoice'], $clientInvoiceObj->getMatchedIds())) {
							if ($clientInvoiceObj->limitProcessingValue) {
								$limitProcessingValue = $clientInvoiceObj->limitProcessingValue;
							}
							break;
						}
					}
				}

				// document value
				if ($invEnt->printTotal>0) {  // inv total > 0 ; min (imp doc unused value, invoice total)
					$formData['docValue']['value'] = min (
						$limitProcessingValue,
						($impDocObj->value-$impDocEnt->usedValue),
						\App\CurrencyExchange\Rates::getInstance($impDocObj->docDate)->convert( ($invEnt->printTotal-$invEnt->cashedTotal), $invEnt->currency, $impDocObj->currency)
					);
				}
				else {  // inv total < 0 ; max (imp doc unused value, invoice total)
					$formData['docValue']['value'] = max (
						$limitProcessingValue,
						($impDocObj->value-$impDocEnt->usedValue),
						\App\CurrencyExchange\Rates::getInstance($impDocObj->docDate)->convert( ($invEnt->printTotal-$invEnt->cashedTotal), $invEnt->currency, $impDocObj->currency)
					);
				}

				// other fields
				$formData['docNumber'] = $impDocEnt->docNumber; // number mey be changed meanwhile by issuing the imported doc
				$formData['explanations'] = $impDocObj->explanations;
				$formData['comments'] = $impDocObj->comments;
				$formData['remarks'] = $impDocObj->remarks;

				// match the bank account
				if ($impDocObj->getAgencyBankAccount()) {
					$formData['idBankAccount'] = $impDocObj->getAgencyBankAccount()->getMatchedId($impDocEnt->idExternalSystem);
				}

				// the external system id
				$idExternalSystem = $impDocObj->getIdExternalSystem();

				// document responsible
				$idUser = null;
				$idOffice = null;
				if ($impDocObj->getResponsibleUser()) {
					$idUser = $impDocObj->getResponsibleUser()->getMatchedId($idExternalSystem);
				}
				if ($impDocObj->getResponsibleOffice()) {
					$idOffice = $impDocObj->getResponsibleOffice()->getMatchedId($idExternalSystem);
				}

				if ($idUser) {
					$formData['idUser']['id'] = $idUser;
					if ($idOffice) {
						$formData['idOffice']['id'] = $idOffice;
					} else {
						$formData['idOffice']['id'] = \Entity\User::select($idUser)->idOffice;
					}
				}
				else {
					$formData['idUser']['id'] = CURRENT_ID_USER;
					$formData['idOffice']['id'] = CURRENT_ID_OFFICE;
				}

			}
		}

		if ($this->cfg['addDocument']['bankAccount'] == 'invoice' and !$R['idBankAccount']) {
			$invoiceEnt = \Entity\Invoice::selectForUpdate($R['idInvoice']);
			// match the bank account
			if ($invoiceEnt->idBankAccount) {
				$formData['idBankAccount'] = $invoiceEnt->idBankAccount;
			}
		}

		$formData['idInvoice'] = $R['idInvoice'];
		$formData['idImportedDocument'] = $R['idImportedDocument'];

		return $formData;
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedEntityListing::insert_createEntityObject()
	 */
	protected function insert_createEntityObject($formData)
	{
		$invoiceCashingEntity = \Entity\InvoiceCashing::insert();
		$invoiceCashingEntity->idInvoice = 		$formData['idInvoice'];
		$invoiceCashingEntity->docType = 		$formData['docType'];
		$invoiceCashingEntity->docDate = 		$formData['docDate'];

		if (isset($formData['docNumber'])) {
			$invoiceCashingEntity->docNumber = 	$formData['docNumber'];
		}
		if (isset($formData['idCashingSeries'])) {
			$invoiceCashingEntity->idCashingSeries = $formData['idCashingSeries'];
		}

		$invoiceCashingEntity->value =			$formData['docValue']['value'];
		$invoiceCashingEntity->currency = 		$formData['docValue']['currency'];
		$invoiceCashingEntity->remarks =		$formData['remarks'];

		if (isset($formData['idBankAccount'])) {
			$invoiceCashingEntity->idBankAccount = 	$formData['idBankAccount'];
		}

		if (isset($formData['explanations'])) {
			$invoiceCashingEntity->explanations = 	$formData['explanations'];
		}

		if (isset($formData['comments'])) {
			$invoiceCashingEntity->comments = 		$formData['comments'];
		}

		if ($formData['idImportedDocument']) {
			$invoiceCashingEntity->idImportedDoc = 	$formData['idImportedDocument'];
		}

		$invoiceCashingEntity->idUser = 		$formData['idUser']['id'];
		$invoiceCashingEntity->idOffice = 		$formData['idOffice']['id'];

		// trigger that allows any plugin to change the entity before insert
		\Engine\Plugins\Manager::getInstance()->executeEvent('Modules\Invoices\Cashings\Management-insert-extendCreateEntityObject', [
			'formData' => $formData,
			'invoiceCashingEntity'=>$invoiceCashingEntity,
		]);

		return $invoiceCashingEntity;
	}

	/**
	 * We need to overwrite actionUpdate() and redefine update_getDefaultFormData() under a new  name in order to process $R
	 */
	protected function actionUpdate($R)
	{

		$msgs = \App\MessagesCollector::create();

		$this->updateIdRecord = $R['id'];

		// execute the model (and collect the output)
		$modelOutput = false;
		if ($R[$this->formSubmitButtonName]) {
			$modelOutput = $this->update_doUpdate($R, $msgs);
		}

		// instantiate the view
		$view = new View_Update($this);

		// get form data for this operation
		if (!$R[$this->formSubmitButtonName]) {
			$formData = $this->actionUpdate_getDefaultFormData($this->updateIdRecord, $R);
			if ($formData!==null) {
				$formData['id']=$this->updateIdRecord;
			}
		} else {
			$formData=$R;
		}

		// send data to the view
		$view->addInput('formData', $formData);
		if ($modelOutput) {
			$view->setClosePopup(true);
		}
		$view->getMessagesCollector()->appendMessages($msgs);
		$view->addInput('formSubmitButtonName', $this->formSubmitButtonName);

		// render the view
		return new \Engine\Mvc\Response\Html($view->render());
	}

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

	/**
	 * @param integer $idEntity
	 * @param Array $R
	 */
	protected function actionUpdate_getDefaultFormData($idEntity, $R)
	{
		$invoiceCashingEntity = \Entity\InvoiceCashing::select($idEntity);
		if (!$invoiceCashingEntity->recordExists()) {
			return null;
		}

		$formData = [];

		if ($R['typeChanged']) {
			$formData = $R;

			if ($invoiceCashingEntity->idImportedDoc) {
				$formData['docValue']['value'] 	  	= \App\Config\CurrencyDecimals::roundPrice($invoiceCashingEntity->value, $invoiceCashingEntity->currency);
				$formData['docValue']['currency'] 	= $invoiceCashingEntity->currency;
			}
		}
		else {
			$formData['idInvoice'] 				= $invoiceCashingEntity->idInvoice;
			$formData['docType'] 				= $invoiceCashingEntity->docType;
			$formData['idCashingSeries'] 		= $invoiceCashingEntity->idCashingSeries;
			if ($invoiceCashingEntity->docNumber) {
				$formData['docNumber'] 			= $invoiceCashingEntity->docNumber;
			}
			$formData['docDate']   				= $invoiceCashingEntity->docDate;
			$formData['docValue']['value'] 	  	= \App\Config\CurrencyDecimals::roundPrice($invoiceCashingEntity->value, $invoiceCashingEntity->currency);
			$formData['docValue']['currency'] 	= $invoiceCashingEntity->currency;
			$formData['idBankAccount'] 			= $invoiceCashingEntity->idBankAccount;
			$formData['explanations']  			= $invoiceCashingEntity->explanations;
			$formData['comments'] 				= $invoiceCashingEntity->comments;
			$formData['remarks']  				= $invoiceCashingEntity->remarks;
			$formData['idOffice']['id'] 		= $invoiceCashingEntity->idOffice;
			$formData['idUser']['id'] 			= $invoiceCashingEntity->idUser;
			$formData['idImportedDocument'] 	= $invoiceCashingEntity->idImportedDoc;
		}

		return $formData;
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedEntityListing::update_createEntityObject()
	 */
	protected function update_createEntityObject($formData)
	{
		$invoiceCashingEntity = \Entity\InvoiceCashing::update($this->updateIdRecord);

		if (isset($formData['docType'])) {
			$invoiceCashingEntity->docType = 		$formData['docType'];
		}

		if (isset($formData['docDate'])) {
			$invoiceCashingEntity->docDate = 		$formData['docDate'];
		}

		if (isset($formData['docNumber'])) {
			$invoiceCashingEntity->docNumber = 		$formData['docNumber'];
		}

		if (isset($formData['idCashingSeries'])) {
			$invoiceCashingEntity->idCashingSeries = $formData['idCashingSeries'];
		} else {
			$invoiceCashingEntity->idCashingSeries = 0;
		}

		if (isset($formData['docValue'])) {
			if (!$formData['idImportedDocument']) {
				$invoiceCashingEntity->value =			$formData['docValue']['value'];
				$invoiceCashingEntity->currency = 		$formData['docValue']['currency'];
			}
		}

		if (isset($formData['remarks'])) {
			$invoiceCashingEntity->remarks =		$formData['remarks'];
		}

		if (isset($formData['idBankAccount'])) {
			$invoiceCashingEntity->idBankAccount = 	$formData['idBankAccount'];
		} else {
			$invoiceCashingEntity->idBankAccount = 0;
		}

		if (isset($formData['explanations'])) {
			$invoiceCashingEntity->explanations = 	$formData['explanations'];
		}

		if (isset($formData['comments'])) {
			$invoiceCashingEntity->comments = 		$formData['comments'];
		}

		if (isset($formData['idUser']['id'])) {
			$invoiceCashingEntity->idUser = 		$formData['idUser']['id'];
		}

		if (isset($formData['idOffice']['id'])) {
			$invoiceCashingEntity->idOffice = 		$formData['idOffice']['id'];
		}

		return $invoiceCashingEntity;
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedEntityListing::delete_createEntityObject()
	 */
	protected function delete_createEntityObject($idRecord)
	{
		// defined only because it's abstract
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\ListingAbstract::optionGetEntityName()
	 */
	protected function optionGetEntityName($id)
	{
		return \Entity\InvoiceCashing::select($id)->getId();
	}

	/**
	 * Block cashing
	 * @param array $recordsIds
	 * @param \App\MessagesCollector $msgs
	 * @param array $R
	 */
	protected function actionBlock($R)
	{
		$msgs = \App\MessagesCollector::create();
		$this->setListingSelection($R['listing']['selection']);

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

		foreach ($selIds as $id) {
			\DB::startTransaction();

			try {
				// update the document
				$invoiceCashingEntity = \Entity\InvoiceCashing::block($id);
				$invoiceCashingEntity->save();

				// commit the transaction
				\DB::commitTransaction();
				// remove this record from the internal list
				$this->getListingSelection()->delete([$id]);
				$msgs->addSuccess($this->lang['block']['successMessage']);
			}
			catch (\App\Entity\Exception $ex) {
				\DB::rollbackTransaction();
				$msgs->addError($ex->getMessage());
			}
		}

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


	/**
	 * Unblock cashing
	 * @param array $recordsIds
	 * @param \App\MessagesCollector $msgs
	 * @param array $R
	 */
	protected function actionUnblock($R)
	{
		$msgs = \App\MessagesCollector::create();
		$this->setListingSelection($R['listing']['selection']);

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

		foreach ($selIds as $id) {
			\DB::startTransaction();

			try {
				// update the document
				$invoiceCashingEntity = \Entity\InvoiceCashing::unblock($id);
				$invoiceCashingEntity->save();

				// commit the transaction
				\DB::commitTransaction();
				// remove this record from the internal list
				$this->getListingSelection()->delete([$id]);
				$msgs->addSuccess($this->lang['unblock']['successMessage']);
			}
			catch (\App\Entity\Exception $ex) {
				\DB::rollbackTransaction();
				$msgs->addError($ex->getMessage());
			}
		}

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

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\ListingAbstract::actionIndex_preRender()
	 */
	protected function actionIndex_preRender(\App\Mvc\ModelAbstract $model, \App\Mvc\ViewAbstract $view, Array $R)
	{
		$invEnt = \Entity\Invoice::select( $this->getListingParams()->getFilters()['idInvoice'] );

		$view->setOutputVar('invEnt', $invEnt);
	}

}
