<?php
// TODO: vezi plugin pt validare (happy_...)

namespace Entity;

class Validator_Supplier extends \App\Entity\Utils\Extension_ValidateDefaultAbstract
{

	protected function isAccessible_insert()
	{

		// get entity messages
		$currMessages=$this->entity->getMessages();

		// check user access
		if (!\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('Modules/Partners/Suppliers-insert')) {
			$currMessages->addWarningCode('noAccessToOption');
		}

	}

	protected function check_insert()
	{
		$this->validateAux_insertUpdate();
	}

	protected function isAccessible_update()
	{
		// get entity messages
		$currMessages=$this->entity->getMessages();

		// check user access
		if (!\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('Modules/Partners/Suppliers-update')) {
			$currMessages->addWarningCode('noAccessToOption');
		}

	}

	protected function isAvailable_update()
	{
		// current entity id
		$currentIdEntity=$this->entity->getId();

		// current collected messages
		$currMessages=$this->entity->getMessages();

		$OK=true;

		// CHECK THE SUPPLIER (deleted, canDelete) ------------------------------------------------
		$supplierObj = \Entity\Supplier::selectForUpdate($currentIdEntity);
		// check supplier id
		if (!$supplierObj->recordExists()) {
			$currMessages->addErrorCode('update_invalidSupplierId');
		}
		// check if supplier is already deleted
		elseif ($supplierObj->deleted) {
			$currMessages->addWarningCode('update_supplierDel');
			$OK=false;
		}

		return $OK;
	}

	protected function check_update()
	{
		$fields = $this->entity->getFields();

		$currMessages=$this->entity->getMessages();

		// check if the user has access to lock/unlock
		if (array_key_exists('locked', $fields) and !\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('Modules/Partners/Suppliers-lock')) {
			$currMessages->addWarningCode('noAccessToOption');
		}

		// STANDARD CHECKS FOR THE SUPPLIER UPDATE ////////////////////////////////////////////////
		$this->validateAux_insertUpdate();

		// validate idGroupElements ///////////////////////////////////////////////////////////////
		$this->check_update_idGroupElements();

	}


	protected function isAccessible_delete()
	{
		// get entity messages
		$currMessages=$this->entity->getMessages();

		// check user access
		if (!\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('Modules/Partners/Suppliers-delete')) {
			$currMessages->addWarningCode('noAccessToOption');
		}
	}

	protected function isAvailable_delete()
	{

		// current entity id
		$currentIdEntity=$this->entity->getId();

		// current collected messages
		$currMessages=$this->entity->getMessages();

		$OK=true;

		// CHECK THE SUPPLIER (deleted, canDelete) ------------------------------------------------
		$supplierObj=Supplier::selectForUpdate($currentIdEntity);
		// check supplier id
		if (!$supplierObj->recordExists()) {
			$currMessages->addErrorCode('delete_suppIdInvalid');
		}
		// check if supplier is already deleted
		elseif ($supplierObj->deleted) {
			$currMessages->addWarningCode('delete_suppDeleted');
			$OK=false;
		}
		// check if supplier can be deleted
		elseif (!$supplierObj->canDelete) {
			$currMessages->addWarningCode('delete_suppCantBeDeleted');
			$OK=false;
		}

		return $OK;

	}

	/**
	 * check if the mark duplicate action can be done
	 */
	protected function isAvailable_markDuplicate()
	{
		$currentMessages = $this->entity->getMessages();

		$supplier = \Entity\Supplier::selectForUpdate($this->entity->getId());

		if (!$supplier->recordExists()) {
			$currentMessages->addErrorCode('markDuplicate_custIdInvalid');
		}
		elseif ($supplier->deleted) {
			$currentMessages->addWarningCode('markDuplicated_custIdInvalid');
		}

		if ($supplier->idRealSupplier) {
			$currentMessages->addWarningCode('passengerHasRealSupplier');
		}
	}

	protected function check_markDuplicate()
	{
		$currentMessages = $this->entity->getMessages();

		$fields = $this->entity->getFields();

		if (!is_array($fields['duplicatedSuppliers'])) {
			throw new \Exception("The field `duplicatedSuppliers` can only be set as an array.");
		}

		foreach ($fields['duplicatedSuppliers'] as $idSupplier) {
			if ($idSupplier == $this->entity->getId()) {
				$currentMessages->addWarningCode('supplierMainAndDuplicated');
			}

			$supplier = \Entity\Supplier::selectForUpdate($idSupplier);

			if (!$supplier->recordExists()) {
				$currentMessages->addErrorCode('markDuplicate_custIdInvalid');
			}
			elseif ($supplier->deleted) {
				$currentMessages->addWarningCode('markDuplicated_custIdInvalid');
			}

			if ($supplier->duplicatedSuppliersList) {
				$currentMessages->addWarningCode('supplierHasDuplicatedSuppliers');
			}

		}
	}

	/**
	 * check if the unmark duplicate action can be done
	 */
	protected function isAvailable_unmarkDuplicate()
	{
		$currentMessages = $this->entity->getMessages();

		$supplier = \Entity\Supplier::selectForUpdate($this->entity->getId());

		if (!$supplier->recordExists()) {
			$currentMessages->addErrorCode('update_custIdInvalid');
		}
		elseif ($supplier->deleted) {
			$currentMessages->addWarningCode('update_custIdInvalid');
		}

		if (!$supplier->idRealSupplier and !$supplier->duplicatedSuppliersList) {
			$currentMessages->addWarningCode('supplierNotRealOrDuplicated');
		}
	}


	/**
	 * Does all the validations needed by insert and update operations.
	 */
	private function validateAux_insertUpdate()
	{

		// CHECK STANDARD FIELDS ------------------------------------------------------------------
		$this->validateAux_stdFields();

		// CHECK LOCATION -------------------------------------------------------------------------
		$this->validateAux_place();

		// CHECK BANK ACCOUNTS --------------------------------------------------------------------
		$this->validateAux_bankAccounts();

		// CHECK CODES ----------------------------------------------------------------------------
		$this->validateAux_codes();

		// CHEK QC RULES --------------------------------------------------------------------------
		$this->validateAux_checkQcRules();

		// CHECK ADDRESS DETAILS -------------------------------------------------------------------
		$this->validateAux_checkAddressDetails();

		// CHECK ACCOUNTING NUMBER ----------------------------------------------------------------
		$this->validateAux_accountingNumber();

	}


	/**
	 * Checks standard fields for suppliers (alias, company, fiscal code, regNo - for uniqueness
	 * and trust for its id).
	 * @return boolean
	 */
	private function validateAux_stdFields(): void
	{

		// configs
		$cfg=$this->entity->getCFG();

		// get current fields details
		$fields=$this->entity->getFields();

		// current collected messages
		$currMessages=$this->entity->getMessages();

		// current entity id
		$currentIdEntity = $this->entity->getId();

		// the current operation
		$operation = $this->entity->getOperation();

		// load global cfgs
		$CFG = \Engine\Loader_Cfg::getInstance()->getGlobal();

		$OK=true;

		// CHECK THAT ALIAS IS UNIQUE -------------------------------------------------------------
		if (array_key_exists('alias', $fields) and $fields['alias']) {
			$supplierObj = new \App\EntityList\Suppliers();
			if ($operation == 'update') {
				$supplierObj->setFilter('supp.id', '!=', $currentIdEntity);
			}
			$supplierObj->setFilter('supp.alias', 'LIKE', $fields['alias']);
			$supplierObj->setLimit(1);
			$supplierArray = $supplierObj->exportRecords();

			if ($supplierArray) {
				$currMessages->addWarningCode('aliasNotUnique', 'alias');
			}
		}

		// CHECK THAT COMPANY IS UNIQUE -----------------------------------------------------------
		if ($cfg['company']['unique'] and $fields['company']) {
			$supplierObj = new \App\EntityList\Suppliers();
			$supplierObj->setColumns(['supp.alias']);
			if ($operation == 'update') {
				$supplierObj->setFilter('supp.id', '!=', $currentIdEntity);
			}
			$supplierObj->setFilter('supp.company', 'LIKE', $fields['company']);
			$supplierObj->setLimit(1);
			$supplierArray = $supplierObj->exportRecords();

			if ($supplierArray) {
				$currMessages->addWarningCode('companyNotUnique', 'company', $supplierArray[0]['alias']);
			}

		}

		// CHECK THAT FISCAL CODE IS UNIQUE -------------------------------------------------------
		if ($cfg['fiscalCode']['unique'] and $fields['fiscalCode']) {
			$supplierObj = new \App\EntityList\Suppliers();
			$supplierObj->setColumns(['supp.alias']);
			if ($operation == 'update') {
				$supplierObj->setFilter('supp.id', '!=', $currentIdEntity);
			}
			$supplierObj->setFilter('supp.fiscalCode', 'LIKE', $fields['fiscalCode']);
			$supplierObj->setLimit(1);
			$supplierArray = $supplierObj->exportRecords();

			if ($supplierArray) {
				$currMessages->addWarningCode('fcNotUnique', 'fiscalCode', $supplierArray[0]['alias']);
			}
		}

		// CHECK THAT REG NO CODE IS UNIQUE -------------------------------------------------------
		if ($cfg['regNo']['unique'] and $fields['regNo']) {
			$supplierObj = new \App\EntityList\Suppliers();
			$supplierObj->setColumns(['supp.alias']);
			if ($operation == 'update') {
				$supplierObj->setFilter('supp.id', '!=', $currentIdEntity);
			}
			$supplierObj->setFilter('supp.regNo', 'LIKE', $fields['regNo']);
			$supplierObj->setLimit(1);
			$supplierArray = $supplierObj->exportRecords();

			if ($supplierArray) {
				$currMessages->addWarningCode('regNoNotUnique', 'regNo', $supplierArray[0]['alias']);
			}

		}

		// CHECK THAT TRUST IS CORRECT (id is valid, not deleted, has the correct type) -----------
		if ($fields['idTrust']) {
			$trust = \Entity\Trust::selectForUpdate($fields['idTrust']);
			if (!$trust->recordExists()) {
				$currMessages->addErrorCode('trustIdNotValid', 'idTrust');
			}
			elseif ($trust->deleted) {
				$currMessages->addWarningCode('trustDeleted', 'idTrust');
				$OK=false;
			}
			elseif ($trust->type!='supplier') {
				$currMessages->addWarningCode('trustNotSupplier', 'idTrust');
				$OK=false;
			}
		}

		// CHECK COMPANY SUFFIX AND PREFIX --------------------------------------------------------
		if ($fields['companyPrefix'] and !in_array($fields['companyPrefix'], $CFG['generalData']['companyPrefix'])) {
			$currMessages->addWarningCode('companyPrefixInvalid', 'company');
			$OK=false;
		}
		if ($fields['companySuffix'] and !in_array($fields['companySuffix'], $CFG['generalData']['companySuffix'])) {
			$currMessages->addWarningCode('companySuffixInvalid', 'company');
			$OK=false;
		}

		// CHECK THAT lockedComments IS SET ONLY IF locked IS SET ---------------------------------
		if ($fields['lockedComments'] and !array_key_exists('locked', $fields)) {
			throw new \Exception('Cannot set `lockedComments` without setting up `locked` key for suppliers insertion.');
		}

		// CHECK THAT IF locked IS SET TO TRUE, lockedComments IS ALSO SET ------------------------
		if ($fields['locked'] and !$fields['lockedComments']) {
			$currMessages->addWarningCode('noLockedComments');
			$OK=false;
		}

		// CHECK THE PAYMENT POSSIBILITIES --------------------------------------------------------
		if (array_key_exists('paymentPossibilities', $fields)) {
			// check if array
			if (!is_array($fields['paymentPossibilities'])) {
				throw new \Exception("The supplier `paymentPossibilities` field must be set as an array.");
			}
			// check pp values
			foreach($fields['paymentPossibilities'] as $pp) {
				if (!\App\Config\FormsOfPayment::getInstance()->check($pp)) {
					$currMessages->addErrorCode('paymentPosInvalid', 'paymentPossibilities', $pp);
				}
			}
		}

		// CHECK IF THE VAT CERTIFICATE NUMBER IS MANDATORY ///////////////////////////////////////
		// it is a special validation as vatCertificateNumber field depends on vatRegistered field

		// first of all, on update, both fields must be set or nont
		if ($operation=='update') {
			if (
				(key_exists('vatRegistered', $fields) and !key_exists('vatCertificateNumber', $fields))
				or (key_exists('vatCertificateNumber', $fields) and !key_exists('vatRegistered', $fields))
			) {
				throw new \Exception('Both vatRegistered and vatCertificateNumber fields must be set or not on update action');
			}
		}
		// check the VAT certificate number on
		if ($cfg['vatCertificateNumber']['mandatoryWhenVatRegistered']) {
			if ($operation=='insert' or key_exists('vatRegistered', $fields)) { // on insert or update on these two fields
				if ($fields['vatRegistered'] and !strlen($fields['vatCertificateNumber'])) {
					$currMessages->addWarningCode('vatCertifNumberMandatory', 'vatCertificateNumber');
				}
			}
		}

	}

	/**
	 * Validates the country/city details for this supplier.
	 * @throws \Exception
	 * @return boolean - true if all checks are ok
	 */
	private function validateAux_place()
	{

		// get current fields details
		$fields=$this->entity->getFields();

		// current collected messages
		$currMessages=$this->entity->getMessages();

		// if location not set - skip this method
		if (!array_key_exists('countryCode', $fields) and !array_key_exists('cityId', $fields)) {
			return true;
		}

		// check country code and city id
		if (!array_key_exists('countryCode', $fields) or !array_key_exists('cityId', $fields)) {
			throw new \Exception('Country code and city id must both be set (or none of them).');
		}

		// check country code
		if ($fields['countryCode']) {
			$country = \Entity\Country::select($fields['countryCode']);
			if (!$country->recordExists() or $country->deleted) {
				$currMessages->addErrorCode('cntrCodeInvalid', 'location');
			}
		}

		// check city id
		if ($fields['cityId']) {
			$city = \Entity\City::select($fields['cityId']);
			if (!$city->recordExists() or $city->deleted) {
				$currMessages->addErrorCode('cityIdInvalid', 'location');
			}

			if ($city->countryCode!=$fields['countryCode']) {
				$currMessages->addErrorCode('cityIdInvalid', 'location');
			}
		}

		return true;
	}

	/**
	 * Checks the bank accounts.
	 * @throws \Exception
	 */
	private function validateAux_bankAccounts()
	{
		// get current fields details
		$fields=$this->entity->getFields();

		// current collected messages
		$currMessages=$this->entity->getMessages();

		// current entity id
		$currentIdEntity=$this->entity->getId();

		// get operation
		$operation=$this->entity->getOperation();

		$OK=true;

		// CHECK INPUT ----------------------------------------------------------------------------
		if (!array_key_exists('bankAccounts', $fields)) {
			return true;
		}
		// check that bank accounts are set
		if (!is_array($fields['bankAccounts'])) {
			throw new \Exception('The bank accounts must be set as an array.');
		}
		if (!$fields['bankAccounts']) {
			return true;
		}

		// GET THE LIST OF OLD BANK ACCOUNTS ------------------------------------------------------
		$oldBas = [];
		if ($operation == 'update') {
			$oldBas = \Entity\Supplier::selectForUpdate($currentIdEntity)->bankAccounts;
		}

		// CHECK BANK ACCOUNT DETAILS -------------------------------------------------------------
		$countDefaults=0;
		$checkBankAccounts = [];
		foreach($fields['bankAccounts'] as $ba) {

			// check operation bank account id for inserting suppliers
			if ($operation == 'insert' and $ba['id']) {
				throw new \Exception('Bank accounts cannot be updated for supplier insert operation.');
			}

			// check that a given bank account id is valid
			if ($ba['id'] and !$oldBas[$ba['id']]) {
				$currMessages->addErrorCode('bankAccInvalidId', '', $ba['id']);
			}

			// count default accounts
			if ($ba['defaultAccount']) {
				$countDefaults++;
			}

			// check that bank account number is set
			if (!$ba['account']) {
				$currMessages->addWarningCode('bankAccWithoutNumber');
				$OK = false;
				break;
			}

			// check that the bank account number does not appear twice in the array
			if ($checkBankAccounts[$ba['account']]) {
				$currMessages->addWarningCode('bankAccNumberExists');
				$OK = false;
				break;
			}
			$checkBankAccounts[$ba['account']] = true;

			// check the currency
			if ($ba['currency'] and !\App\Config\Currencies::getInstance()->check($ba['currency'])) {
				$currMessages->addWarningCode('bankAccCurrencyInvalid', '', $ba['currency']);
				$OK=false;
				break;
			}

		}
		// count the default bank accounts
		if (!$countDefaults) {
			$currMessages->addWarningCode('bankAccountsNoDef');
		}

		if ($countDefaults > 1) {
			throw new \Exception('You cannot set more than one default bank account.');
		}

		// CHECK BANK AND BANK OFFICE ---------------------------------------------------------
		foreach($fields['bankAccounts'] as $ba) {
			// check bank id
			if ($ba['idBank']) {
				$bankObj = \Entity\Bank::select($ba['idBank']);
				if (!$bankObj->recordExists() or $bankObj->deleted) {
					$currMessages->addWarningCode('bankAccBankBad');
					$OK=false;
					break;
				}
			}
			else {
				$currMessages->addWarningCode('bankAccBankNotSet');
				$OK=0;
				break;
			}

			// check bank office id
			if ($ba['idBankOffice']) {
				$baOffObj = \Entity\BankOffice::select($ba['idBankOffice']);
				if (!$baOffObj->recordExists() or $baOffObj->deleted) {
					$currMessages->addWarningCode('bankAccBankOfficeBad');
					$OK=false;
					break;
				}

				if ($baOffObj->idBank!=$ba['idBank']) {
					$currMessages->addWarningCode('bankAccBankOfficeBad');
					$OK=0;
					break;
				}
			}
		}

		return $OK;
	}

	/**
	 * Checks the supplier codes (if they alreay exist).
	 */
	private function validateAux_codes()
	{
		// get current fields details
		$fields = $this->entity->getFields();

		// current collected messages
		$currMessages = $this->entity->getMessages();

		// current entity id
		$currentIdEntity = $this->entity->getId();

		// get operation
		$operation = $this->entity->getOperation();

		// load global cfgs
		$CFG = \Engine\Loader_Cfg::getInstance()->getGlobal();

		// check codes format
		if (array_key_exists('codes', $fields) and !is_array($fields['codes'])) {
			throw new \Exception('The supplier codes can only be set as an array.');
		}

		// if no codes set - skip this method
		if (!$fields['codes']) {
			return true;
		}

		foreach($fields['codes'] as $code => $val) {
			if (!$CFG['travel']['standardCodes'][$code]) {
				$currMessages->addErrorCode('suppCodeInvalid', '', $code);
			}

			if ($val) {
				$supplierObj = new \App\EntityList\Suppliers();
				$supplierObj->setColumns(['codes.value', 'codes.code']);
				if ($operation == 'update') {
					$supplierObj->setFilter('supp.id', '!=', $currentIdEntity);
				}

				$supplierObj->setFilter('codes.code', 'LIKE', $code);
				$supplierObj->setFilter('codes.value', 'LIKE', $val);
				$supplierObj->setLimit(1);
				$supplierArray = $supplierObj->exportRecords();

				if ($supplierArray) {
					$currMessages->addWarningCode('suppCodeExists', '', [$supplierArray[0]['code'], $supplierArray[0]['value']]);
					break;
				}
			}

		}

	}

	/**
	 * Checks the QC rules for the current supplier (depending on the set fields).
	 */
	private function validateAux_checkQcRules()
	{

		// INITIALIZATIONS ////////////////////////////////////////////////////////////////////////
		$currMessages = $this->entity->getMessages();

		// the currently set fields
		$fields = $this->entity->getFields();

		// the collected supplier fields
		$entFieldsObj = new \App\QcRules\Supplier_Fields();

		// POPULATE THE ENTITY FIELDS BASED ON THE CURRENT OPERATION //////////////////////////////
		switch ($this->entity->getOperation()) {
			case 'insert': {
				$entFieldsObj->countryCode = $fields['countryCode'];
				$entFieldsObj->fiscalCode = $fields['fiscalCode'];
				$entFieldsObj->processedRemarks = $fields['processedRemarks'];
				break;
			}

			case 'update': {
				$supplierEnt = Supplier::selectForUpdate($this->entity->getId());
				if (array_key_exists('countryCode', $fields)) {
					$entFieldsObj->countryCode = $fields['countryCode'];
				}
				else {
					$entFieldsObj->countryCode = $supplierEnt->countryCode;
				}

				if (array_key_exists('fiscalCode', $fields)) {
					$entFieldsObj->fiscalCode = $fields['fiscalCode'];
				}
				else {
					$entFieldsObj->fiscalCode = $supplierEnt->fiscalCode;
				}

				if (array_key_exists('processedRemarks', $fields)) {
					$entFieldsObj->processedRemarks = $fields['processedRemarks'];
				}
				else {
					$entFieldsObj->processedRemarks = $supplierEnt->processedRemarks;
				}

				break;
			}

			default: {
				throw new \Exception('Invalid operation for QC rules applying on suppliers.');
			}
		}

		// CHECK THE QC RULES /////////////////////////////////////////////////////////////////////
		$applyRule = new \App\QcRules\Apply('Supplier');
		if (!$applyRule->checkFields($entFieldsObj)) {
			$_LANG = \App\Loader_Lang::getInstance()->getGlobal();
			foreach($applyRule->getAllUnmetRules() as $idRule=>$rule) {
				$currMessages->addWarningText(sprintf($_LANG['QcRules']['messages']['ruleFailed'], $rule->createDescription(), '#'.$idRule));
			}

			return false;
		}

		return true;
	}

	private function validateAux_checkAddressDetails()
	{
		// INITIALIZATIONS ////////////////////////////////////////////////////////////////////////
		$currMessages = $this->entity->getMessages();
		$OK = true;

		// the currently set fields
		$fields = $this->entity->getFields();

		// CHECK THAT ALL FIELDS FROM MAIN ADDRESS ARE COMPLETED or NONE OF THEM
		// list with all name of fields for names
		$mainAddressFields = ['address_main_streetPrefix', 'address_main_streetName', 'address_main_streetNumber', 'address_main_district', 'address_main_buildingNumber', 'address_main_buildingEntrance', 'address_main_floor', 'address_main_apartment', 'address_main_zipCode', 'address_main_cityId', 'address_main_countryCode'];
		$resultMainAddress = array_intersect(array_keys($fields), $mainAddressFields);

		// CHECK THAT ALL FIELDS FROM DELIVERY ADDRESS ARE COMPLETED or NONE OF THEM
		// list with all name of fields for names
		$deliveryAddressFields = ['address_delivery_streetPrefix', 'address_delivery_streetName', 'address_delivery_streetNumber', 'address_delivery_district', 'address_delivery_buildingNumber', 'address_delivery_buildingEntrance', 'address_delivery_floor', 'address_delivery_apartment', 'address_delivery_zipCode', 'address_delivery_cityId', 'address_delivery_countryCode'];
		$resultDeliveryAddress = array_intersect(array_keys($fields), $deliveryAddressFields);


		if ($this->entity->getOperation() == 'insert' or $this->entity->getOperation() == 'update') {
			// check address main details
			if ($resultMainAddress and count($resultMainAddress) != 11) {
				throw new \Exception(sprintf("You must set all fields for address main details (%s) or none of them", implode(', ', $mainAddressFields)));
			}

			if (!$resultMainAddress) {
				return true;
			}

			if ($resultDeliveryAddress and count($resultDeliveryAddress) != 11) {
				throw new \Exception(sprintf("You must set all fields for address delivery details (%s) or none of them", implode(', ', $deliveryAddressFields)));
			}

			if (!$resultDeliveryAddress) {
				return true;
			}
		}
		else {
			throw new \Exception("This function can be used only for insert/update operation");
		}

		if ($fields['address_main_countryCode']) {
			$country = \Entity\Country::select($fields['address_main_countryCode']);

			// check if country is valid
			if (!$country->recordExists()) {
				$currMessages->addErrorCode('cntrCodeInvalid', 'address_main_countryCode');
			}
			elseif ($country->deleted) {
				$currMessages->addWarningCode('cntrCodeInvalid', 'address_main_countryCode');
				$OK = false;
			}
		}

		// CHECK MAIN ADDRESS CITY
		if ($fields['address_main_cityId']) {
			$city = \Entity\City::select($fields['address_main_cityId']);

			// check if city is valid
			if (!$city->recordExists()) {
				$currMessages->addErrorCode('cityIdInvalid', 'address_main_cityId');
			}
			elseif ($city->deleted) {
				$currMessages->addWarningCode('cityIdInvalid', 'address_main_cityId');
				$OK = false;
			}

			// check if city is from selected country
			if ($OK and $city->countryCode != $fields['address_main_countryCode']) {
				$currMessages->addWarningCode('cityIdInvalid');
			}
		}

		if ($fields['address_delivery_countryCode']) {
			$country = \Entity\Country::select($fields['address_delivery_countryCode']);

			// check if country is valid
			if (!$country->recordExists()) {
				$currMessages->addErrorCode('cntrCodeInvalid', 'address_delivery_countryCode');
			}
			elseif ($country->deleted) {
				$currMessages->addWarningCode('cntrCodeInvalid', 'address_delivery_countryCode');
				$OK = false;
			}
		}

		// CHECK ADDRESS  DELIVERY CITY
		if ($fields['address_delivery_cityId']) {
			$city = \Entity\City::select($fields['address_delivery_cityId']);

			// check if city is valid
			if (!$city->recordExists()) {
				$currMessages->addErrorCode('cityIdInvalid', 'address_delivery_cityId');
			}
			elseif ($city->deleted) {
				$currMessages->addWarningCode('cityIdInvalid', 'address_delivery_cityId');
				$OK = false;
			}

			// check if city is from selected country
			if ($OK and $city->countryCode != $fields['address_delivery_countryCode']) {
				$currMessages->addWarningCode('cityIdInvalid');
			}
		}

		return $OK;
	}

	/**
	 * Check accounting number
	 */
	private function validateAux_accountingNumber()
	{
		// current collected messages
		$currentMessages = $this->entity->getMessages();

		// get current fields details
		$fields = $this->entity->getFields();

		// entity configs
		$cfg = $this->entity->getCFG();

		$OK = true;

		// CHECK ACCOUNTING NUMBER
		if ($fields['accountingNumber'] and $cfg['accountingNumber']['unique']) {

			$supplierObj = new \App\EntityList\Suppliers();
			$supplierObj->setColumns(['alias']);
			$supplierObj->setFilter('accountingNumber', '=', $fields['accountingNumber']);
			if ($this->entity->getOperation() == 'update') {
				$supplierObj->setFilter('id', '!=', $this->entity->getId());
			}

			$supplierObj->setLimit(1);
			$suppArray = $supplierObj->exportRecords();
			if ($suppArray) {
				$currentMessages->addWarningCode('AccountingNumberNotUnique', 'accountingNumber', $suppArray[0]['alias']);
				$OK = false;
			}
		}

		return $OK;
	}

	/**
	 * Check group elements
	 */
	protected function check_update_idGroupElements()
	{
		// current collected messages
		$currentMessages = $this->entity->getMessages();

		// get current fields details
		$fields = $this->entity->getFields();

		// stop the execution of the following code if the `idGroupElements` list is empty
		if (!$fields['idGroupElements']) {
			return;
		}

		$groupsCfg = \App\Config\SupplierGroups::getInstance()->getAll();

		foreach ($fields['idGroupElements'] as $idGroup=>$idGroupElement) {
			// we make sure the group exists
			if (!$groupsCfg[$idGroup]) {
				$currentMessages->addErrorCode('idGroupElements_idGroupInvalid');
			}

			// we make sure the group element exists
			if ($idGroupElement && !$groupsCfg[$idGroup]['groupElements'][$idGroupElement]) {
				$currentMessages->addErrorCode('idGroupElements_idGroupElementInvalid');
			}
		}
	}

}
