@Transactional
  @Override
  public CommandProcessingResult createOffice(final JsonCommand command) {

    try {
      final AppUser currentUser = context.authenticatedUser();

      this.fromApiJsonDeserializer.validateForCreate(command.json());

      Long parentId = null;
      if (command.parameterExists("parentId")) {
        parentId = command.longValueOfParameterNamed("parentId");
      }

      final Office parent = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, parentId);
      final Office office = Office.fromJson(parent, command);

      // pre save to generate id for use in office hierarchy
      this.officeRepository.save(office);

      office.generateHierarchy();

      this.officeRepository.save(office);

      return new CommandProcessingResultBuilder() //
          .withCommandId(command.commandId()) //
          .withEntityId(office.getId()) //
          .withOfficeId(office.getId()) //
          .build();
    } catch (DataIntegrityViolationException dve) {
      handleOfficeDataIntegrityIssues(command, dve);
      return CommandProcessingResult.empty();
    }
  }
  @Transactional
  @Override
  @Caching(
      evict = {
        @CacheEvict(
            value = "offices",
            key =
                "T(org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat(#root.target.context.authenticatedUser().getOffice().getHierarchy()+'of')"),
        @CacheEvict(
            value = "officesForDropdown",
            key =
                "T(org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat(#root.target.context.authenticatedUser().getOffice().getHierarchy()+'ofd')"),
        @CacheEvict(
            value = "officesById",
            key =
                "T(org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat(#officeId)")
      })
  public CommandProcessingResult updateOffice(final Long officeId, final JsonCommand command) {

    try {
      final AppUser currentUser = context.authenticatedUser();

      this.fromApiJsonDeserializer.validateForUpdate(command.json());

      Long parentId = null;
      if (command.parameterExists("parentId")) {
        parentId = command.longValueOfParameterNamed("parentId");
      }

      final Office office = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, officeId);

      final Map<String, Object> changes = office.update(command);

      if (changes.containsKey("parentId")) {
        final Office parent = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, parentId);
        office.update(parent);
      }

      if (!changes.isEmpty()) {
        this.officeRepository.saveAndFlush(office);
      }

      return new CommandProcessingResultBuilder() //
          .withCommandId(command.commandId()) //
          .withEntityId(office.getId()) //
          .withOfficeId(office.getId()) //
          .with(changes) //
          .build();
    } catch (DataIntegrityViolationException dve) {
      handleOfficeDataIntegrityIssues(command, dve);
      return CommandProcessingResult.empty();
    }
  }
  @Transactional
  @Override
  public CommandProcessingResult officeTransaction(final JsonCommand command) {

    context.authenticatedUser();

    this.moneyTransferCommandFromApiJsonDeserializer.validateOfficeTransfer(command.json());

    Long officeId = null;
    Office fromOffice = null;
    final Long fromOfficeId = command.longValueOfParameterNamed("fromOfficeId");
    if (fromOfficeId != null) {
      fromOffice = this.officeRepository.findOne(fromOfficeId);
      officeId = fromOffice.getId();
    }
    Office toOffice = null;
    final Long toOfficeId = command.longValueOfParameterNamed("toOfficeId");
    if (toOfficeId != null) {
      toOffice = this.officeRepository.findOne(toOfficeId);
      officeId = toOffice.getId();
    }

    if (fromOffice == null && toOffice == null) {
      throw new OfficeNotFoundException(toOfficeId);
    }

    final String currencyCode = command.stringValueOfParameterNamed("currencyCode");
    final ApplicationCurrency appCurrency =
        this.applicationCurrencyRepository.findOneByCode(currencyCode);
    if (appCurrency == null) {
      throw new CurrencyNotFoundException(currencyCode);
    }

    final MonetaryCurrency currency =
        new MonetaryCurrency(appCurrency.getCode(), appCurrency.getDecimalPlaces());
    final Money amount =
        Money.of(currency, command.bigDecimalValueOfParameterNamed("transactionAmount"));

    final OfficeTransaction entity =
        OfficeTransaction.fromJson(fromOffice, toOffice, amount, command);

    this.officeTransactionRepository.save(entity);

    return new CommandProcessingResultBuilder() //
        .withCommandId(command.commandId()) //
        .withEntityId(entity.getId()) //
        .withOfficeId(officeId) //
        .build();
  }
  @Transactional
  @Override
  @CacheEvict(value = "usersByUsername", allEntries = true)
  public CommandProcessingResult createUser(final JsonCommand command) {

    try {
      this.context.authenticatedUser();

      this.fromApiJsonDeserializer.validateForCreate(command.json());

      final String officeIdParamName = "officeId";
      final Long officeId = command.longValueOfParameterNamed(officeIdParamName);

      final Office userOffice = this.officeRepository.findOne(officeId);
      if (userOffice == null) {
        throw new OfficeNotFoundException(officeId);
      }

      final String[] roles = command.arrayValueOfParameterNamed("roles");
      final Set<Role> allRoles = assembleSetOfRoles(roles);

      final AppUser appUser = AppUser.fromJson(userOffice, allRoles, command);
      final Boolean sendPasswordToEmail =
          command.booleanObjectValueOfParameterNamed("sendPasswordToEmail");
      this.userDomainService.create(appUser, sendPasswordToEmail);

      return new CommandProcessingResultBuilder() //
          .withCommandId(command.commandId()) //
          .withEntityId(appUser.getId()) //
          .withOfficeId(userOffice.getId()) //
          .build();
    } catch (final DataIntegrityViolationException dve) {
      handleDataIntegrityIssues(command, dve);
      return CommandProcessingResult.empty();
    } catch (final PlatformEmailSendException e) {
      final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();

      final String email = command.stringValueOfParameterNamed("email");
      final ApiParameterError error =
          ApiParameterError.parameterError(
              "error.msg.user.email.invalid", "The parameter email is invalid.", "email", email);
      dataValidationErrors.add(error);

      throw new PlatformApiDataValidationException(
          "validation.msg.validation.errors.exist",
          "Validation errors exist.",
          dataValidationErrors);
    }
  }
  @Transactional
  @Override
  public CommandProcessingResult updateOffice(final Long officeId, final JsonCommand command) {

    try {
      final AppUser currentUser = context.authenticatedUser();

      this.fromApiJsonDeserializer.validateForUpdate(command.json());

      Long parentId = null;
      if (command.parameterExists("parentId")) {
        parentId = command.longValueOfParameterNamed("parentId");
      }

      final Office office = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, officeId);

      final Map<String, Object> changes = office.update(command);

      if (changes.containsKey("parentId")) {
        final Office parent = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, parentId);
        office.update(parent);
      }

      if (!changes.isEmpty()) {
        this.officeRepository.saveAndFlush(office);
      }

      return new CommandProcessingResultBuilder() //
          .withCommandId(command.commandId()) //
          .withEntityId(office.getId()) //
          .withOfficeId(office.getId()) //
          .with(changes) //
          .build();
    } catch (DataIntegrityViolationException dve) {
      handleOfficeDataIntegrityIssues(command, dve);
      return CommandProcessingResult.empty();
    }
  }
  /*
   * used to restrict modifying operations to office that are either the users
   * office or lower (child) in the office hierarchy
   */
  private Office validateUserPriviledgeOnOfficeAndRetrieve(
      final AppUser currentUser, final Long officeId) {

    final Long userOfficeId = currentUser.getOffice().getId();
    final Office userOffice = this.officeRepository.findOne(userOfficeId);
    if (userOffice == null) {
      throw new OfficeNotFoundException(userOfficeId);
    }

    if (userOffice.doesNotHaveAnOfficeInHierarchyWithId(officeId)) {
      throw new NoAuthorizationException(
          "User does not have sufficient priviledges to act on the provided office.");
    }

    Office officeToReturn = userOffice;
    if (!userOffice.identifiedBy(officeId)) {
      officeToReturn = this.officeRepository.findOne(officeId);
      if (officeToReturn == null) {
        throw new OfficeNotFoundException(officeId);
      }
    }

    return officeToReturn;
  }