You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@fineract.apache.org by nikpawar89 <gi...@git.apache.org> on 2016/08/11 01:11:24 UTC

[GitHub] incubator-fineract pull request #201: address_module

GitHub user nikpawar89 opened a pull request:

    https://github.com/apache/incubator-fineract/pull/201

    address_module

    

You can merge this pull request into a Git repository by running:

    $ git pull https://github.com/nikpawar89/incubator-fineract addressModulefinal

Alternatively you can review and apply these changes as the patch at:

    https://github.com/apache/incubator-fineract/pull/201.patch

To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:

    This closes #201
    
----
commit 34150ef0a94b98677a3d56c35cee839326fc4106
Author: nikpawar89 <ni...@yahoo.in>
Date:   2016-07-19T06:08:06Z

    address_module

----


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-fineract pull request #201: address_module

Posted by Nayan <gi...@git.apache.org>.
Github user Nayan commented on a diff in the pull request:

    https://github.com/apache/incubator-fineract/pull/201#discussion_r74360065
  
    --- Diff: fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java ---
    @@ -90,734 +92,803 @@
     @Service
     public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWritePlatformService {
     
    -    private final static Logger logger = LoggerFactory.getLogger(ClientWritePlatformServiceJpaRepositoryImpl.class);
    -
    -    private final PlatformSecurityContext context;
    -    private final ClientRepositoryWrapper clientRepository;
    -    private final ClientNonPersonRepositoryWrapper clientNonPersonRepository;
    -    private final OfficeRepository officeRepository;
    -    private final NoteRepository noteRepository;
    -    private final GroupRepository groupRepository;
    -    private final ClientDataValidator fromApiJsonDeserializer;
    -    private final AccountNumberGenerator accountNumberGenerator;
    -    private final StaffRepositoryWrapper staffRepository;
    -    private final CodeValueRepositoryWrapper codeValueRepository;
    -    private final LoanRepository loanRepository;
    -    private final SavingsAccountRepository savingsRepository;
    -    private final SavingsProductRepository savingsProductRepository;
    -    private final SavingsApplicationProcessWritePlatformService savingsApplicationProcessWritePlatformService;
    -    private final CommandProcessingService commandProcessingService;
    -    private final ConfigurationDomainService configurationDomainService;
    -    private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository;
    +	private final static Logger logger = LoggerFactory.getLogger(ClientWritePlatformServiceJpaRepositoryImpl.class);
    +
    +	private final PlatformSecurityContext context;
    +	private final ClientRepositoryWrapper clientRepository;
    +	private final ClientNonPersonRepositoryWrapper clientNonPersonRepository;
    +	private final OfficeRepository officeRepository;
    +	private final NoteRepository noteRepository;
    +	private final GroupRepository groupRepository;
    +	private final ClientDataValidator fromApiJsonDeserializer;
    +	private final AccountNumberGenerator accountNumberGenerator;
    +	private final StaffRepositoryWrapper staffRepository;
    +	private final CodeValueRepositoryWrapper codeValueRepository;
    +	private final LoanRepository loanRepository;
    +	private final SavingsAccountRepository savingsRepository;
    +	private final SavingsProductRepository savingsProductRepository;
    +	private final SavingsApplicationProcessWritePlatformService savingsApplicationProcessWritePlatformService;
    +	private final CommandProcessingService commandProcessingService;
    +	private final ConfigurationDomainService configurationDomainService;
    +	private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository;
     	private final FromJsonHelper fromApiJsonHelper;
    +	private final ConfigurationReadPlatformService configurationReadPlatformService;
    +	private final AddressWritePlatformService addressWritePlatformService;
    +
    +	@Autowired
    +	public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
    +			final ClientRepositoryWrapper clientRepository,
    +			final ClientNonPersonRepositoryWrapper clientNonPersonRepository, final OfficeRepository officeRepository,
    +			final NoteRepository noteRepository, final ClientDataValidator fromApiJsonDeserializer,
    +			final AccountNumberGenerator accountNumberGenerator, final GroupRepository groupRepository,
    +			final StaffRepositoryWrapper staffRepository, final CodeValueRepositoryWrapper codeValueRepository,
    +			final LoanRepository loanRepository, final SavingsAccountRepository savingsRepository,
    +			final SavingsProductRepository savingsProductRepository,
    +			final SavingsApplicationProcessWritePlatformService savingsApplicationProcessWritePlatformService,
    +			final CommandProcessingService commandProcessingService,
    +			final ConfigurationDomainService configurationDomainService,
    +			final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository,
    +			final FromJsonHelper fromApiJsonHelper,
    +			final ConfigurationReadPlatformService configurationReadPlatformService,
    +			final AddressWritePlatformService addressWritePlatformService) {
    +		this.context = context;
    +		this.clientRepository = clientRepository;
    +		this.clientNonPersonRepository = clientNonPersonRepository;
    +		this.officeRepository = officeRepository;
    +		this.noteRepository = noteRepository;
    +		this.fromApiJsonDeserializer = fromApiJsonDeserializer;
    +		this.accountNumberGenerator = accountNumberGenerator;
    +		this.groupRepository = groupRepository;
    +		this.staffRepository = staffRepository;
    +		this.codeValueRepository = codeValueRepository;
    +		this.loanRepository = loanRepository;
    +		this.savingsRepository = savingsRepository;
    +		this.savingsProductRepository = savingsProductRepository;
    +		this.savingsApplicationProcessWritePlatformService = savingsApplicationProcessWritePlatformService;
    +		this.commandProcessingService = commandProcessingService;
    +		this.configurationDomainService = configurationDomainService;
    +		this.accountNumberFormatRepository = accountNumberFormatRepository;
    +		this.fromApiJsonHelper = fromApiJsonHelper;
    +		this.configurationReadPlatformService = configurationReadPlatformService;
    +		this.addressWritePlatformService = addressWritePlatformService;
    +	}
    +
    +	@Transactional
    +	@Override
    +	public CommandProcessingResult deleteClient(final Long clientId) {
    +
    +		final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
    +
    +		if (client.isNotPending()) {
    +			throw new ClientMustBePendingToBeDeletedException(clientId);
    +		}
    +
    +		final List<Note> relatedNotes = this.noteRepository.findByClientId(clientId);
    +		this.noteRepository.deleteInBatch(relatedNotes);
    +
    +		final ClientNonPerson clientNonPerson = this.clientNonPersonRepository.findOneByClientId(clientId);
    +		if (clientNonPerson != null)
    +			this.clientNonPersonRepository.delete(clientNonPerson);
    +
    +		this.clientRepository.delete(client);
    +
    +		return new CommandProcessingResultBuilder() //
    +				.withOfficeId(client.officeId()) //
    +				.withClientId(clientId) //
    +				.withEntityId(clientId) //
    +				.build();
    +	}
    +
    +	/*
    +	 * Guaranteed to throw an exception no matter what the data integrity issue
    +	 * is.
    +	 */
    +	private void handleDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) {
    +
    +		final Throwable realCause = dve.getMostSpecificCause();
    +		if (realCause.getMessage().contains("external_id")) {
    +
    +			final String externalId = command.stringValueOfParameterNamed("externalId");
    +			throw new PlatformDataIntegrityException("error.msg.client.duplicate.externalId",
    +					"Client with externalId `" + externalId + "` already exists", "externalId", externalId);
    +		} else if (realCause.getMessage().contains("account_no_UNIQUE")) {
    +			final String accountNo = command.stringValueOfParameterNamed("accountNo");
    +			throw new PlatformDataIntegrityException("error.msg.client.duplicate.accountNo",
    +					"Client with accountNo `" + accountNo + "` already exists", "accountNo", accountNo);
    +		} else if (realCause.getMessage().contains("mobile_no")) {
    +			final String mobileNo = command.stringValueOfParameterNamed("mobileNo");
    +			throw new PlatformDataIntegrityException("error.msg.client.duplicate.mobileNo",
    +					"Client with mobileNo `" + mobileNo + "` already exists", "mobileNo", mobileNo);
    +		}
    +
    +		logAsErrorUnexpectedDataIntegrityException(dve);
    +		throw new PlatformDataIntegrityException("error.msg.client.unknown.data.integrity.issue",
    +				"Unknown data integrity issue with resource.");
    +	}
    +
    +	@Transactional
    +	@Override
    +	public CommandProcessingResult createClient(final JsonCommand command) {
    +		try {
    +			final AppUser currentUser = this.context.authenticatedUser();
    +			this.fromApiJsonDeserializer.validateForCreate(command.json());
    +
    +			// final long configId=29;
    +
    +			final GlobalConfigurationPropertyData configuration = this.configurationReadPlatformService
    +					.retrieveGlobalConfiguration("Enable-Address");
    +
    +			final Boolean isAddressEnabled = configuration.isEnabled();
    +
    +			final Long officeId = command.longValueOfParameterNamed(ClientApiConstants.officeIdParamName);
    +
    +			final Office clientOffice = this.officeRepository.findOne(officeId);
    +			if (clientOffice == null) {
    +				throw new OfficeNotFoundException(officeId);
    +			}
    +
    +			final Long groupId = command.longValueOfParameterNamed(ClientApiConstants.groupIdParamName);
    +
    +			Group clientParentGroup = null;
    +			if (groupId != null) {
    +				clientParentGroup = this.groupRepository.findOne(groupId);
    +				if (clientParentGroup == null) {
    +					throw new GroupNotFoundException(groupId);
    +				}
    +			}
    +
    +			Staff staff = null;
    +			final Long staffId = command.longValueOfParameterNamed(ClientApiConstants.staffIdParamName);
    +			if (staffId != null) {
    +				staff = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(staffId,
    +						clientOffice.getHierarchy());
    +			}
    +
    +			CodeValue gender = null;
    +			final Long genderId = command.longValueOfParameterNamed(ClientApiConstants.genderIdParamName);
    +			if (genderId != null) {
    +				gender = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.GENDER,
    +						genderId);
    +			}
    +
    +			CodeValue clientType = null;
    +			final Long clientTypeId = command.longValueOfParameterNamed(ClientApiConstants.clientTypeIdParamName);
    +			if (clientTypeId != null) {
    +				clientType = this.codeValueRepository
    +						.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.CLIENT_TYPE, clientTypeId);
    +			}
    +
    +			CodeValue clientClassification = null;
    +			final Long clientClassificationId = command
    +					.longValueOfParameterNamed(ClientApiConstants.clientClassificationIdParamName);
    +			if (clientClassificationId != null) {
    +				clientClassification = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
    +						ClientApiConstants.CLIENT_CLASSIFICATION, clientClassificationId);
    +			}
    +
    +			SavingsProduct savingsProduct = null;
    +			final Long savingsProductId = command
    +					.longValueOfParameterNamed(ClientApiConstants.savingsProductIdParamName);
    +			if (savingsProductId != null) {
    +				savingsProduct = this.savingsProductRepository.findOne(savingsProductId);
    +				if (savingsProduct == null) {
    +					throw new SavingsProductNotFoundException(savingsProductId);
    +				}
    +
    +			}
    +
    +			final Integer legalFormParamValue = command
    +					.integerValueOfParameterNamed(ClientApiConstants.legalFormIdParamName);
    +			boolean isEntity = false;
    +			Integer legalFormValue = null;
    +			if (legalFormParamValue != null) {
    +				LegalForm legalForm = LegalForm.fromInt(legalFormParamValue);
    +				if (legalForm != null) {
    +					legalFormValue = legalForm.getValue();
    +					isEntity = legalForm.isEntity();
    +				}
    +			}
    +
    +			final Client newClient = Client.createNew(currentUser, clientOffice, clientParentGroup, staff,
    +					savingsProduct, gender, clientType, clientClassification, legalFormValue, command);
    +			boolean rollbackTransaction = false;
    +			if (newClient.isActive()) {
    +				validateParentGroupRulesBeforeClientActivation(newClient);
    +				final CommandWrapper commandWrapper = new CommandWrapperBuilder().activateClient(null).build();
    +				rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper, currentUser);
    +			}
    +
    +			this.clientRepository.save(newClient);
    +
    +			if (newClient.isAccountNumberRequiresAutoGeneration()) {
    +				AccountNumberFormat accountNumberFormat = this.accountNumberFormatRepository
    +						.findByAccountType(EntityAccountType.CLIENT);
    +				newClient.updateAccountNo(accountNumberGenerator.generate(newClient, accountNumberFormat));
    +				this.clientRepository.save(newClient);
    +			}
    +
    +			final Locale locale = command.extractLocale();
    +			final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
    +			CommandProcessingResult result = openSavingsAccount(newClient, fmt);
    +			if (result.getSavingsId() != null) {
    +				this.clientRepository.save(newClient);
    +			}
    +
    +			if (isEntity)
    +				extractAndCreateClientNonPerson(newClient, command);
    +
    +			final long clientId = newClient.getId();
    +
    +			if (isAddressEnabled) {
    +
    +				this.addressWritePlatformService.addNewClientAddress(newClient, command);
    +
    +			}
    +
    +			return new CommandProcessingResultBuilder() //
    +					.withCommandId(command.commandId()) //
    +					.withOfficeId(clientOffice.getId()) //
    +					.withClientId(newClient.getId()) //
    +					.withGroupId(groupId) //
    +					.withEntityId(newClient.getId()) //
    +					.withSavingsId(result.getSavingsId())//
    +					.setRollbackTransaction(rollbackTransaction)//
    +					.setRollbackTransaction(result.isRollbackTransaction())//
    +					.build();
    +		} catch (final DataIntegrityViolationException dve) {
    +			handleDataIntegrityIssues(command, dve);
    +			return CommandProcessingResult.empty();
    +		}
    +
    +	}
    +
    +	/**
    +	 * This method extracts ClientNonPerson details from Client command and
    +	 * creates a new ClientNonPerson record
    +	 * 
    +	 * @param client
    +	 * @param command
    +	 */
    +	public void extractAndCreateClientNonPerson(Client client, JsonCommand command) {
    +		final JsonElement clientNonPersonElement = this.fromApiJsonHelper
    +				.parse(command.jsonFragment(ClientApiConstants.clientNonPersonDetailsParamName));
    +
    +		if (clientNonPersonElement != null) {
    +			final String incorpNumber = this.fromApiJsonHelper
    +					.extractStringNamed(ClientApiConstants.incorpNumberParamName, clientNonPersonElement);
    +			final String remarks = this.fromApiJsonHelper.extractStringNamed(ClientApiConstants.remarksParamName,
    +					clientNonPersonElement);
    +			final LocalDate incorpValidityTill = this.fromApiJsonHelper
    +					.extractLocalDateNamed(ClientApiConstants.incorpValidityTillParamName, clientNonPersonElement);
    +
    +			// JsonCommand clientNonPersonCommand =
    +			// JsonCommand.fromExistingCommand(command,
    +			// command.arrayOfParameterNamed(ClientApiConstants.clientNonPersonDetailsParamName).getAsJsonObject());
    +			CodeValue clientNonPersonConstitution = null;
    +			final Long clientNonPersonConstitutionId = this.fromApiJsonHelper
    +					.extractLongNamed(ClientApiConstants.constitutionIdParamName, clientNonPersonElement);
    +			if (clientNonPersonConstitutionId != null) {
    +				clientNonPersonConstitution = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
    +						ClientApiConstants.CLIENT_NON_PERSON_CONSTITUTION, clientNonPersonConstitutionId);
    +			}
    +
    +			CodeValue clientNonPersonMainBusinessLine = null;
    +			final Long clientNonPersonMainBusinessLineId = this.fromApiJsonHelper
    +					.extractLongNamed(ClientApiConstants.mainBusinessLineIdParamName, clientNonPersonElement);
    +			if (clientNonPersonMainBusinessLineId != null) {
    +				clientNonPersonMainBusinessLine = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
    +						ClientApiConstants.CLIENT_NON_PERSON_MAIN_BUSINESS_LINE, clientNonPersonMainBusinessLineId);
    +			}
    +
    +			final ClientNonPerson newClientNonPerson = ClientNonPerson.createNew(client, clientNonPersonConstitution,
    +					clientNonPersonMainBusinessLine, incorpNumber, incorpValidityTill, remarks);
    +
    +			this.clientNonPersonRepository.save(newClientNonPerson);
    +		}
    +	}
    +
    +	@Transactional
    +	@Override
    +	public CommandProcessingResult updateClient(final Long clientId, final JsonCommand command) {
    +
    +		try {
    +			this.fromApiJsonDeserializer.validateForUpdate(command.json());
    +
    +			final Client clientForUpdate = this.clientRepository.findOneWithNotFoundDetection(clientId);
    +			final String clientHierarchy = clientForUpdate.getOffice().getHierarchy();
    +
    +			this.context.validateAccessRights(clientHierarchy);
    +
    +			final Map<String, Object> changes = clientForUpdate.update(command);
    +
    +			if (changes.containsKey(ClientApiConstants.staffIdParamName)) {
    +
    +				final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.staffIdParamName);
    +				Staff newStaff = null;
    +				if (newValue != null) {
    +					newStaff = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(newValue,
    +							clientForUpdate.getOffice().getHierarchy());
    +				}
    +				clientForUpdate.updateStaff(newStaff);
    +			}
    +
    +			if (changes.containsKey(ClientApiConstants.genderIdParamName)) {
    +
    +				final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.genderIdParamName);
    +				CodeValue gender = null;
    +				if (newValue != null) {
    +					gender = this.codeValueRepository
    +							.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.GENDER, newValue);
    +				}
    +				clientForUpdate.updateGender(gender);
    +			}
    +
    +			if (changes.containsKey(ClientApiConstants.savingsProductIdParamName)) {
    +				if (clientForUpdate.isActive()) {
    +					throw new ClientActiveForUpdateException(clientId, ClientApiConstants.savingsProductIdParamName);
    +				}
    +				SavingsProduct savingsProduct = null;
    +				final Long savingsProductId = command
    +						.longValueOfParameterNamed(ClientApiConstants.savingsProductIdParamName);
    +				if (savingsProductId != null) {
    +					savingsProduct = this.savingsProductRepository.findOne(savingsProductId);
    +					if (savingsProduct == null) {
    +						throw new SavingsProductNotFoundException(savingsProductId);
    +					}
    +				}
    +				clientForUpdate.updateSavingsProduct(savingsProduct);
    +			}
    +
    +			if (changes.containsKey(ClientApiConstants.genderIdParamName)) {
    +				final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.genderIdParamName);
    +				CodeValue newCodeVal = null;
    +				if (newValue != null) {
    +					newCodeVal = this.codeValueRepository
    +							.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.GENDER, newValue);
    +				}
    +				clientForUpdate.updateGender(newCodeVal);
    +			}
    +
    +			if (changes.containsKey(ClientApiConstants.clientTypeIdParamName)) {
    +				final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.clientTypeIdParamName);
    +				CodeValue newCodeVal = null;
    +				if (newValue != null) {
    +					newCodeVal = this.codeValueRepository
    +							.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.CLIENT_TYPE, newValue);
    +				}
    +				clientForUpdate.updateClientType(newCodeVal);
    +			}
    +
    +			if (changes.containsKey(ClientApiConstants.clientClassificationIdParamName)) {
    +				final Long newValue = command
    +						.longValueOfParameterNamed(ClientApiConstants.clientClassificationIdParamName);
    +				CodeValue newCodeVal = null;
    +				if (newValue != null) {
    +					newCodeVal = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
    +							ClientApiConstants.CLIENT_CLASSIFICATION, newValue);
    +				}
    +				clientForUpdate.updateClientClassification(newCodeVal);
    +			}
    +
    +			if (!changes.isEmpty()) {
    +				this.clientRepository.saveAndFlush(clientForUpdate);
    +			}
    +
    +			if (changes.containsKey(ClientApiConstants.legalFormIdParamName)) {
    +				Integer legalFormValue = clientForUpdate.getLegalForm();
    +				boolean isChangedToEntity = false;
    +				if (legalFormValue != null) {
    +					LegalForm legalForm = LegalForm.fromInt(legalFormValue);
    +					if (legalForm != null)
    +						isChangedToEntity = legalForm.isEntity();
    +				}
    +
    +				if (isChangedToEntity) {
    +					extractAndCreateClientNonPerson(clientForUpdate, command);
    +				} else {
    +					final ClientNonPerson clientNonPerson = this.clientNonPersonRepository
    +							.findOneByClientId(clientForUpdate.getId());
    +					if (clientNonPerson != null)
    +						this.clientNonPersonRepository.delete(clientNonPerson);
    +				}
    +			}
    +
    +			final ClientNonPerson clientNonPersonForUpdate = this.clientNonPersonRepository.findOneByClientId(clientId);
    +			if (clientNonPersonForUpdate != null) {
    +				final JsonElement clientNonPersonElement = this.fromApiJsonHelper
    +						.parse(command.jsonFragment(ClientApiConstants.clientNonPersonDetailsParamName));
    +				final Map<String, Object> clientNonPersonChanges = clientNonPersonForUpdate
    +						.update(JsonCommand.fromExistingCommand(command, clientNonPersonElement));
    +
    +				if (clientNonPersonChanges.containsKey(ClientApiConstants.constitutionIdParamName)) {
    +
    +					final Long newValue = this.fromApiJsonHelper
    +							.extractLongNamed(ClientApiConstants.constitutionIdParamName, clientNonPersonElement);
    +					CodeValue constitution = null;
    +					if (newValue != null) {
    +						constitution = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
    +								ClientApiConstants.CLIENT_NON_PERSON_CONSTITUTION, newValue);
    +					}
    +					clientNonPersonForUpdate.updateConstitution(constitution);
    +				}
    +
    +				if (clientNonPersonChanges.containsKey(ClientApiConstants.mainBusinessLineIdParamName)) {
    +
    +					final Long newValue = this.fromApiJsonHelper
    +							.extractLongNamed(ClientApiConstants.mainBusinessLineIdParamName, clientNonPersonElement);
    +					CodeValue mainBusinessLine = null;
    +					if (newValue != null) {
    +						mainBusinessLine = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
    +								ClientApiConstants.CLIENT_NON_PERSON_MAIN_BUSINESS_LINE, newValue);
    +					}
    +					clientNonPersonForUpdate.updateMainBusinessLine(mainBusinessLine);
    +				}
    +
    +				if (!clientNonPersonChanges.isEmpty()) {
    +					this.clientNonPersonRepository.saveAndFlush(clientNonPersonForUpdate);
    +				}
    +
    +				changes.putAll(clientNonPersonChanges);
    +			}
    +
    +			return new CommandProcessingResultBuilder() //
    +					.withCommandId(command.commandId()) //
    +					.withOfficeId(clientForUpdate.officeId()) //
    +					.withClientId(clientId) //
    +					.withEntityId(clientId) //
    +					.with(changes) //
    +					.build();
    +		} catch (final DataIntegrityViolationException dve) {
    +			handleDataIntegrityIssues(command, dve);
    +			return CommandProcessingResult.empty();
    +		}
    +	}
    +
    +	@Transactional
    +	@Override
    +	public CommandProcessingResult activateClient(final Long clientId, final JsonCommand command) {
    +		try {
    +			this.fromApiJsonDeserializer.validateActivation(command);
    +
    +			final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
    +			validateParentGroupRulesBeforeClientActivation(client);
    +
    +			final Locale locale = command.extractLocale();
    +			final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
    +			final LocalDate activationDate = command.localDateValueOfParameterNamed("activationDate");
    +
    +			final AppUser currentUser = this.context.authenticatedUser();
    +			client.activate(currentUser, fmt, activationDate);
    +			CommandProcessingResult result = openSavingsAccount(client, fmt);
    +			this.clientRepository.saveAndFlush(client);
    +
    +			return new CommandProcessingResultBuilder() //
    +					.withCommandId(command.commandId()) //
    +					.withOfficeId(client.officeId()) //
    +					.withClientId(clientId) //
    +					.withEntityId(clientId) //
    +					.withSavingsId(result.getSavingsId())//
    +					.setRollbackTransaction(result.isRollbackTransaction())//
    +					.build();
    +		} catch (final DataIntegrityViolationException dve) {
    +			handleDataIntegrityIssues(command, dve);
    +			return CommandProcessingResult.empty();
    +		}
    +	}
    +
    +	private CommandProcessingResult openSavingsAccount(final Client client, final DateTimeFormatter fmt) {
    +		CommandProcessingResult commandProcessingResult = CommandProcessingResult.empty();
    +		if (client.isActive() && client.SavingsProduct() != null) {
    +			SavingsAccountDataDTO savingsAccountDataDTO = new SavingsAccountDataDTO(client, null,
    +					client.SavingsProduct(), client.getActivationLocalDate(), client.activatedBy(), fmt);
    +			commandProcessingResult = this.savingsApplicationProcessWritePlatformService
    +					.createActiveApplication(savingsAccountDataDTO);
    +			if (commandProcessingResult.getSavingsId() != null) {
    +				SavingsAccount savingsAccount = this.savingsRepository.findOne(commandProcessingResult.getSavingsId());
    +				client.updateSavingsAccount(savingsAccount);
    +				client.updateSavingsProduct(null);
    +			}
    +		}
    +		return commandProcessingResult;
    +	}
    +
    +	private void logAsErrorUnexpectedDataIntegrityException(final DataIntegrityViolationException dve) {
    +		logger.error(dve.getMessage(), dve);
    +	}
    +
    +	@Transactional
    +	@Override
    +	public CommandProcessingResult unassignClientStaff(final Long clientId, final JsonCommand command) {
    +
    +		this.context.authenticatedUser();
    +
    +		final Map<String, Object> actualChanges = new LinkedHashMap<>(5);
    +
    +		this.fromApiJsonDeserializer.validateForUnassignStaff(command.json());
    +
    +		final Client clientForUpdate = this.clientRepository.findOneWithNotFoundDetection(clientId);
    +
    +		final Staff presentStaff = clientForUpdate.getStaff();
    +		Long presentStaffId = null;
    +		if (presentStaff == null) {
    +			throw new ClientHasNoStaffException(clientId);
    +		}
    +		presentStaffId = presentStaff.getId();
    +		final String staffIdParamName = ClientApiConstants.staffIdParamName;
    +		if (!command.isChangeInLongParameterNamed(staffIdParamName, presentStaffId)) {
    +			clientForUpdate.unassignStaff();
    +		}
    +		this.clientRepository.saveAndFlush(clientForUpdate);
    +
    +		actualChanges.put(staffIdParamName, presentStaffId);
     
    -    @Autowired
    -    public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
    -            final ClientRepositoryWrapper clientRepository, final ClientNonPersonRepositoryWrapper clientNonPersonRepository, final OfficeRepository officeRepository, final NoteRepository noteRepository,
    -            final ClientDataValidator fromApiJsonDeserializer, final AccountNumberGenerator accountNumberGenerator,
    -            final GroupRepository groupRepository, final StaffRepositoryWrapper staffRepository,
    -            final CodeValueRepositoryWrapper codeValueRepository, final LoanRepository loanRepository,
    -            final SavingsAccountRepository savingsRepository, final SavingsProductRepository savingsProductRepository,
    -            final SavingsApplicationProcessWritePlatformService savingsApplicationProcessWritePlatformService,
    -            final CommandProcessingService commandProcessingService, final ConfigurationDomainService configurationDomainService,
    -            final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, final FromJsonHelper fromApiJsonHelper) {
    -        this.context = context;
    -        this.clientRepository = clientRepository;
    -        this.clientNonPersonRepository = clientNonPersonRepository;
    -        this.officeRepository = officeRepository;
    -        this.noteRepository = noteRepository;
    -        this.fromApiJsonDeserializer = fromApiJsonDeserializer;
    -        this.accountNumberGenerator = accountNumberGenerator;
    -        this.groupRepository = groupRepository;
    -        this.staffRepository = staffRepository;
    -        this.codeValueRepository = codeValueRepository;
    -        this.loanRepository = loanRepository;
    -        this.savingsRepository = savingsRepository;
    -        this.savingsProductRepository = savingsProductRepository;
    -        this.savingsApplicationProcessWritePlatformService = savingsApplicationProcessWritePlatformService;
    -        this.commandProcessingService = commandProcessingService;
    -        this.configurationDomainService = configurationDomainService;
    -        this.accountNumberFormatRepository = accountNumberFormatRepository;
    -        this.fromApiJsonHelper = fromApiJsonHelper;
    -    }
    -
    -    @Transactional
    -    @Override
    -    public CommandProcessingResult deleteClient(final Long clientId) {
    -
    -        final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
    -
    -        if (client.isNotPending()) { throw new ClientMustBePendingToBeDeletedException(clientId); }
    -
    -        final List<Note> relatedNotes = this.noteRepository.findByClientId(clientId);
    -        this.noteRepository.deleteInBatch(relatedNotes);
    -
    -        final ClientNonPerson clientNonPerson = this.clientNonPersonRepository.findOneByClientId(clientId);
    -        if(clientNonPerson != null)
    -        	this.clientNonPersonRepository.delete(clientNonPerson);
    -        
    -        this.clientRepository.delete(client);
    -
    -        return new CommandProcessingResultBuilder() //
    -                .withOfficeId(client.officeId()) //
    -                .withClientId(clientId) //
    -                .withEntityId(clientId) //
    -                .build();
    -    }
    -
    -    /*
    -     * Guaranteed to throw an exception no matter what the data integrity issue
    -     * is.
    -     */
    -    private void handleDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) {
    -
    -        final Throwable realCause = dve.getMostSpecificCause();
    -        if (realCause.getMessage().contains("external_id")) {
    -
    -            final String externalId = command.stringValueOfParameterNamed("externalId");
    -            throw new PlatformDataIntegrityException("error.msg.client.duplicate.externalId", "Client with externalId `" + externalId
    -                    + "` already exists", "externalId", externalId);
    -        } else if (realCause.getMessage().contains("account_no_UNIQUE")) {
    -            final String accountNo = command.stringValueOfParameterNamed("accountNo");
    -            throw new PlatformDataIntegrityException("error.msg.client.duplicate.accountNo", "Client with accountNo `" + accountNo
    -                    + "` already exists", "accountNo", accountNo);
    -        } else if (realCause.getMessage().contains("mobile_no")) {
    -            final String mobileNo = command.stringValueOfParameterNamed("mobileNo");
    -            throw new PlatformDataIntegrityException("error.msg.client.duplicate.mobileNo", "Client with mobileNo `" + mobileNo
    -                    + "` already exists", "mobileNo", mobileNo);
    -        }
    -
    -        logAsErrorUnexpectedDataIntegrityException(dve);
    -        throw new PlatformDataIntegrityException("error.msg.client.unknown.data.integrity.issue",
    -                "Unknown data integrity issue with resource.");
    -    }
    -
    -    @Transactional
    -    @Override
    -    public CommandProcessingResult createClient(final JsonCommand command) {
    -
    -        try {
    -            final AppUser currentUser = this.context.authenticatedUser();
    -
    -            this.fromApiJsonDeserializer.validateForCreate(command.json());
    -
    -            final Long officeId = command.longValueOfParameterNamed(ClientApiConstants.officeIdParamName);
    -
    -            final Office clientOffice = this.officeRepository.findOne(officeId);
    -            if (clientOffice == null) { throw new OfficeNotFoundException(officeId); }
    -
    -            final Long groupId = command.longValueOfParameterNamed(ClientApiConstants.groupIdParamName);
    -
    -            Group clientParentGroup = null;
    -            if (groupId != null) {
    -                clientParentGroup = this.groupRepository.findOne(groupId);
    -                if (clientParentGroup == null) { throw new GroupNotFoundException(groupId); }
    -            }
    -
    -            Staff staff = null;
    -            final Long staffId = command.longValueOfParameterNamed(ClientApiConstants.staffIdParamName);
    -            if (staffId != null) {
    -                staff = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(staffId, clientOffice.getHierarchy());
    -            }
    -
    -            CodeValue gender = null;
    -            final Long genderId = command.longValueOfParameterNamed(ClientApiConstants.genderIdParamName);
    -            if (genderId != null) {
    -                gender = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.GENDER, genderId);
    -            }
    -
    -            CodeValue clientType = null;
    -            final Long clientTypeId = command.longValueOfParameterNamed(ClientApiConstants.clientTypeIdParamName);
    -            if (clientTypeId != null) {
    -                clientType = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.CLIENT_TYPE,
    -                        clientTypeId);
    -            }
    -
    -            CodeValue clientClassification = null;
    -            final Long clientClassificationId = command.longValueOfParameterNamed(ClientApiConstants.clientClassificationIdParamName);
    -            if (clientClassificationId != null) {
    -                clientClassification = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
    -                        ClientApiConstants.CLIENT_CLASSIFICATION, clientClassificationId);
    -            }
    -
    -            SavingsProduct savingsProduct = null;
    -            final Long savingsProductId = command.longValueOfParameterNamed(ClientApiConstants.savingsProductIdParamName);
    -            if (savingsProductId != null) {
    -                savingsProduct = this.savingsProductRepository.findOne(savingsProductId);
    -                if (savingsProduct == null) { throw new SavingsProductNotFoundException(savingsProductId); }
    -
    -            }
    -            
    -            final Integer legalFormParamValue = command.integerValueOfParameterNamed(ClientApiConstants.legalFormIdParamName);
    -            boolean isEntity = false;
    -            Integer legalFormValue = null;
    -            if(legalFormParamValue != null)
    -            {
    -            	LegalForm legalForm = LegalForm.fromInt(legalFormParamValue);
    -            	if(legalForm != null)
    -                {
    -                	legalFormValue = legalForm.getValue();
    -                	isEntity = legalForm.isEntity();
    -                }
    -            }
    -            
    -            final Client newClient = Client.createNew(currentUser, clientOffice, clientParentGroup, staff, savingsProduct, gender,
    -                    clientType, clientClassification, legalFormValue, command);
    -            boolean rollbackTransaction = false;
    -            if (newClient.isActive()) {
    -                validateParentGroupRulesBeforeClientActivation(newClient);
    -                final CommandWrapper commandWrapper = new CommandWrapperBuilder().activateClient(null).build();
    -                rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper, currentUser);
    -            }
    -
    -            this.clientRepository.save(newClient);
    -
    -            if (newClient.isAccountNumberRequiresAutoGeneration()) {
    -                AccountNumberFormat accountNumberFormat = this.accountNumberFormatRepository.findByAccountType(EntityAccountType.CLIENT);
    -                newClient.updateAccountNo(accountNumberGenerator.generate(newClient, accountNumberFormat));
    -                this.clientRepository.save(newClient);
    -            }
    -                        
    -            final Locale locale = command.extractLocale();
    -            final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
    -            CommandProcessingResult result = openSavingsAccount(newClient, fmt);
    -            if (result.getSavingsId() != null) {
    -                this.clientRepository.save(newClient);
    -            }
    -            
    -            if(isEntity)            
    -            	extractAndCreateClientNonPerson(newClient, command);
    -
    -            return new CommandProcessingResultBuilder() //
    -                    .withCommandId(command.commandId()) //
    -                    .withOfficeId(clientOffice.getId()) //
    -                    .withClientId(newClient.getId()) //
    -                    .withGroupId(groupId) //
    -                    .withEntityId(newClient.getId()) //
    -                    .withSavingsId(result.getSavingsId())//
    -                    .setRollbackTransaction(rollbackTransaction)//
    -                    .setRollbackTransaction(result.isRollbackTransaction())//
    -                    .build();
    -        } catch (final DataIntegrityViolationException dve) {
    -            handleDataIntegrityIssues(command, dve);
    -            return CommandProcessingResult.empty();
    -        }
    -    }
    -    
    -    /**
    -     * This method extracts ClientNonPerson details from Client command and creates a new ClientNonPerson record
    -     * @param client
    -     * @param command
    -     */
    -    public void extractAndCreateClientNonPerson(Client client, JsonCommand command)
    -    {    	
    -    	final JsonElement clientNonPersonElement = this.fromApiJsonHelper.parse(command.jsonFragment(ClientApiConstants.clientNonPersonDetailsParamName));
    -
    -		if(clientNonPersonElement != null)
    -		{
    -			final String incorpNumber = this.fromApiJsonHelper.extractStringNamed(ClientApiConstants.incorpNumberParamName, clientNonPersonElement);
    -	        final String remarks = this.fromApiJsonHelper.extractStringNamed(ClientApiConstants.remarksParamName, clientNonPersonElement);                
    -	        final LocalDate incorpValidityTill = this.fromApiJsonHelper.extractLocalDateNamed(ClientApiConstants.incorpValidityTillParamName, clientNonPersonElement);
    -	        
    -	    	//JsonCommand clientNonPersonCommand = JsonCommand.fromExistingCommand(command, command.arrayOfParameterNamed(ClientApiConstants.clientNonPersonDetailsParamName).getAsJsonObject());
    -	    	CodeValue clientNonPersonConstitution = null;
    -	        final Long clientNonPersonConstitutionId = this.fromApiJsonHelper.extractLongNamed(ClientApiConstants.constitutionIdParamName, clientNonPersonElement);
    -	        if (clientNonPersonConstitutionId != null) {
    -	        	clientNonPersonConstitution = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.CLIENT_NON_PERSON_CONSTITUTION,
    -	        			clientNonPersonConstitutionId);
    -	        }
    -	        
    -	        CodeValue clientNonPersonMainBusinessLine = null;
    -	        final Long clientNonPersonMainBusinessLineId = this.fromApiJsonHelper.extractLongNamed(ClientApiConstants.mainBusinessLineIdParamName, clientNonPersonElement);
    -	        if (clientNonPersonMainBusinessLineId != null) {
    -	        	clientNonPersonMainBusinessLine = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.CLIENT_NON_PERSON_MAIN_BUSINESS_LINE,
    -	        			clientNonPersonMainBusinessLineId);
    -	        }
    -	        
    -	    	final ClientNonPerson newClientNonPerson = ClientNonPerson.createNew(client, clientNonPersonConstitution, clientNonPersonMainBusinessLine, incorpNumber, incorpValidityTill, remarks);
    -	    	
    -	    	this.clientNonPersonRepository.save(newClientNonPerson);
    +		return new CommandProcessingResultBuilder() //
    +				.withCommandId(command.commandId()) //
    +				.withOfficeId(clientForUpdate.officeId()) //
    +				.withEntityId(clientForUpdate.getId()) //
    +				.withClientId(clientId) //
    +				.with(actualChanges) //
    +				.build();
    +	}
    +
    +	@Override
    +	public CommandProcessingResult assignClientStaff(final Long clientId, final JsonCommand command) {
    +
    +		this.context.authenticatedUser();
    +
    +		final Map<String, Object> actualChanges = new LinkedHashMap<>(5);
    +
    +		this.fromApiJsonDeserializer.validateForAssignStaff(command.json());
    +
    +		final Client clientForUpdate = this.clientRepository.findOneWithNotFoundDetection(clientId);
    +
    +		Staff staff = null;
    +		final Long staffId = command.longValueOfParameterNamed(ClientApiConstants.staffIdParamName);
    +		if (staffId != null) {
    +			staff = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(staffId,
    +					clientForUpdate.getOffice().getHierarchy());
    +			/**
    +			 * TODO Vishwas: We maintain history of chage of loan officer w.r.t
    +			 * loan in a history table, should we do the same for a client?
    +			 * Especially useful when the change happens due to a transfer etc
    +			 **/
    +			clientForUpdate.assignStaff(staff);
    +		}
    +
    +		this.clientRepository.saveAndFlush(clientForUpdate);
    +
    +		actualChanges.put(ClientApiConstants.staffIdParamName, staffId);
    +
    +		return new CommandProcessingResultBuilder() //
    +				.withCommandId(command.commandId()) //
    +				.withOfficeId(clientForUpdate.officeId()) //
    +				.withEntityId(clientForUpdate.getId()) //
    +				.withClientId(clientId) //
    +				.with(actualChanges) //
    +				.build();
    +	}
    +
    +	@Transactional
    +	@Override
    +	public CommandProcessingResult closeClient(final Long clientId, final JsonCommand command) {
    +		try {
    +
    +			final AppUser currentUser = this.context.authenticatedUser();
    +			this.fromApiJsonDeserializer.validateClose(command);
    +
    +			final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
    +			final LocalDate closureDate = command
    +					.localDateValueOfParameterNamed(ClientApiConstants.closureDateParamName);
    +			final Long closureReasonId = command.longValueOfParameterNamed(ClientApiConstants.closureReasonIdParamName);
    +
    +			final CodeValue closureReason = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
    +					ClientApiConstants.CLIENT_CLOSURE_REASON, closureReasonId);
    +
    +			if (ClientStatus.fromInt(client.getStatus()).isClosed()) {
    +				final String errorMessage = "Client is already closed.";
    +				throw new InvalidClientStateTransitionException("close", "is.already.closed", errorMessage);
    +			} else if (ClientStatus.fromInt(client.getStatus()).isUnderTransfer()) {
    +				final String errorMessage = "Cannot Close a Client under Transfer";
    +				throw new InvalidClientStateTransitionException("close", "is.under.transfer", errorMessage);
    +			}
    +
    +			if (client.isNotPending() && client.getActivationLocalDate().isAfter(closureDate)) {
    +				final String errorMessage = "The client closureDate cannot be before the client ActivationDate.";
    +				throw new InvalidClientStateTransitionException("close", "date.cannot.before.client.actvation.date",
    +						errorMessage, closureDate, client.getActivationLocalDate());
    +			}
    +
    +			final List<Loan> clientLoans = this.loanRepository.findLoanByClientId(clientId);
    +
    +			for (final Loan loan : clientLoans) {
    +				final LoanStatusMapper loanStatus = new LoanStatusMapper(loan.status().getValue());
    +				if (loanStatus.isOpen() || loanStatus.isPendingApproval() || loanStatus.isAwaitingDisbursal()) {
    +					final String errorMessage = "Client cannot be closed because of non-closed loans.";
    +					throw new InvalidClientStateTransitionException("close", "loan.non-closed", errorMessage);
    +				} else if (loanStatus.isClosed() && loan.getClosedOnDate().after(closureDate.toDate())) {
    +					final String errorMessage = "The client closureDate cannot be before the loan closedOnDate.";
    +					throw new InvalidClientStateTransitionException("close", "date.cannot.before.loan.closed.date",
    +							errorMessage, closureDate, loan.getClosedOnDate());
    +				} else if (loanStatus.isOverpaid()) {
    +					final String errorMessage = "Client cannot be closed because of overpaid loans.";
    +					throw new InvalidClientStateTransitionException("close", "loan.overpaid", errorMessage);
    +				}
    +			}
    +			final List<SavingsAccount> clientSavingAccounts = this.savingsRepository
    +					.findSavingAccountByClientId(clientId);
    +
    +			for (final SavingsAccount saving : clientSavingAccounts) {
    +				if (saving.isActive() || saving.isSubmittedAndPendingApproval() || saving.isApproved()) {
    +					final String errorMessage = "Client cannot be closed because of non-closed savings account.";
    +					throw new InvalidClientStateTransitionException("close", "non-closed.savings.account",
    +							errorMessage);
    +				}
    +			}
    +
    +			client.close(currentUser, closureReason, closureDate.toDate());
    +			this.clientRepository.saveAndFlush(client);
    +
    +			return new CommandProcessingResultBuilder() //
    +					.withCommandId(command.commandId()) //
    +					.withClientId(clientId) //
    +					.withEntityId(clientId) //
    +					.build();
    +		} catch (final DataIntegrityViolationException dve) {
    +			handleDataIntegrityIssues(command, dve);
    +			return CommandProcessingResult.empty();
    +		}
    +	}
    +
    +	@Override
    +	public CommandProcessingResult updateDefaultSavingsAccount(final Long clientId, final JsonCommand command) {
    +
    +		this.context.authenticatedUser();
    +
    +		final Map<String, Object> actualChanges = new LinkedHashMap<>(5);
    +
    +		this.fromApiJsonDeserializer.validateForSavingsAccount(command.json());
    +
    +		final Client clientForUpdate = this.clientRepository.findOneWithNotFoundDetection(clientId);
    +
    +		SavingsAccount savingsAccount = null;
    +		final Long savingsId = command.longValueOfParameterNamed(ClientApiConstants.savingsAccountIdParamName);
    +		if (savingsId != null) {
    +			savingsAccount = this.savingsRepository.findOne(savingsId);
    +			if (savingsAccount == null) {
    +				throw new SavingsAccountNotFoundException(savingsId);
    +			}
    +			if (!savingsAccount.getClient().identifiedBy(clientId)) {
    +				String defaultUserMessage = "saving account must belongs to client";
    +				throw new InvalidClientSavingProductException("saving.account", "must.belongs.to.client",
    +						defaultUserMessage, savingsId, clientForUpdate.getId());
    +			}
    +			clientForUpdate.updateSavingsAccount(savingsAccount);
    +		}
    +
    +		this.clientRepository.saveAndFlush(clientForUpdate);
    +
    +		actualChanges.put(ClientApiConstants.savingsAccountIdParamName, savingsId);
    +
    +		return new CommandProcessingResultBuilder() //
    +				.withCommandId(command.commandId()) //
    +				.withOfficeId(clientForUpdate.officeId()) //
    +				.withEntityId(clientForUpdate.getId()) //
    +				.withClientId(clientId) //
    +				.with(actualChanges) //
    +				.build();
    +	}
    +
    +	/*
    +	 * To become a part of a group, group may have set of criteria to be m et
    +	 * before client can become member of it.
    +	 */
    +	private void validateParentGroupRulesBeforeClientActivation(Client client) {
    +		Integer minNumberOfClients = configurationDomainService.retrieveMinAllowedClientsInGroup();
    +		Integer maxNumberOfClients = configurationDomainService.retrieveMaxAllowedClientsInGroup();
    +		if (client.getGroups() != null && maxNumberOfClients != null) {
    +			for (Group group : client.getGroups()) {
    +				/**
    +				 * Since this Client has not yet been associated with the group,
    +				 * reduce maxNumberOfClients by 1
    +				 **/
    +				final boolean validationsuccess = group.isGroupsClientCountWithinMaxRange(maxNumberOfClients - 1);
    +				if (!validationsuccess) {
    +					throw new GroupMemberCountNotInPermissibleRangeException(group.getId(), minNumberOfClients,
    +							maxNumberOfClients);
    +				}
    +			}
    +		}
    +	}
    +
    +	@Override
    +	public CommandProcessingResult rejectClient(final Long entityId, final JsonCommand command) {
    +		final AppUser currentUser = this.context.authenticatedUser();
    +		this.fromApiJsonDeserializer.validateRejection(command);
    +
    +		final Client client = this.clientRepository.findOneWithNotFoundDetection(entityId);
    +		final LocalDate rejectionDate = command
    +				.localDateValueOfParameterNamed(ClientApiConstants.rejectionDateParamName);
    +		final Long rejectionReasonId = command.longValueOfParameterNamed(ClientApiConstants.rejectionReasonIdParamName);
    +
    +		final CodeValue rejectionReason = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
    +				ClientApiConstants.CLIENT_REJECT_REASON, rejectionReasonId);
    +
    +		if (client.isNotPending()) {
    +			final String errorMessage = "Only clients pending activation may be withdrawn.";
    +			throw new InvalidClientStateTransitionException("rejection", "on.account.not.in.pending.activation.status",
    +					errorMessage, rejectionDate, client.getSubmittedOnDate());
    +		} else if (client.getSubmittedOnDate().isAfter(rejectionDate)) {
    +			final String errorMessage = "The client rejection date cannot be before the client submitted date.";
    +			throw new InvalidClientStateTransitionException("rejection", "date.cannot.before.client.submitted.date",
    +					errorMessage, rejectionDate, client.getSubmittedOnDate());
    +		}
    +		client.reject(currentUser, rejectionReason, rejectionDate.toDate());
    +		this.clientRepository.saveAndFlush(client);
    +
    +		return new CommandProcessingResultBuilder() //
    +				.withCommandId(command.commandId()) //
    +				.withClientId(entityId) //
    +				.withEntityId(entityId) //
    +				.build();
    +	}
    +
    +	@Override
    +	public CommandProcessingResult withdrawClient(Long entityId, JsonCommand command) {
    +		final AppUser currentUser = this.context.authenticatedUser();
    +		this.fromApiJsonDeserializer.validateWithdrawn(command);
    +
    +		final Client client = this.clientRepository.findOneWithNotFoundDetection(entityId);
    +		final LocalDate withdrawalDate = command
    +				.localDateValueOfParameterNamed(ClientApiConstants.withdrawalDateParamName);
    +		final Long withdrawalReasonId = command
    +				.longValueOfParameterNamed(ClientApiConstants.withdrawalReasonIdParamName);
    +
    +		final CodeValue withdrawalReason = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
    +				ClientApiConstants.CLIENT_WITHDRAW_REASON, withdrawalReasonId);
    +
    +		if (client.isNotPending()) {
    +			final String errorMessage = "Only clients pending activation may be withdrawn.";
    +			throw new InvalidClientStateTransitionException("withdrawal", "on.account.not.in.pending.activation.status",
    +					errorMessage, withdrawalDate, client.getSubmittedOnDate());
    +		} else if (client.getSubmittedOnDate().isAfter(withdrawalDate)) {
    +			final String errorMessage = "The client withdrawal date cannot be before the client submitted date.";
    +			throw new InvalidClientStateTransitionException("withdrawal", "date.cannot.before.client.submitted.date",
    +					errorMessage, withdrawalDate, client.getSubmittedOnDate());
    +		}
    +		client.withdraw(currentUser, withdrawalReason, withdrawalDate.toDate());
    +		this.clientRepository.saveAndFlush(client);
    +
    +		return new CommandProcessingResultBuilder() //
    +				.withCommandId(command.commandId()) //
    +				.withClientId(entityId) //
    +				.withEntityId(entityId) //
    +				.build();
    +	}
    +
    +	@Override
    +	public CommandProcessingResult reActivateClient(Long entityId, JsonCommand command) {
    +		final AppUser currentUser = this.context.authenticatedUser();
    +		this.fromApiJsonDeserializer.validateReactivate(command);
    +
    +		final Client client = this.clientRepository.findOneWithNotFoundDetection(entityId);
    +		final LocalDate reactivateDate = command
    +				.localDateValueOfParameterNamed(ClientApiConstants.reactivationDateParamName);
    +
    +		if (!client.isClosed()) {
    +			final String errorMessage = "only closed clients may be reactivated.";
    +			throw new InvalidClientStateTransitionException("reactivation", "on.nonclosed.account", errorMessage);
    +		} else if (client.getClosureDate().isAfter(reactivateDate)) {
    +			final String errorMessage = "The client reactivation date cannot be before the client closed date.";
    +			throw new InvalidClientStateTransitionException("reactivation", "date.cannot.before.client.closed.date",
    +					errorMessage, reactivateDate, client.getClosureDate());
     		}
    -    }
    --- End diff --
    
    @nikpawar89 do not reformat the old code


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-fineract pull request #201: address_module

Posted by Nayan <gi...@git.apache.org>.
Github user Nayan commented on a diff in the pull request:

    https://github.com/apache/incubator-fineract/pull/201#discussion_r74359839
  
    --- Diff: fineract-provider/src/main/resources/sql/migrations/core_db/V312__address_module_tables_metadat.sql ---
    @@ -0,0 +1,142 @@
    +--
    +-- Licensed to the Apache Software Foundation (ASF) under one
    +-- or more contributor license agreements. See the NOTICE file
    +-- distributed with this work for additional information
    +-- regarding copyright ownership. The ASF licenses this file
    +-- to you under the Apache License, Version 2.0 (the
    +-- "License"); you may not use this file except in compliance
    +-- with the License. You may obtain a copy of the License at
    +--
    +-- http://www.apache.org/licenses/LICENSE-2.0
    +--
    +-- Unless required by applicable law or agreed to in writing,
    +-- software distributed under the License is distributed on an
    +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    +-- KIND, either express or implied. See the License for the
    +-- specific language governing permissions and limitations
    +-- under the License.
    +
    +
    +
    +-- code inserts
    +INSERT INTO `m_code` (`code_name`, `is_system_defined`) VALUES ('STATE',1);
    +INSERT INTO `m_code` (`code_name`, `is_system_defined`) VALUES ('COUNTRY',1);
    +INSERT INTO `m_code` (`code_name`, `is_system_defined`) VALUES ('ADDRESS_TYPE',1);
    +
    +-- inserts for COUNTRY
    + 
    +   INSERT INTO `m_code_value` (`code_id`, `code_value`,`order_position`, `is_active`) 
    +VALUES(
    + (select id from m_code where code_name = 'COUNTRY'), 'India', 0,1);
    --- End diff --
    
    this data should not be part of migration script


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-fineract pull request #201: address_module

Posted by nikpawar89 <gi...@git.apache.org>.
Github user nikpawar89 closed the pull request at:

    https://github.com/apache/incubator-fineract/pull/201


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-fineract pull request #201: address_module

Posted by Nayan <gi...@git.apache.org>.
Github user Nayan commented on a diff in the pull request:

    https://github.com/apache/incubator-fineract/pull/201#discussion_r74360007
  
    --- Diff: fineract-provider/src/main/resources/sql/migrations/core_db/V312__address_module_tables_metadat.sql ---
    @@ -0,0 +1,142 @@
    +--
    +-- Licensed to the Apache Software Foundation (ASF) under one
    +-- or more contributor license agreements. See the NOTICE file
    +-- distributed with this work for additional information
    +-- regarding copyright ownership. The ASF licenses this file
    +-- to you under the Apache License, Version 2.0 (the
    +-- "License"); you may not use this file except in compliance
    +-- with the License. You may obtain a copy of the License at
    +--
    +-- http://www.apache.org/licenses/LICENSE-2.0
    +--
    +-- Unless required by applicable law or agreed to in writing,
    +-- software distributed under the License is distributed on an
    +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    +-- KIND, either express or implied. See the License for the
    +-- specific language governing permissions and limitations
    +-- under the License.
    +
    +
    +
    +-- code inserts
    +INSERT INTO `m_code` (`code_name`, `is_system_defined`) VALUES ('STATE',1);
    +INSERT INTO `m_code` (`code_name`, `is_system_defined`) VALUES ('COUNTRY',1);
    +INSERT INTO `m_code` (`code_name`, `is_system_defined`) VALUES ('ADDRESS_TYPE',1);
    +
    +-- inserts for COUNTRY
    + 
    +   INSERT INTO `m_code_value` (`code_id`, `code_value`,`order_position`, `is_active`) 
    +VALUES(
    + (select id from m_code where code_name = 'COUNTRY'), 'India', 0,1);
    +INSERT INTO `m_code_value` (`code_id`, `code_value`,`order_position`, `is_active`) 
    +VALUES(
    + (select id from m_code where code_name = 'COUNTRY'), 'Srilanka', 0,1);
    + INSERT INTO `m_code_value` (`code_id`, `code_value`,`order_position`, `is_active`) 
    +VALUES(
    + (select id from m_code where code_name = 'COUNTRY'), 'Nigeria', 0,1);
    +
    +-- inserts for address type
    +  INSERT INTO `m_code_value` (`code_id`, `code_value`,`order_position`, `is_active`) 
    +VALUES(
    + (select id from m_code where code_name = 'ADDRESS_TYPE'), 'PERMANENT ADDRESS', 0,1);
    +  INSERT INTO `m_code_value` (`code_id`, `code_value`,`order_position`, `is_active`) 
    +VALUES(
    + (select id from m_code where code_name = 'ADDRESS_TYPE'), 'OFFICE ADDRESS', 0,1);
    +  INSERT INTO `m_code_value` (`code_id`, `code_value`,`order_position`, `is_active`) 
    +VALUES(
    + (select id from m_code where code_name = 'ADDRESS_TYPE'), 'CURRENT ADDRESS', 0,1);
    +
    +
    +
    +
    +-- configuration
    +INSERT INTO `c_configuration` (`name`, `value`, `date_value`, `enabled`, `is_trap_door`, `description`) VALUES ('Enable-Address', NULL, NULL, 1, 0, NULL);
    +
    +-- add address table
    +CREATE TABLE `m_address` (
    +	`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
    +	`street` VARCHAR(100) NULL DEFAULT NULL,
    +	`address_line_1` VARCHAR(100) NULL DEFAULT NULL,
    +	`address_line_2` VARCHAR(100) NULL DEFAULT NULL,
    +	`address_line_3` VARCHAR(100) NULL DEFAULT NULL,
    +	`town_village` VARCHAR(100) NULL DEFAULT NULL,
    +	`city` VARCHAR(100) NULL DEFAULT NULL,
    +	`county_district` VARCHAR(100) NULL DEFAULT NULL,
    +	`state_province_id` INT(11) NULL DEFAULT NULL,
    +	`country_id` INT(11) NULL DEFAULT NULL,
    +	`postal_code` VARCHAR(10) NULL DEFAULT NULL,
    +	`latitude` DECIMAL(10,8) UNSIGNED NULL DEFAULT '0.00000000',
    +	`longitude` DECIMAL(10,8) UNSIGNED NULL DEFAULT '0.00000000',
    +	`created_by` VARCHAR(100) NULL DEFAULT NULL,
    +	`created_on` DATE NULL DEFAULT NULL,
    +	`updated_by` VARCHAR(100) NULL DEFAULT NULL,
    +	`updated_on` DATE NULL DEFAULT NULL,
    +	PRIMARY KEY (`id`),
    +	INDEX `address_fields_codefk1` (`state_province_id`),
    +	INDEX `address_fields_codefk2` (`country_id`),
    +	CONSTRAINT `address_fields_codefk1` FOREIGN KEY (`state_province_id`) REFERENCES `m_code_value` (`id`),
    +	CONSTRAINT `address_fields_codefk2` FOREIGN KEY (`country_id`) REFERENCES `m_code_value` (`id`)
    +)
    +ENGINE=InnoDB
    +AUTO_INCREMENT=1
    +;
    +
    +
    +-- entity address table
    +CREATE TABLE `m_client_address` (
    +	`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
    +	`client_id` BIGINT(20) NOT NULL DEFAULT '0',
    +	`address_id` BIGINT(20) NOT NULL DEFAULT '0',
    +	`address_type_id` INT(11) NOT NULL DEFAULT '0',
    +	`is_active` TINYINT(4) NOT NULL DEFAULT '0',
    +	PRIMARY KEY (`id`),
    +	INDEX `addressIdFk` (`address_id`),
    +	INDEX `address_codefk` (`address_type_id`),
    +	INDEX `clientaddressfk` (`client_id`),
    +	CONSTRAINT `address_codefk` FOREIGN KEY (`address_type_id`) REFERENCES `m_code_value` (`id`),
    +	CONSTRAINT `clientaddressfk` FOREIGN KEY (`client_id`) REFERENCES `m_client` (`id`)
    +)
    +ENGINE=InnoDB
    +AUTO_INCREMENT=1
    +;
    +
    +
    +-- field configuration
    +CREATE TABLE `m_field_configuration` (
    +	`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
    +	`entity` VARCHAR(100) NOT NULL,
    +	`subentity` VARCHAR(100) NOT NULL,
    +	`field` VARCHAR(100) NOT NULL,
    +	`is_enabled` TINYINT(4) NOT NULL,
    +	`is_mandatory` TINYINT(4) NOT NULL,
    +	`validation_regex` VARCHAR(50) NULL DEFAULT NULL,
    +	PRIMARY KEY (`id`)
    +)
    +ENGINE=InnoDB
    +AUTO_INCREMENT=1
    +;
    +
    +
    +INSERT INTO `m_field_configuration` ( `entity`, `subentity`, `field`, `is_enabled`, `is_mandatory`, `validation_regex`) VALUES
    +	('ADDRESS', 'CLIENT', 'addressType', 1, 0, ''),
    +	('ADDRESS', 'CLIENT', 'street', 1, 1, ''),
    +	('ADDRESS', 'CLIENT', 'addressLine1', 1, 0, ''),
    +	('ADDRESS', 'CLIENT', 'addressLine2', 1, 0, ''),
    +	('ADDRESS', 'CLIENT', 'addressLine3', 1, 0, ''),
    +	('ADDRESS', 'CLIENT', 'townVillage', 0, 0, ''),
    +	('ADDRESS', 'CLIENT', 'city', 1, 0, ''),
    +	('ADDRESS', 'CLIENT', 'countyDistrict', 0, 0, ''),
    +	('ADDRESS', 'CLIENT', 'stateProvinceId', 1, 0, ''),
    +	('ADDRESS', 'CLIENT', 'countryId', 1, 0, ''),
    +	('ADDRESS', 'CLIENT', 'postalCode', 1, 0, ''),
    +	('ADDRESS', 'CLIENT', 'latitude', 0, 0, ''),
    +	('ADDRESS', 'CLIENT', 'longitude', 0, 0, ''),
    +	('ADDRESS', 'CLIENT', 'createdBy', 1, 0, ''),
    +	('ADDRESS', 'CLIENT', 'createdOn', 1, 0, ''),
    +	('ADDRESS', 'CLIENT', 'updatedBy', 1, 0, ''),
    +	('ADDRESS', 'CLIENT', 'updatedOn', 1, 0, ''),
    +	('ADDRESS', 'CLIENT', 'isActive', 1, 0, '');
    +
    +-- inserts for permission
    +INSERT INTO `m_permission` ( `grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'CREATE_ADDRESS', 'ADDRESS', 'CREATE', 0);
    --- End diff --
    
    @nikpawar89  all the permissions are not covered like create, delete, update of address


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-fineract pull request #201: address_module

Posted by Nayan <gi...@git.apache.org>.
Github user Nayan commented on a diff in the pull request:

    https://github.com/apache/incubator-fineract/pull/201#discussion_r74360092
  
    --- Diff: fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientData.java ---
    @@ -39,420 +40,469 @@
      */
     final public class ClientData implements Comparable<ClientData> {
     
    -    private final Long id;
    --- End diff --
    
    @nikpawar89 do not reformat the old code


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-fineract pull request #201: address_module

Posted by Nayan <gi...@git.apache.org>.
Github user Nayan commented on a diff in the pull request:

    https://github.com/apache/incubator-fineract/pull/201#discussion_r74359923
  
    --- Diff: fineract-provider/src/main/resources/sql/migrations/core_db/V312__address_module_tables_metadat.sql ---
    @@ -0,0 +1,142 @@
    +--
    +-- Licensed to the Apache Software Foundation (ASF) under one
    +-- or more contributor license agreements. See the NOTICE file
    +-- distributed with this work for additional information
    +-- regarding copyright ownership. The ASF licenses this file
    +-- to you under the Apache License, Version 2.0 (the
    +-- "License"); you may not use this file except in compliance
    +-- with the License. You may obtain a copy of the License at
    +--
    +-- http://www.apache.org/licenses/LICENSE-2.0
    +--
    +-- Unless required by applicable law or agreed to in writing,
    +-- software distributed under the License is distributed on an
    +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    +-- KIND, either express or implied. See the License for the
    +-- specific language governing permissions and limitations
    +-- under the License.
    +
    +
    +
    +-- code inserts
    +INSERT INTO `m_code` (`code_name`, `is_system_defined`) VALUES ('STATE',1);
    +INSERT INTO `m_code` (`code_name`, `is_system_defined`) VALUES ('COUNTRY',1);
    +INSERT INTO `m_code` (`code_name`, `is_system_defined`) VALUES ('ADDRESS_TYPE',1);
    +
    +-- inserts for COUNTRY
    + 
    +   INSERT INTO `m_code_value` (`code_id`, `code_value`,`order_position`, `is_active`) 
    +VALUES(
    + (select id from m_code where code_name = 'COUNTRY'), 'India', 0,1);
    +INSERT INTO `m_code_value` (`code_id`, `code_value`,`order_position`, `is_active`) 
    +VALUES(
    + (select id from m_code where code_name = 'COUNTRY'), 'Srilanka', 0,1);
    + INSERT INTO `m_code_value` (`code_id`, `code_value`,`order_position`, `is_active`) 
    +VALUES(
    + (select id from m_code where code_name = 'COUNTRY'), 'Nigeria', 0,1);
    +
    +-- inserts for address type
    +  INSERT INTO `m_code_value` (`code_id`, `code_value`,`order_position`, `is_active`) 
    +VALUES(
    + (select id from m_code where code_name = 'ADDRESS_TYPE'), 'PERMANENT ADDRESS', 0,1);
    --- End diff --
    
    @nikpawar89 Data like 'ERMANENT ADDRESS' will be config by admin and this will diff from org to org


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---