@Transactional
  @Override
  public CommandProcessingResult deleteGLClosure(final Long glClosureId) {
    final GLClosure glClosure = this.glClosureRepository.findOne(glClosureId);

    if (glClosure == null) {
      throw new GLClosureNotFoundException(glClosureId);
    }

    /** check if any closures are present for this branch at a later date than this closure date */
    final Date closureDate = glClosure.getClosingDate();
    final GLClosure latestGLClosure =
        this.glClosureRepository.getLatestGLClosureByBranch(glClosure.getOffice().getId());
    if (latestGLClosure.getClosingDate().after(closureDate)) {
      throw new GLClosureInvalidDeleteException(
          latestGLClosure.getOffice().getId(),
          latestGLClosure.getOffice().getName(),
          latestGLClosure.getClosingDate());
    }

    this.glClosureRepository.delete(glClosure);

    return new CommandProcessingResultBuilder()
        .withOfficeId(glClosure.getOffice().getId())
        .withEntityId(glClosure.getId())
        .build();
  }
  @Transactional
  @Override
  public CommandProcessingResult updateGLClosure(
      final Long glClosureId, final JsonCommand command) {
    final GLClosureCommand closureCommand =
        this.fromApiJsonDeserializer.commandFromApiJson(command.json());
    closureCommand.validateForUpdate();

    // is the glClosure valid
    final GLClosure glClosure = this.glClosureRepository.findOne(glClosureId);
    if (glClosure == null) {
      throw new GLClosureNotFoundException(glClosureId);
    }

    final Map<String, Object> changesOnly = glClosure.update(command);

    if (!changesOnly.isEmpty()) {
      this.glClosureRepository.saveAndFlush(glClosure);
    }

    return new CommandProcessingResultBuilder()
        .withCommandId(command.commandId())
        .withOfficeId(glClosure.getOffice().getId())
        .withEntityId(glClosure.getId())
        .with(changesOnly)
        .build();
  }
  @Transactional
  @Override
  public CommandProcessingResult createGLClosure(final JsonCommand command) {
    try {
      final GLClosureCommand closureCommand =
          this.fromApiJsonDeserializer.commandFromApiJson(command.json());
      closureCommand.validateForCreate();

      // check office is valid
      final Long officeId =
          command.longValueOfParameterNamed(GLClosureJsonInputParams.OFFICE_ID.getValue());
      final Office office = this.officeRepository.findOne(officeId);
      if (office == null) {
        throw new OfficeNotFoundException(officeId);
      }

      // TODO: Get Tenant specific date
      // ensure closure date is not in the future
      final Date todaysDate = DateUtils.getDateOfTenant();
      final Date closureDate =
          command.DateValueOfParameterNamed(GLClosureJsonInputParams.CLOSING_DATE.getValue());
      if (closureDate.after(todaysDate)) {
        throw new GLClosureInvalidException(GL_CLOSURE_INVALID_REASON.FUTURE_DATE, closureDate);
      }
      // shouldn't be before an existing accounting closure
      final GLClosure latestGLClosure =
          this.glClosureRepository.getLatestGLClosureByBranch(officeId);
      if (latestGLClosure != null) {
        if (latestGLClosure.getClosingDate().after(closureDate)) {
          throw new GLClosureInvalidException(
              GL_CLOSURE_INVALID_REASON.ACCOUNTING_CLOSED, latestGLClosure.getClosingDate());
        }
      }
      final GLClosure glClosure = GLClosure.fromJson(office, command);

      this.glClosureRepository.saveAndFlush(glClosure);

      return new CommandProcessingResultBuilder()
          .withCommandId(command.commandId())
          .withOfficeId(officeId)
          .withEntityId(glClosure.getId())
          .build();
    } catch (final DataIntegrityViolationException dve) {
      handleGLClosureIntegrityIssues(command, dve);
      return CommandProcessingResult.empty();
    }
  }