@Transactional
  @Override
  public CommandProcessingResult modifyApplication(
      final Long savingsId, final JsonCommand command) {
    try {
      this.savingsAccountDataValidator.validateForUpdate(command.json());

      final Map<String, Object> changes = new LinkedHashMap<String, Object>(20);

      final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
      checkClientOrGroupActive(account);
      account.modifyApplication(command, changes);
      account.validateNewApplicationState(DateUtils.getLocalDateOfTenant());
      account.validateAccountValuesWithProduct();

      if (!changes.isEmpty()) {

        if (changes.containsKey(SavingsApiConstants.clientIdParamName)) {
          final Long clientId =
              command.longValueOfParameterNamed(SavingsApiConstants.clientIdParamName);
          if (clientId != null) {
            final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
            if (client.isNotActive()) {
              throw new ClientNotActiveException(clientId);
            }
            account.update(client);
          } else {
            final Client client = null;
            account.update(client);
          }
        }

        if (changes.containsKey(SavingsApiConstants.groupIdParamName)) {
          final Long groupId =
              command.longValueOfParameterNamed(SavingsApiConstants.groupIdParamName);
          if (groupId != null) {
            final Group group = this.groupRepository.findOne(groupId);
            if (group == null) {
              throw new GroupNotFoundException(groupId);
            }
            if (group.isNotActive()) {
              if (group.isCenter()) {
                throw new CenterNotActiveException(groupId);
              }
              throw new GroupNotActiveException(groupId);
            }
            account.update(group);
          } else {
            final Group group = null;
            account.update(group);
          }
        }

        if (changes.containsKey(SavingsApiConstants.productIdParamName)) {
          final Long productId =
              command.longValueOfParameterNamed(SavingsApiConstants.productIdParamName);
          final SavingsProduct product = this.savingsProductRepository.findOne(productId);
          if (product == null) {
            throw new SavingsProductNotFoundException(productId);
          }

          account.update(product);
        }

        if (changes.containsKey(SavingsApiConstants.fieldOfficerIdParamName)) {
          final Long fieldOfficerId =
              command.longValueOfParameterNamed(SavingsApiConstants.fieldOfficerIdParamName);
          Staff fieldOfficer = null;
          if (fieldOfficerId != null) {
            fieldOfficer = this.staffRepository.findOneWithNotFoundDetection(fieldOfficerId);
          } else {
            changes.put(SavingsApiConstants.fieldOfficerIdParamName, "");
          }
          account.update(fieldOfficer);
        }

        if (changes.containsKey("charges")) {
          final Set<SavingsAccountCharge> charges =
              this.savingsAccountChargeAssembler.fromParsedJson(
                  command.parsedJson(), account.getCurrency().getCode());
          final boolean updated = account.update(charges);
          if (!updated) {
            changes.remove("charges");
          }
        }

        this.savingAccountRepository.saveAndFlush(account);
      }

      return new CommandProcessingResultBuilder() //
          .withCommandId(command.commandId()) //
          .withEntityId(savingsId) //
          .withOfficeId(account.officeId()) //
          .withClientId(account.clientId()) //
          .withGroupId(account.groupId()) //
          .withSavingsId(savingsId) //
          .with(changes) //
          .build();
    } catch (final DataAccessException dve) {
      handleDataIntegrityIssues(command, dve);
      return new CommandProcessingResult(Long.valueOf(-1));
    }
  }
  @Transactional
  @Override
  public CommandProcessingResult updateSavingAccount(
      final Long savingsId, final JsonCommand command) {
    try {
      this.context.authenticatedUser();
      this.savingsAccountDataValidator.validateForUpdate(command.json());

      final Map<String, Object> changes = new LinkedHashMap<String, Object>(20);

      final SavingsAccount account =
          this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);

      account.update(command, changes);

      if (!changes.isEmpty()) {

        if (changes.containsKey(SavingsApiConstants.clientIdParamName)) {
          final Long clientId =
              command.longValueOfParameterNamed(SavingsApiConstants.clientIdParamName);
          if (clientId != null) {
            final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
            account.update(client);
          } else {
            final Client client = null;
            account.update(client);
          }
        }

        if (changes.containsKey(SavingsApiConstants.groupIdParamName)) {
          final Long groupId =
              command.longValueOfParameterNamed(SavingsApiConstants.groupIdParamName);
          if (groupId != null) {
            final Group group = this.groupRepository.findOne(groupId);
            if (group == null) {
              throw new GroupNotFoundException(groupId);
            }
            account.update(group);
          } else {
            final Group group = null;
            account.update(group);
          }
        }

        if (changes.containsKey(SavingsApiConstants.productIdParamName)) {
          final Long productId =
              command.longValueOfParameterNamed(SavingsApiConstants.productIdParamName);
          final SavingsProduct product = this.savingsProductRepository.findOne(productId);
          if (product == null) {
            throw new SavingsProductNotFoundException(productId);
          }

          account.update(product);
        }

        this.savingAccountRepository.saveAndFlush(account);
      }

      return new CommandProcessingResultBuilder() //
          .withCommandId(command.commandId()) //
          .withEntityId(savingsId) //
          .withOfficeId(account.officeId()) //
          .withClientId(account.clientId()) //
          .withGroupId(account.groupId()) //
          .withSavingsId(savingsId) //
          .with(changes) //
          .build();
    } catch (DataAccessException dve) {
      handleDataIntegrityIssues(command, dve);
      return new CommandProcessingResult(Long.valueOf(-1));
    }
  }