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

    return this.writePlatformService.adjustLoanTransaction(
        command.getLoanId(), command.entityId(), command);
  }
  @Override
  public CommandProcessingResult updateOfficeRunningBalance(JsonCommand command) {
    this.dataValidator.validateForUpdateRunningbalance(command);
    final Long officeId =
        this.fromApiJsonHelper.extractLongNamed(
            JournalEntryJsonInputParams.OFFICE_ID.getValue(), command.parsedJson());
    CommandProcessingResultBuilder commandProcessingResultBuilder =
        new CommandProcessingResultBuilder().withCommandId(command.commandId());
    if (officeId == null) {
      updateRunningBalance();
    } else {
      final Office office = this.officeRepository.findOne(officeId);
      if (office == null) {
        throw new OfficeNotFoundException(officeId);
      }

      String dateFinder =
          "select MIN(je.entry_date) as entityDate "
              + "from acc_gl_journal_entry  je "
              + "where je.is_running_balance_calculated=0  and je.office_id=?";
      try {
        Date entityDate = this.jdbcTemplate.queryForObject(dateFinder, Date.class, officeId);
        updateRunningBalance(officeId, entityDate);
      } catch (EmptyResultDataAccessException e) {
        logger.debug(
            "No results found for updation of office running balance with office id:" + officeId);
      }
      commandProcessingResultBuilder.withOfficeId(officeId);
    }
    return commandProcessingResultBuilder.build();
  }
  /*
   * Guaranteed to throw an exception no matter what the data integrity issue
   * is.
   */
  private void handleDataIntegrityIssues(
      final JsonCommand command, final Throwable realCause, final Exception dae) {

    if (realCause.getMessage().contains("sp_unq_name")) {

      final String name = command.stringValueOfParameterNamed("name");
      throw new PlatformDataIntegrityException(
          "error.msg.product.savings.duplicate.name",
          "Savings product with name `" + name + "` already exists",
          "name",
          name);
    } else if (realCause.getMessage().contains("sp_unq_short_name")) {

      final String shortName = command.stringValueOfParameterNamed("shortName");
      throw new PlatformDataIntegrityException(
          "error.msg.product.savings.duplicate.short.name",
          "Savings product with short name `" + shortName + "` already exists",
          "shortName",
          shortName);
    }

    logAsErrorUnexpectedDataIntegrityException(dae);
    throw new PlatformDataIntegrityException(
        "error.msg.savingsproduct.unknown.data.integrity.issue",
        "Unknown data integrity issue with resource.");
  }
  public SmsMessage assembleFromJson(final JsonCommand command) {

    final JsonElement element = command.parsedJson();

    String mobileNo = null;

    Group group = null;
    if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.groupIdParamName, element)) {
      final Long groupId =
          this.fromApiJsonHelper.extractLongNamed(SmsApiConstants.groupIdParamName, element);
      group = this.groupRepository.findOneWithNotFoundDetection(groupId);
    }

    Client client = null;
    if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.clientIdParamName, element)) {
      final Long clientId =
          this.fromApiJsonHelper.extractLongNamed(SmsApiConstants.clientIdParamName, element);
      client = this.clientRepository.findOneWithNotFoundDetection(clientId);
      mobileNo = client.mobileNo();
    }

    Staff staff = null;
    if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.staffIdParamName, element)) {
      final Long staffId =
          this.fromApiJsonHelper.extractLongNamed(SmsApiConstants.staffIdParamName, element);
      staff = this.staffRepository.findOneWithNotFoundDetection(staffId);
      mobileNo = staff.mobileNo();
    }

    final String message =
        this.fromApiJsonHelper.extractStringNamed(SmsApiConstants.messageParamName, element);

    return SmsMessage.pendingSms(group, client, staff, message, mobileNo);
  }
  @Transactional
  @Override
  public CommandProcessingResult create(final JsonCommand command) {

    try {
      this.fromApiJsonDataValidator.validateForCreate(command.json());

      final SavingsProduct product = this.savingsProductAssembler.assemble(command);

      this.savingProductRepository.save(product);

      // save accounting mappings
      this.accountMappingWritePlatformService.createSavingProductToGLAccountMapping(
          product.getId(), command, DepositAccountType.SAVINGS_DEPOSIT);

      // check if the office specific products are enabled. If yes, then
      // save this savings product against a specific office
      // i.e. this savings product is specific for this office.
      fineractEntityAccessUtil.checkConfigurationAndAddProductResrictionsForUserOffice(
          FineractEntityAccessType.OFFICE_ACCESS_TO_SAVINGS_PRODUCTS, product.getId());

      return new CommandProcessingResultBuilder() //
          .withEntityId(product.getId()) //
          .build();
    } catch (final DataAccessException e) {
      handleDataIntegrityIssues(command, e.getMostSpecificCause(), e);
      return CommandProcessingResult.empty();
    } catch (final PersistenceException dve) {
      Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
      handleDataIntegrityIssues(command, throwable, dve);
      return CommandProcessingResult.empty();
    }
  }
  public Map<String, Object> update(final JsonCommand command) {

    final Map<String, Object> actualChanges = new LinkedHashMap<>(3);

    if (command.isChangeInStringParameterNamed(PaymentTypeApiResourceConstants.NAME, this.name)) {
      final String newValue =
          command.stringValueOfParameterNamed(PaymentTypeApiResourceConstants.NAME);
      actualChanges.put(PaymentTypeApiResourceConstants.NAME, newValue);
      this.name = StringUtils.defaultIfEmpty(newValue, null);
    }

    if (command.isChangeInStringParameterNamed(
        PaymentTypeApiResourceConstants.DESCRIPTION, this.description)) {
      final String newDescription =
          command.stringValueOfParameterNamed(PaymentTypeApiResourceConstants.DESCRIPTION);
      actualChanges.put(PaymentTypeApiResourceConstants.DESCRIPTION, newDescription);
      this.description = StringUtils.defaultIfEmpty(newDescription, null);
    }

    if (command.isChangeInBooleanParameterNamed(
        PaymentTypeApiResourceConstants.ISCASHPAYMENT, this.isCashPayment)) {
      final Boolean newCashPaymentType =
          command.booleanObjectValueOfParameterNamed(PaymentTypeApiResourceConstants.ISCASHPAYMENT);
      actualChanges.put(PaymentTypeApiResourceConstants.ISCASHPAYMENT, newCashPaymentType);
      this.isCashPayment = newCashPaymentType.booleanValue();
    }

    if (command.isChangeInLongParameterNamed(
        PaymentTypeApiResourceConstants.POSITION, this.position)) {
      final Long newPosition =
          command.longValueOfParameterNamed(PaymentTypeApiResourceConstants.POSITION);
      actualChanges.put(PaymentTypeApiResourceConstants.POSITION, newPosition);
      this.position = newPosition;
    }

    return actualChanges;
  }
 @Transactional
 @Override
 public CommandProcessingResult processCommand(final JsonCommand command) {
   return this.groupWritePlatformService.assignGroupOrCenterStaff(command.entityId(), command);
 }
  @Transactional
  @Override
  public Long handleRDAccountPreMatureClosure(
      final RecurringDepositAccount account,
      final PaymentDetail paymentDetail,
      final AppUser user,
      final JsonCommand command,
      final LocalDate tenantsTodayDate,
      final Map<String, Object> changes) {

    final boolean isSavingsInterestPostingAtCurrentPeriodEnd =
        this.configurationDomainService.isSavingsInterestPostingAtCurrentPeriodEnd();
    final Integer financialYearBeginningMonth =
        this.configurationDomainService.retrieveFinancialYearBeginningMonth();

    boolean isAccountTransfer = false;
    final boolean isPreMatureClosure = true;
    boolean isRegularTransaction = false;
    final Set<Long> existingTransactionIds = new HashSet<>();
    final Set<Long> existingReversedTransactionIds = new HashSet<>();
    updateExistingTransactionsDetails(
        account, existingTransactionIds, existingReversedTransactionIds);

    final LocalDate closedDate =
        command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName);
    final Locale locale = command.extractLocale();
    final DateTimeFormatter fmt =
        DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
    Long savingsTransactionId = null;
    // post interest
    account.postPreMaturityInterest(
        closedDate,
        isPreMatureClosure,
        isSavingsInterestPostingAtCurrentPeriodEnd,
        financialYearBeginningMonth);

    final Integer closureTypeValue =
        command.integerValueOfParameterNamed(DepositsApiConstants.onAccountClosureIdParamName);
    DepositAccountOnClosureType closureType = DepositAccountOnClosureType.fromInt(closureTypeValue);

    if (closureType.isTransferToSavings()) {
      final boolean isExceptionForBalanceCheck = false;
      final Long toSavingsId = command.longValueOfParameterNamed(toSavingsAccountIdParamName);
      final String transferDescription =
          command.stringValueOfParameterNamed(transferDescriptionParamName);
      final SavingsAccount toSavingsAccount =
          this.depositAccountAssembler.assembleFrom(
              toSavingsId, DepositAccountType.SAVINGS_DEPOSIT);
      final AccountTransferDTO accountTransferDTO =
          new AccountTransferDTO(
              closedDate,
              account.getAccountBalance(),
              PortfolioAccountType.SAVINGS,
              PortfolioAccountType.SAVINGS,
              null,
              null,
              transferDescription,
              locale,
              fmt,
              null,
              null,
              null,
              null,
              null,
              AccountTransferType.ACCOUNT_TRANSFER.getValue(),
              null,
              null,
              null,
              null,
              toSavingsAccount,
              account,
              isRegularTransaction,
              isExceptionForBalanceCheck);
      this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
    } else {
      final SavingsAccountTransaction withdrawal =
          this.handleWithdrawal(
              account,
              fmt,
              closedDate,
              account.getAccountBalance(),
              paymentDetail,
              false,
              isRegularTransaction);
      savingsTransactionId = withdrawal.getId();
    }

    /** * Update account transactionIds for post journal entries. */
    updateExistingTransactionsDetails(
        account, existingTransactionIds, existingReversedTransactionIds);
    account.prematureClosure(user, command, tenantsTodayDate, changes);
    this.savingsAccountRepository.save(account);
    postJournalEntries(
        account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
    return savingsTransactionId;
  }
  @Transactional
  @Override
  public Long handleRDAccountClosure(
      final RecurringDepositAccount account,
      final PaymentDetail paymentDetail,
      final AppUser user,
      final JsonCommand command,
      final LocalDate tenantsTodayDate,
      final Map<String, Object> changes) {

    final boolean isSavingsInterestPostingAtCurrentPeriodEnd =
        this.configurationDomainService.isSavingsInterestPostingAtCurrentPeriodEnd();
    final Integer financialYearBeginningMonth =
        this.configurationDomainService.retrieveFinancialYearBeginningMonth();

    boolean isRegularTransaction = false;
    boolean isAccountTransfer = false;
    final boolean isPreMatureClosure = false;
    final Set<Long> existingTransactionIds = new HashSet<>();
    final Set<Long> existingReversedTransactionIds = new HashSet<>();
    updateExistingTransactionsDetails(
        account, existingTransactionIds, existingReversedTransactionIds);

    final MathContext mc = MathContext.DECIMAL64;
    final Locale locale = command.extractLocale();
    final DateTimeFormatter fmt =
        DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
    final LocalDate closedDate =
        command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName);
    Long savingsTransactionId = null;
    account.postMaturityInterest(
        isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, closedDate);
    final BigDecimal transactionAmount = account.getAccountBalance();
    final Integer onAccountClosureId =
        command.integerValueOfParameterNamed(onAccountClosureIdParamName);
    final DepositAccountOnClosureType onClosureType =
        DepositAccountOnClosureType.fromInt(onAccountClosureId);
    if (onClosureType.isReinvest()) {
      RecurringDepositAccount reinvestedDeposit = account.reInvest(transactionAmount);
      depositAccountAssembler.assignSavingAccountHelpers(reinvestedDeposit);
      reinvestedDeposit.updateMaturityDateAndAmount(
          mc,
          isPreMatureClosure,
          isSavingsInterestPostingAtCurrentPeriodEnd,
          financialYearBeginningMonth);
      reinvestedDeposit.processAccountUponActivation(fmt, user);
      reinvestedDeposit.updateMaturityDateAndAmount(
          mc,
          isPreMatureClosure,
          isSavingsInterestPostingAtCurrentPeriodEnd,
          financialYearBeginningMonth);
      this.savingsAccountRepository.save(reinvestedDeposit);

      Money amountForDeposit = reinvestedDeposit.activateWithBalance();
      if (amountForDeposit.isGreaterThanZero()) {
        handleRDDeposit(
            reinvestedDeposit,
            fmt,
            reinvestedDeposit.getActivationLocalDate(),
            amountForDeposit.getAmount(),
            paymentDetail,
            isRegularTransaction);
      }
      reinvestedDeposit.updateMaturityDateAndAmount(
          mc,
          isPreMatureClosure,
          isSavingsInterestPostingAtCurrentPeriodEnd,
          financialYearBeginningMonth);
      this.savingsAccountRepository.save(reinvestedDeposit);
      autoGenerateAccountNumber(reinvestedDeposit);

      final SavingsAccountTransaction withdrawal =
          this.handleWithdrawal(
              account,
              fmt,
              closedDate,
              account.getAccountBalance(),
              paymentDetail,
              false,
              isRegularTransaction);
      savingsTransactionId = withdrawal.getId();

    } else if (onClosureType.isTransferToSavings()) {
      final Long toSavingsId = command.longValueOfParameterNamed(toSavingsAccountIdParamName);
      final String transferDescription =
          command.stringValueOfParameterNamed(transferDescriptionParamName);
      final SavingsAccount toSavingsAccount =
          this.depositAccountAssembler.assembleFrom(
              toSavingsId, DepositAccountType.SAVINGS_DEPOSIT);
      final boolean isExceptionForBalanceCheck = false;
      final AccountTransferDTO accountTransferDTO =
          new AccountTransferDTO(
              closedDate,
              transactionAmount,
              PortfolioAccountType.SAVINGS,
              PortfolioAccountType.SAVINGS,
              null,
              null,
              transferDescription,
              locale,
              fmt,
              null,
              null,
              null,
              null,
              null,
              AccountTransferType.ACCOUNT_TRANSFER.getValue(),
              null,
              null,
              null,
              null,
              toSavingsAccount,
              account,
              isRegularTransaction,
              isExceptionForBalanceCheck);
      this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
    } else {
      final SavingsAccountTransaction withdrawal =
          this.handleWithdrawal(
              account,
              fmt,
              closedDate,
              account.getAccountBalance(),
              paymentDetail,
              false,
              isRegularTransaction);
      savingsTransactionId = withdrawal.getId();
    }

    /** * Update account transactionIds for post journal entries. */
    updateExistingTransactionsDetails(
        account, existingTransactionIds, existingReversedTransactionIds);
    account.close(user, command, tenantsTodayDate, changes);

    this.savingsAccountRepository.save(account);

    postJournalEntries(
        account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);

    return savingsTransactionId;
  }
  @Transactional
  @Override
  public CommandProcessingResult update(final Long productId, final JsonCommand command) {

    try {
      this.context.authenticatedUser();
      final SavingsProduct product = this.savingProductRepository.findOne(productId);
      if (product == null) {
        throw new SavingsProductNotFoundException(productId);
      }

      this.fromApiJsonDataValidator.validateForUpdate(command.json(), product);

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

      if (changes.containsKey(chargesParamName)) {
        final Set<Charge> savingsProductCharges =
            this.savingsProductAssembler.assembleListOfSavingsProductCharges(
                command, product.currency().getCode());
        final boolean updated = product.update(savingsProductCharges);
        if (!updated) {
          changes.remove(chargesParamName);
        }
      }

      if (changes.containsKey(taxGroupIdParamName)) {
        final TaxGroup taxGroup = this.savingsProductAssembler.assembleTaxGroup(command);
        product.setTaxGroup(taxGroup);
        if (product.withHoldTax() && product.getTaxGroup() == null) {
          final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
          final DataValidatorBuilder baseDataValidator =
              new DataValidatorBuilder(dataValidationErrors)
                  .resource(SAVINGS_PRODUCT_RESOURCE_NAME);
          final Long taxGroupId = null;
          baseDataValidator.reset().parameter(taxGroupIdParamName).value(taxGroupId).notBlank();
          throw new PlatformApiDataValidationException(dataValidationErrors);
        }
      }

      // accounting related changes
      final boolean accountingTypeChanged = changes.containsKey(accountingRuleParamName);
      final Map<String, Object> accountingMappingChanges =
          this.accountMappingWritePlatformService.updateSavingsProductToGLAccountMapping(
              product.getId(),
              command,
              accountingTypeChanged,
              product.getAccountingType(),
              DepositAccountType.SAVINGS_DEPOSIT);
      changes.putAll(accountingMappingChanges);

      if (!changes.isEmpty()) {
        this.savingProductRepository.saveAndFlush(product);
      }

      return new CommandProcessingResultBuilder() //
          .withEntityId(product.getId()) //
          .with(changes)
          .build();
    } catch (final DataAccessException e) {
      handleDataIntegrityIssues(command, e.getMostSpecificCause(), e);
      return CommandProcessingResult.empty();
    } catch (final PersistenceException dve) {
      Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
      handleDataIntegrityIssues(command, throwable, dve);
      return CommandProcessingResult.empty();
    }
  }
 @Transactional
 @Override
 public CommandProcessingResult processCommand(JsonCommand jsonCommand) {
   return this.shareProductWritePlatformService.updateProduct(jsonCommand.entityId(), jsonCommand);
 }
  @Transactional
  @Override
  public CommandProcessingResult processCommand(final JsonCommand command) {

    return this.clientWritePlatformService.closeClient(command.entityId(), command);
  }