@Override
  public erp.lib.form.SFormValidation formValidate() {
    SFormValidation validation = new SFormValidation();

    for (int i = 0; i < mvFields.size(); i++) {
      if (!((erp.lib.form.SFormField) mvFields.get(i)).validateField()) {
        validation.setIsError(true);
        validation.setComponent(mvFields.get(i).getComponent());
        break;
      }
    }

    if (moExchangeRate == null && !validation.getIsError()) {
      if (moFieldPkCurrencyId.getKeyAsIntArray()[0]
          == miClient.getSessionXXX().getParamsErp().getFkCurrencyId()) {
        validation.setMessage(
            "La moneda del tipo de cambio no puede ser la moneda local del sistema.");
        validation.setComponent(jcbPkCurrencyId);
      } else {
        if (SDataUtilities.callProcedureVal(
                miClient,
                SProcConstants.FIN_EXC_RATE_VAL,
                new Object[] {moFieldPkCurrencyId.getKeyAsIntArray()[0], moFieldPkDateId.getDate()},
                SLibConstants.EXEC_MODE_VERBOSE)
            > 0) {
          validation.setMessage("Ya existe un registro para la moneda y fecha especificadas.");
          validation.setComponent(jftPkDateId);
        }
      }
    }

    return validation;
  }
  public void focusLostYear() {
    int[] date = null;

    if (jckShowPayDays.isSelected()) {
      date = SLibTimeUtils.digestDate(miClient.getSession().getCurrentDate());
      moFieldDateRef.setFieldValue(
          SLibTimeUtils.createDate(moFieldYear.getInteger(), date[1], date[2]));
    }
  }
  public void initForm() {
    mbFirstTime = true;

    moFieldYear.setFieldValue(miClient.getSessionXXX().getWorkingYear());
    jckShowPayDays.setSelected(false);
    itemStateChangedShowPayDays(); // resets reference date

    if (mnBizPartnerId == SLibConsts.UNDEFINED) {
      moFieldBizPartner.resetField();
    } else {
      SFormUtilities.locateComboBoxItem(jcbBizPartner, new int[] {mnBizPartnerId});
    }
  }
  private void initComponentsExtra() {
    mvFields = new Vector<SFormField>();

    moFieldPkCurrencyId =
        new SFormField(
            miClient, SLibConstants.DATA_TYPE_KEY, true, jcbPkCurrencyId, jlPkCurrencyId);
    moFieldPkCurrencyId.setPickerButton(jbPkCurrencyId);
    moFieldPkDateId =
        new SFormField(miClient, SLibConstants.DATA_TYPE_DATE, true, jftPkDateId, jlPkDateId);
    moFieldPkDateId.setPickerButton(jbPkDateId);
    moFieldExchangeRate =
        new SFormField(
            miClient, SLibConstants.DATA_TYPE_DOUBLE, true, jtfExchangeRate, jlExchangeRate);
    moFieldExchangeRate.setDecimalFormat(
        miClient.getSessionXXX().getFormatters().getDecimalsExchangeRateFormat());
    moFieldIsDeleted =
        new SFormField(miClient, SLibConstants.DATA_TYPE_BOOLEAN, true, jckIsDeleted);

    mvFields.add(moFieldPkCurrencyId);
    mvFields.add(moFieldPkDateId);
    mvFields.add(moFieldExchangeRate);
    mvFields.add(moFieldIsDeleted);

    jbOk.addActionListener(this);
    jbCancel.addActionListener(this);
    jbPkCurrencyId.addActionListener(this);
    jbPkDateId.addActionListener(this);

    AbstractAction actionOk =
        new AbstractAction() {
          @Override
          public void actionPerformed(ActionEvent e) {
            actionOk();
          }
        };

    SFormUtilities.putActionMap(
        getRootPane(), actionOk, "ok", KeyEvent.VK_ENTER, KeyEvent.CTRL_DOWN_MASK);

    AbstractAction actionCancel =
        new AbstractAction() {
          @Override
          public void actionPerformed(ActionEvent e) {
            actionCancel();
          }
        };

    SFormUtilities.putActionMap(getRootPane(), actionCancel, "cancel", KeyEvent.VK_ESCAPE, 0);
  }
  @Override
  public erp.lib.data.SDataRegistry getRegistry() {
    if (moExchangeRate == null) {
      moExchangeRate = new SDataExchangeRate();
      moExchangeRate.setPkCurrencyId(moFieldPkCurrencyId.getKeyAsIntArray()[0]);
      moExchangeRate.setPkDateId(moFieldPkDateId.getDate());
      moExchangeRate.setFkUserNewId(miClient.getSession().getUser().getPkUserId());
    } else {
      moExchangeRate.setFkUserEditId(miClient.getSession().getUser().getPkUserId());
    }

    moExchangeRate.setExchangeRate(moFieldExchangeRate.getDouble());
    moExchangeRate.setIsDeleted(moFieldIsDeleted.getBoolean());

    return moExchangeRate;
  }
  @Override
  public void setRegistry(erp.lib.data.SDataRegistry registry) {
    moExchangeRate = (SDataExchangeRate) registry;

    moFieldPkCurrencyId.setFieldValue(new int[] {moExchangeRate.getPkCurrencyId()});
    moFieldPkDateId.setFieldValue(moExchangeRate.getPkDateId());
    moFieldExchangeRate.setFieldValue(moExchangeRate.getExchangeRate());
    moFieldIsDeleted.setFieldValue(moExchangeRate.getIsDeleted());

    jcbPkCurrencyId.setEnabled(false);
    jbPkCurrencyId.setEnabled(false);

    jftPkDateId.setEnabled(false);
    jbPkDateId.setEnabled(false);
    jckIsDeleted.setEnabled(true);
  }
  private void itemStateChangedShowPayDays() {
    int[] date = null;

    if (jckShowPayDays.isSelected()) {
      jftDateRef.setEnabled(true);
      jbPickDateRef.setEnabled(true);

      date = SLibTimeUtils.digestDate(miClient.getSession().getCurrentDate());
      moFieldDateRef.setFieldValue(
          SLibTimeUtils.createDate(moFieldYear.getInteger(), date[1], date[2]));
    } else {
      jftDateRef.setEnabled(false);
      jbPickDateRef.setEnabled(false);

      moFieldDateRef.resetField();
    }
  }
  public void actionPrint() {
    boolean error = false;
    JComponent component = null;

    for (SFormField field : mvFields) {
      if (!field.validateField()) {
        error = true;
        component = field.getComponent();
      }
    }

    if (error) {
      if (component != null) {
        component.requestFocus();
      }
    } else {
      print();
    }
  }
  private void initComponentsCustom() {
    mnBizPartnerId = 0;
    msBizPartnerCatSng =
        SBpsUtils.getBizPartnerCategoryName(mnBizPartnerCategoryId, SUtilConsts.NUM_SNG);
    msBizPartnerCatPlr =
        SBpsUtils.getBizPartnerCategoryName(mnBizPartnerCategoryId, SUtilConsts.NUM_PLR);
    jlBizPartner.setText(msBizPartnerCatSng + ": *");
    jbPickBizPartner.setToolTipText(
        SUtilConsts.TXT_SELECT + " " + msBizPartnerCatSng.toLowerCase());
    setTitle("Movimientos contables de " + msBizPartnerCatPlr.toLowerCase() + " por documento");

    switch (mnBizPartnerCategoryId) {
      case SDataConstantsSys.BPSS_CT_BP_SUP:
        manSysMoveTypeKey = SDataConstantsSys.FINS_TP_SYS_MOV_BPS_SUP;
        SFormUtilities.populateComboBox(
            miClient, jcbBizPartner, mnOptionPickerId = SDataConstants.BPSX_BP_SUP);
        break;
      case SDataConstantsSys.BPSS_CT_BP_CUS:
        manSysMoveTypeKey = SDataConstantsSys.FINS_TP_SYS_MOV_BPS_CUS;
        SFormUtilities.populateComboBox(
            miClient, jcbBizPartner, mnOptionPickerId = SDataConstants.BPSX_BP_CUS);
        break;
      default:
        miClient.showMsgBoxWarning(SLibConstants.MSG_ERR_UTIL_UNKNOWN_OPTION);
    }

    moFieldYear = new SFormField(miClient, SLibConstants.DATA_TYPE_INTEGER, true, jtfYear, jlYear);
    moFieldYear.setIntegerMin(2000);
    moFieldYear.setIntegerMax(2100);
    moFieldYear.setMinInclusive(true);
    moFieldYear.setMaxInclusive(true);
    moFieldYear.setDecimalFormat(miClient.getSessionXXX().getFormatters().getYearFormat());
    moFieldBizPartner =
        new SFormField(miClient, SLibConstants.DATA_TYPE_KEY, true, jcbBizPartner, jlBizPartner);
    moFieldBizPartner.setPickerButton(jbPickBizPartner);
    moFieldDateRef =
        new SFormField(miClient, SLibConstants.DATA_TYPE_DATE, true, jftDateRef, jlDateRef);
    moFieldDateRef.setPickerButton(jbPickDateRef);

    mvFields = new Vector<SFormField>();
    mvFields.add(moFieldYear);
    mvFields.add(moFieldBizPartner);
    mvFields.add(moFieldDateRef);

    jbPickBizPartner.addActionListener(this);
    jbPickDateRef.addActionListener(this);
    jbPrint.addActionListener(this);
    jbClose.addActionListener(this);
    jckShowPayDays.addItemListener(this);
    jtfYear.addFocusListener(this);
    jftDateRef.addFocusListener(this);

    SFormUtilities.createActionMap(
        rootPane, this, "actionPrint", "print", KeyEvent.VK_ENTER, KeyEvent.CTRL_DOWN_MASK);
    SFormUtilities.createActionMap(rootPane, this, "actionClose", "close", KeyEvent.VK_ESCAPE, 0);
  }
  @Override
  public void formReset() {
    mnFormResult = SLibConstants.UNDEFINED;
    mnFormStatus = SLibConstants.UNDEFINED;
    mbFirstTime = true;

    moExchangeRate = null;

    for (int i = 0; i < mvFields.size(); i++) {
      mvFields.get(i).resetField();
    }

    moFieldPkDateId.setFieldValue(miClient.getSessionXXX().getWorkingDate());

    jcbPkCurrencyId.setEnabled(true);
    jbPkCurrencyId.setEnabled(true);
    jftPkDateId.setEnabled(true);
    jbPkDateId.setEnabled(true);

    jckIsDeleted.setEnabled(false);
  }
 private void actionPkDateId() {
   miClient.getGuiDatePickerXXX().pickDate(moFieldPkDateId.getDate(), moFieldPkDateId);
 }
 private void actionPickDate() {
   miClient.getGuiDatePickerXXX().pickDate(moFieldDateRef.getDate(), moFieldDateRef);
 }
 public void focusLostDate() {
   moFieldYear.setFieldValue(SLibTimeUtilities.digestYear(moFieldDateRef.getDate())[0]);
 }
  private void print() {
    int year = moFieldYear.getInteger();
    Cursor cursor = getCursor();
    Map<String, Object> map = null;
    JasperPrint jasperPrint = null;
    JasperViewer jasperViewer = null;
    SDataBizPartner bizPartner = null;
    SDataBizPartnerCategory bizPartnerCategory = null;

    try {
      setCursor(new Cursor(Cursor.WAIT_CURSOR));

      bizPartner =
          (SDataBizPartner)
              SDataUtilities.readRegistry(
                  miClient,
                  SDataConstants.BPSU_BP,
                  moFieldBizPartner.getKeyAsIntArray(),
                  SLibConstants.EXEC_MODE_VERBOSE);

      map = miClient.createReportParams();
      map.put("nSysMoveCatId", manSysMoveTypeKey[0]);
      map.put("nSysMoveTypeId", manSysMoveTypeKey[1]);
      map.put("sBizPartnerCat", msBizPartnerCatSng.toUpperCase());
      map.put("sBizPartnerCatPlural", msBizPartnerCatPlr.toUpperCase());
      map.put(
          "nLocalCurrencyId",
          miClient.getSessionXXX().getParamsErp().getDbmsDataCurrency().getPkCurrencyId());
      map.put(
          "sLocalCurrency",
          miClient.getSessionXXX().getParamsErp().getDbmsDataCurrency().getCurrency());
      map.put("nYear", year);
      map.put(
          "tDate",
          jckShowPayDays.isSelected()
              ? moFieldDateRef.getDate()
              : SLibTimeUtilities.createDate(year, 12, 31));
      map.put("nBizPartnerId", bizPartner.getPkBizPartnerId());
      map.put("sBizPartner", bizPartner.getBizPartner());

      switch (mnBizPartnerCategoryId) {
        case SDataConstantsSys.BPSS_CT_BP_SUP:
          bizPartnerCategory = bizPartner.getDbmsCategorySettingsSup();
          break;
        case SDataConstantsSys.BPSS_CT_BP_CUS:
          bizPartnerCategory = bizPartner.getDbmsCategorySettingsCus();
          break;
        default:
      }

      map.put("dCreditLimit", bizPartnerCategory.getEffectiveCreditLimit());
      map.put("nDaysCredit", bizPartnerCategory.getEffectiveDaysOfCredit());
      map.put("nDaysGrace", bizPartnerCategory.getEffectiveDaysOfGrace());
      map.put(
          "sCreditType",
          SDataReadDescriptions.getCatalogueDescription(
              miClient,
              SDataConstants.BPSS_TP_CRED,
              new int[] {bizPartnerCategory.getEffectiveCreditTypeId()}));

      jasperPrint =
          SDataUtilities.fillReport(
              miClient,
              jckShowPayDays.isSelected()
                  ? SDataConstantsSys.REP_FIN_BPS_ACC_MOV_DAY
                  : SDataConstantsSys.REP_FIN_BPS_ACC_MOV,
              map);
      jasperViewer = new JasperViewer(jasperPrint, false);
      jasperViewer.setTitle(getTitle());
      jasperViewer.setVisible(true);
    } catch (Exception e) {
      SLibUtilities.renderException(this, e);
    } finally {
      setCursor(cursor);
    }
  }