diff --git a/pom.xml b/pom.xml
index 3e0aa151c..bc62f167c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,12 +4,12 @@
4.0.0
br.com.rjconsultores
ventaboletosadm
- 1.39.3
+ 1.40.0
war
1.29.0
- 1.23.3
+ 1.24.0
UTF-8
UTF-8
diff --git a/src/java/com/rjconsultores/ventaboletos/relatorios/impl/RelatorioDesempenhoPorLinha.java b/src/java/com/rjconsultores/ventaboletos/relatorios/impl/RelatorioDesempenhoPorLinha.java
new file mode 100644
index 000000000..5cd66c00b
--- /dev/null
+++ b/src/java/com/rjconsultores/ventaboletos/relatorios/impl/RelatorioDesempenhoPorLinha.java
@@ -0,0 +1,242 @@
+package com.rjconsultores.ventaboletos.relatorios.impl;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.log4j.Logger;
+
+import com.rjconsultores.ventaboletos.relatorios.utilitarios.ArrayDataSource;
+import com.rjconsultores.ventaboletos.relatorios.utilitarios.Relatorio;
+import com.rjconsultores.ventaboletos.utilerias.DateUtil;
+import com.rjconsultores.ventaboletos.utilerias.MoneyHelper;
+import com.rjconsultores.ventaboletos.vo.parada.ParadaVO;
+import com.rjconsultores.ventaboletos.vo.ruta.RutaVO;
+import com.rjconsultores.ventaboletos.web.utilerias.NamedParameterStatement;
+
+public class RelatorioDesempenhoPorLinha extends Relatorio {
+
+ private static Logger log = Logger.getLogger(RelatorioDesempenhoPorLinha.class);
+
+ public RelatorioDesempenhoPorLinha(Map parametros, Connection conexao) throws Exception {
+ super(parametros, conexao);
+
+ this.setCustomDataSource(new ArrayDataSource(this) {
+ @Override
+ public void initDados() throws Exception {
+
+ Connection conexao = this.relatorio.getConexao();
+ Map parametros = this.relatorio.getParametros();
+ @SuppressWarnings("unchecked")
+ Map> mapRutaTrecho = (Map>) parametros.get("MAPRUTATRECHO");
+
+ if (parametros.get("TRECHOS") != null) {
+ for (Entry> entry : mapRutaTrecho.entrySet()) {
+ String sqlCombinacoes = gerarCombinacaoTrechos(parametros);
+ StringBuilder sql = getSQL(parametros, sqlCombinacoes, entry.getKey());
+ NamedParameterStatement stmt = new NamedParameterStatement(conexao, sql.toString());
+ setarParametrosDaConsulta(parametros, stmt);
+ ResultSet rset2 = stmt.executeQuery();
+ setarResult(rset2);
+ }
+ } else {
+ StringBuilder sql = getSQL(parametros, null, null);
+ NamedParameterStatement stmt = new NamedParameterStatement(conexao, sql.toString());
+ setarParametrosDaConsulta(parametros, stmt);
+ ResultSet rset2 = stmt.executeQuery();
+ setarResult(rset2);
+ }
+ }
+
+ private void setarParametrosDaConsulta(Map parametros, NamedParameterStatement stmt)
+ throws SQLException {
+ stmt.setInt("EMPRESA_ID", Integer.valueOf(parametros.get("EMPRESA_ID").toString()));
+
+ stmt.setTimestamp("DATA_INICIAL",
+ new Timestamp(DateUtil.inicioFecha((Date) parametros.get("DATA_INICIAL")).getTime()));
+ stmt.setTimestamp("DATA_FINAL",
+ new Timestamp(DateUtil.fimFecha((Date) parametros.get("DATA_FINAL")).getTime()));
+ }
+
+ private void setarResult(ResultSet rset2) throws SQLException {
+ while (rset2.next()) {
+ Map dataResult = new HashMap();
+
+ dataResult.put("DATA", rset2.getString("data"));
+ dataResult.put("PREFIXO", rset2.getString("prefixo"));
+ dataResult.put("ITINERARIO", rset2.getString("itinerario"));
+ dataResult.put("HORA", rset2.getString("hora"));
+ dataResult.put("TARIFASARRECADA", rset2.getBigDecimal("tarifasArrecada"));
+ dataResult.put("QTDPASSAGENS", rset2.getInt("qtdPassagens"));
+ dataResult.put("QTDVIAGENS", 1);
+ dataResult.put("EXTENSAO", rset2.getInt("extensao"));
+ dataResult.put("TOTALKM", rset2.getInt("extensao"));
+ dataResult.put("MEDIAKM", MoneyHelper.arredondar(rset2.getBigDecimal("mediaKm")));
+
+ this.dados.add(dataResult);
+ }
+ }
+
+ private StringBuilder getSQL(Map parametros, String sqlCombinacoes, Integer rutaId) {
+
+ StringBuilder sql = new StringBuilder();
+
+ sql.append(" SELECT ");
+ sql.append(" c.corrida_id, ");
+ sql.append(" to_char(c.fechorsalida,'DD/MM/YYYY') as data, ");
+ sql.append(" to_char(c.fechorsalida, 'HH24:MI') AS hora, ");
+ sql.append(" r.prefixo prefixo, ");
+ sql.append(" r.descruta itinerario, ");
+ sql.append(" coalesce(SUM(cj.preciopagado),0) tarifasArrecada, ");
+ sql.append(" COUNT(cj.boleto_id) qtdPassagens, ");
+ sql.append(" tr.cantkmreal extensao, ");
+ sql.append(" coalesce(SUM(cj.preciopagado),0) / coalesce(tr.cantkmreal,0) as mediaKm ");
+ sql.append(" FROM ");
+ sql.append(" corrida c ");
+ sql.append(" INNER JOIN ruta r ON r.ruta_id = c.ruta_id ");
+ sql.append(" INNER JOIN parada origem ON ( c.origen_id = origem.parada_id ) ");
+ sql.append(" INNER JOIN parada destino ON ( c.destino_id = destino.parada_id ) ");
+ sql.append(" INNER JOIN ruta_combinacion rc ON ( rc.ruta_id = c.ruta_id ");
+ sql.append(" AND rc.activo = 1 ) ");
+ sql.append(" INNER JOIN tramo tr ON ( tr.tramo_id = rc.tramo_id ");
+ sql.append(" AND tr.origen_id = c.origen_id ");
+ sql.append(" AND tr.destino_id = c.destino_id ) ");
+ sql.append(" inner join MARCA m ");
+ sql.append(" on m.marca_id = c.marca_id ");
+ sql.append(" and m.activo = 1 ");
+ sql.append(" LEFT JOIN ( ");
+ sql.append(" SELECT ");
+ sql.append(" co.corrida_id corrida_id, ");
+ sql.append(" co.feccorrida feccorrida, ");
+ sql.append(" bo.boleto_id, ");
+ sql.append(" bo.preciopagado ");
+ sql.append(" FROM ");
+ sql.append(" corrida co ");
+ sql.append(" INNER JOIN boleto bo ON co.corrida_id = bo.corrida_id ");
+ sql.append(" AND co.feccorrida = bo.feccorrida ");
+ sql.append(" AND bo.activo = 1 ");
+ sql.append(" INNER JOIN ruta_combinacion rc ON rc.ruta_id = co.ruta_id ");
+ sql.append(" INNER JOIN tramo t ON rc.tramo_id = t.tramo_id ");
+ sql.append(" AND t.origen_id = bo.origen_id ");
+ sql.append(" AND t.destino_id = bo.destino_id ");
+ sql.append(" INNER JOIN ruta r ON r.ruta_id = co.ruta_id ");
+ sql.append(" INNER JOIN ruta_combinacion rc2 ON ( rc2.ruta_id = r.ruta_id ");
+ sql.append(" AND rc2.activo = 1 ) ");
+ sql.append(" INNER JOIN tramo tr ON ( tr.tramo_id = rc2.tramo_id ");
+ sql.append(" AND tr.origen_id = co.origen_id ");
+ sql.append(" AND tr.destino_id = co.destino_id ) ");
+ sql.append(" WHERE ");
+ sql.append(" co.activo NOT IN ( 0, 2 ) ");
+ sql.append(" AND rc.activo = 1 ");
+ sql.append(" AND t.activo = 1 ");
+ sql.append(" AND bo.indstatusboleto != 'S' ");
+ sql.append(" AND bo.motivocancelacion_id IS NULL ");
+// sql.append(" AND bo.categoria_id <> :crianca_id ");
+ sql.append(" and co.FECCORRIDA >= :DATA_INICIAL ");
+ sql.append(" and co.FECCORRIDA <= :DATA_FINAL ");
+ sql.append(" GROUP BY ");
+ sql.append(" co.corrida_id, ");
+ sql.append(" co.feccorrida, ");
+ sql.append(" bo.boleto_id, ");
+ sql.append(" bo.preciopagado ");
+ sql.append(" ) cj ON ( cj.corrida_id = c.corrida_id ");
+ sql.append(" AND cj.feccorrida = c.feccorrida ) ");
+ sql.append(" WHERE ");
+ sql.append(" m.EMPRESA_ID = :EMPRESA_ID ");
+ sql.append(" and c.FECCORRIDA >= :DATA_INICIAL ");
+ sql.append(" and c.FECCORRIDA <= :DATA_FINAL ");
+
+ if (parametros.get("LINHAS") != null && !possuiFiltroTodos("LINHAS")
+ && parametros.get("TRECHOS") != null) {
+ sql.append(" and c.ruta_id IN (" + rutaId + ")");
+ } else if (parametros.get("LINHAS") != null && !possuiFiltroTodos("LINHAS")) {
+ sql.append(" and c.ruta_id IN (" + parametros.get("LINHAS").toString() + ")");
+ }
+ if (sqlCombinacoes != null && !sqlCombinacoes.isEmpty()) {
+ sql.append(" " + sqlCombinacoes + " ");
+ }
+
+ sql.append(" GROUP BY ");
+ sql.append(" c.corrida_id, ");
+ sql.append(" c.fechorsalida, ");
+ sql.append(" to_char(c.fechorsalida, 'HH24:MI'), ");
+ sql.append(" r.descruta, ");
+ sql.append(" r.prefixo, ");
+ sql.append(" tr.cantkmreal ");
+ sql.append(" order by c.fechorsalida asc ");
+
+ return sql;
+ }
+
+ });
+ }
+
+ @Override
+ protected void processaParametros() throws Exception {
+
+ }
+
+ private String gerarCombinacaoTrechos(Map parametros) {
+
+ @SuppressWarnings("unchecked")
+ List trechos = (List) parametros.get("TRECHOS");
+
+ List listParada1 = new ArrayList<>();
+ List listParada2 = new ArrayList<>();
+ StringBuilder sql = new StringBuilder();
+
+ for (RutaVO tramoVO : trechos) {
+ listParada1.add(new ParadaVO(tramoVO.getOrigenId(), tramoVO.getRutaId().intValue()));
+ }
+
+ listParada2.addAll(listParada1);
+
+ if (trechos != null) {
+
+ LinkedList> lists = new LinkedList>();
+
+ lists.add(listParada1);
+ lists.add(listParada2);
+
+ Set combinacoes = new TreeSet();
+
+ sql.append("AND (");
+ for (ParadaVO s : lists.removeFirst())
+ combinacoes.add(s.getParadaId().toString());
+
+ while (!lists.isEmpty()) {
+ List next = lists.removeFirst();
+ Set novasCombinacoes = new TreeSet();
+ for (String s1 : combinacoes) {
+ for (ParadaVO s2 : next) {
+ novasCombinacoes.add(s1 + ";" + s2.getParadaId());
+ sql.append("(c.origen_id = ").append(s1).append(" AND c.destino_id = ").append(s2.getParadaId())
+ .append(" and c.ruta_id = " + s2.getRutaId() + " ) OR ");
+ }
+ }
+ combinacoes = novasCombinacoes;
+ }
+
+ // Remover o último " OR " da string
+ if (combinacoes.size() > 0) {
+ sql.delete(sql.length() - 4, sql.length());
+ }
+ sql.append(")");
+
+ }
+
+ return sql.toString();
+
+ }
+
+}
diff --git a/src/java/com/rjconsultores/ventaboletos/relatorios/internacionalizacao/RelatorioDesempenhoPorLinha_pt_BR.properties b/src/java/com/rjconsultores/ventaboletos/relatorios/internacionalizacao/RelatorioDesempenhoPorLinha_pt_BR.properties
new file mode 100644
index 000000000..f39ccac7e
--- /dev/null
+++ b/src/java/com/rjconsultores/ventaboletos/relatorios/internacionalizacao/RelatorioDesempenhoPorLinha_pt_BR.properties
@@ -0,0 +1,13 @@
+#geral
+msg.noData=Não foi possivel obter dados com os parâmetros informados.
+
+
+#Labels cabeçalho
+cabecalho.relatorio=Relatório:
+cabecalho.periodo=Período:
+cabecalho.periodoA=à
+cabecalho.dataHora=Data/Hora:
+cabecalho.impressorPor=Impressor por:
+cabecalho.pagina=Página
+cabecalho.de=de
+cabecalho.filtros=Filtros:
\ No newline at end of file
diff --git a/src/java/com/rjconsultores/ventaboletos/relatorios/templates/RelatorioDesempenhoPorLinha.jasper b/src/java/com/rjconsultores/ventaboletos/relatorios/templates/RelatorioDesempenhoPorLinha.jasper
new file mode 100644
index 000000000..17b8526b6
Binary files /dev/null and b/src/java/com/rjconsultores/ventaboletos/relatorios/templates/RelatorioDesempenhoPorLinha.jasper differ
diff --git a/src/java/com/rjconsultores/ventaboletos/relatorios/templates/RelatorioDesempenhoPorLinha.jrxml b/src/java/com/rjconsultores/ventaboletos/relatorios/templates/RelatorioDesempenhoPorLinha.jrxml
new file mode 100644
index 000000000..7a65dd2b8
--- /dev/null
+++ b/src/java/com/rjconsultores/ventaboletos/relatorios/templates/RelatorioDesempenhoPorLinha.jrxml
@@ -0,0 +1,343 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/java/com/rjconsultores/ventaboletos/web/gui/controladores/relatorios/RelatorioDesempenhoPorLinhaController.java b/src/java/com/rjconsultores/ventaboletos/web/gui/controladores/relatorios/RelatorioDesempenhoPorLinhaController.java
new file mode 100644
index 000000000..d18307ff3
--- /dev/null
+++ b/src/java/com/rjconsultores/ventaboletos/web/gui/controladores/relatorios/RelatorioDesempenhoPorLinhaController.java
@@ -0,0 +1,348 @@
+package com.rjconsultores.ventaboletos.web.gui.controladores.relatorios;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.sql.DataSource;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Controller;
+import org.zkoss.util.resource.Labels;
+import org.zkoss.zhtml.Messagebox;
+import org.zkoss.zk.ui.Component;
+import org.zkoss.zk.ui.event.Event;
+import org.zkoss.zk.ui.event.EventListener;
+import org.zkoss.zul.Button;
+import org.zkoss.zul.Comboitem;
+import org.zkoss.zul.Datebox;
+import org.zkoss.zul.Listcell;
+import org.zkoss.zul.Listitem;
+import org.zkoss.zul.ListitemRenderer;
+import org.zkoss.zul.Radiogroup;
+import org.zkoss.zul.Textbox;
+
+import com.rjconsultores.ventaboletos.entidad.Empresa;
+import com.rjconsultores.ventaboletos.entidad.OrgaoConcedente;
+import com.rjconsultores.ventaboletos.entidad.Ruta;
+import com.rjconsultores.ventaboletos.relatorios.impl.RelatorioDesempenhoPorLinha;
+import com.rjconsultores.ventaboletos.relatorios.utilitarios.Relatorio;
+import com.rjconsultores.ventaboletos.service.RutaService;
+import com.rjconsultores.ventaboletos.utilerias.UsuarioLogado;
+import com.rjconsultores.ventaboletos.vo.ruta.RutaVO;
+import com.rjconsultores.ventaboletos.web.utilerias.MyComboboxEstandar;
+import com.rjconsultores.ventaboletos.web.utilerias.MyGenericForwardComposer;
+import com.rjconsultores.ventaboletos.web.utilerias.MyListbox;
+import com.rjconsultores.ventaboletos.web.utilerias.render.RenderDesempenhoPorLinha;
+import com.rjconsultores.ventaboletos.web.utilerias.render.RenderDesempenhoPorLinhaTrecho;
+
+@Controller("relatorioDesempenhoPorLinhaController")
+@Scope("prototype")
+public class RelatorioDesempenhoPorLinhaController extends MyGenericForwardComposer {
+
+ private static final long serialVersionUID = 1L;
+ private static Logger log = Logger.getLogger(RelatorioDesempenhoPorLinhaController.class);
+
+ @Autowired
+ private DataSource dataSourceRead;
+
+ private Datebox datInicial;
+ private Datebox datFinal;
+ private MyComboboxEstandar cmbEmpresa;
+ private List lsEmpresa;
+ @Autowired
+ private RutaService rutaService;
+
+ private MyListbox linhaList;
+ private MyListbox trechoList;
+ private MyListbox linhaListSelList;
+ private Textbox txtPalavraPesquisaLinha;
+ private ArrayList lsNumLinha = new ArrayList();
+ private Radiogroup rgLayout;
+ private Map> mapRutaTrecho = new HashMap<>();
+
+ @Override
+ public void doAfterCompose(Component comp) throws Exception {
+ super.doAfterCompose(comp);
+
+ lsEmpresa = UsuarioLogado.getUsuarioLogado().getEmpresa();
+ linhaList.setItemRenderer(new RenderDesempenhoPorLinha());
+ renderizarListRuta();
+ trechoList.setItemRenderer(new RenderDesempenhoPorLinhaTrecho());
+
+ }
+
+ private void renderizarListRuta() {
+ linhaListSelList.setItemRenderer(new ListitemRenderer() {
+ @Override
+ public void render(Listitem lstm, Object o) throws Exception {
+
+ Ruta ruta = (Ruta) o;
+ if (ruta == null) {
+ return;
+ }
+
+ Listcell lc = new Listcell(ruta.getNumRuta() != null ? ruta.getNumRuta().toString() : "");
+ lc.setParent(lstm);
+ lc = new Listcell(ruta.getPrefixo());
+ lc.setParent(lstm);
+ lc = new Listcell(ruta.getDescruta());
+ lc.setParent(lstm);
+
+ OrgaoConcedente orgaoConcedente = ruta.getOrgaoConcedente();
+ if (orgaoConcedente != null) {
+ lc = new Listcell(orgaoConcedente.getDescOrgao());
+ } else {
+ lc = new Listcell("-");
+ }
+ lc.setParent(lstm);
+
+ Button btn = new Button();
+ lc = new Listcell();
+ lc.setParent(lstm);
+
+ btn.setWidth("16");
+ btn.setHeight("16");
+ btn.setImage("/gui/img/remove.png");
+
+ btn.addEventListener("onClick", new EventListener() {
+ @Override
+ public void onEvent(Event event) throws Exception {
+ MyListbox listBox = (MyListbox) event.getTarget().getParent().getParent().getParent();
+ Listitem listItem = (Listitem) event.getTarget().getParent().getParent();
+ listBox.removeItem((Ruta) listItem.getAttribute("data"));
+ List lsRutaVOAux = new ArrayList<>(trechoList.getListData());
+ Ruta ruta = (Ruta) listItem.getAttribute("data");
+ for (RutaVO rutaVO : (List) trechoList.getListData()) {
+ if (StringUtils.isNotBlank(ruta.getNumRuta()) && StringUtils.isNotBlank(rutaVO.getNumRuta())
+ && ruta.getNumRuta().equals(rutaVO.getNumRuta())) {
+ lsRutaVOAux.remove(rutaVO);
+ mapRutaTrecho.remove(rutaVO.getRutaId().intValue());
+ }
+ }
+ trechoList.setData(lsRutaVOAux);
+ }
+ });
+ lc.appendChild(btn);
+ lstm.setAttribute("data", ruta);
+ }
+ });
+ }
+
+ public void carregarTramos(Ruta rutaSelecionada) {
+
+ List lsRutaVO = rutaService.buscaRutaParadas(rutaSelecionada.getRutaId());
+ RutaVO ultimaRuta = lsRutaVO.get(lsRutaVO.size() - 1);
+ RutaVO novaRuta = new RutaVO(ultimaRuta.getRutaId(), ultimaRuta.getNumRuta(), ultimaRuta.getPrefixo(),
+ ultimaRuta.getDescruta(), ultimaRuta.getDescDestino(), ultimaRuta.getNumSecuencia(),
+ ultimaRuta.getDestinoId(), ultimaRuta.getDestinoId());
+ novaRuta.setDescOrigem(novaRuta.getDescParada());
+ lsRutaVO.add(novaRuta);
+
+ mapRutaTrecho.put(rutaSelecionada.getRutaId(), lsRutaVO);
+ List lsRutaVOAux = new ArrayList();
+ lsRutaVOAux.addAll(trechoList.getListData());
+ lsRutaVOAux.addAll(lsRutaVO);
+ trechoList.setData(lsRutaVOAux);
+
+ }
+
+ public void actualizarDados(List listaRutaVO) {
+
+ }
+
+ public List getLsEmpresa() {
+ return lsEmpresa;
+ }
+
+ public void setLsEmpresa(List lsEmpresa) {
+ this.lsEmpresa = lsEmpresa;
+ }
+
+ public void onDoubleClick$linhaList(Event ev) {
+ Ruta rutaAux = (Ruta) linhaList.getSelected();
+ if (rutaAux == null) {
+ return;
+ }
+ linhaListSelList.addItemNovo(rutaAux);
+
+ carregarTramos(rutaAux);
+ }
+
+ private void executarPesquisaLinha() {
+
+ String palavraPesquisaRuta = txtPalavraPesquisaLinha.getText();
+ linhaList.setData(rutaService.buscaRuta(palavraPesquisaRuta));
+
+ if (linhaList.getData().length == 0) {
+ try {
+ Messagebox.show(Labels.getLabel("MSG.ningunRegistro"),
+ Labels.getLabel("relatorioLinhasHorarioController.window.title"), Messagebox.OK,
+ Messagebox.INFORMATION);
+ } catch (InterruptedException ex) {
+ log.error(ex);
+ }
+ } else {
+ Collections.sort(linhaList.getListData(), new Comparator() {
+ @Override
+ public int compare(Ruta m1, Ruta m2) {
+ return m1.getDescruta().compareTo(m2.getDescruta());
+ }
+ });
+ }
+ }
+
+ public void onClick$btnPesquisaLinha(Event ev) {
+ executarPesquisaLinha();
+ }
+
+ public void onClick$btnLimparLinha(Event ev) {
+ linhaList.clearSelection();
+ lsNumLinha.clear();
+ }
+
+ public void onClick$btnExecutarRelatorio(Event ev) throws Exception {
+ executarRelatorio();
+ }
+
+ private void executarRelatorio() throws Exception {
+
+ if (rgLayout.getSelectedItem().getValue().equals("EMISSAO_LINHA")) {
+ executarRelatorioLinha();
+ } else {
+ executarRelatorioTrecho();
+ }
+ }
+
+ private void executarRelatorioLinha() throws Exception {
+
+ Map parametros = new HashMap();
+ StringBuilder filtro = new StringBuilder();
+
+ filtro.append("Linha: ");
+ String linhaIds = "";
+ String linhas = "";
+ List lslinhaSelecionados = new ArrayList(Arrays.asList(linhaListSelList.getData()));
+ if (lslinhaSelecionados.isEmpty()) {
+ linhas = "Todas";
+ } else {
+ for (int i = 0; i < lslinhaSelecionados.size(); i++) {
+ Ruta linha = lslinhaSelecionados.get(i);
+ linhas = linhas + linha.getDescruta() + ", ";
+
+ linhaIds = linhaIds + linha.getRutaId() + ", ";
+ }
+
+ // removendo ultima virgula
+ linhaIds = linhaIds.substring(0, linhaIds.length() - 2);
+ linhas = linhas.substring(0, linhas.length() - 2);
+ parametros.put("LINHAS", linhaIds);
+ }
+ filtro.append(linhas).append(";");
+
+ parametros.put("DATA_INICIAL", (java.util.Date) this.datInicial.getValue());
+ parametros.put("DATA_FINAL", (java.util.Date) this.datFinal.getValue());
+ parametros.put("NOME_RELATORIO", Labels.getLabel("relatorioDesempenhoPorLinhaController.window.title"));
+ parametros.put("USUARIO", UsuarioLogado.getUsuarioLogado().getNombusuario());
+
+ filtro.append(" Empresa: ");
+
+ Comboitem itemEmpresa = cmbEmpresa.getSelectedItem();
+ if (itemEmpresa != null) {
+ Empresa empresa = (Empresa) itemEmpresa.getValue();
+ parametros.put("EMPRESA_ID", empresa.getEmpresaId());
+ parametros.put("EMPRESA", empresa.getNombempresa());
+ filtro.append(empresa.getNombempresa() + ";");
+ } else {
+ filtro.append(" Todas;");
+ }
+
+ parametros.put("FILTROS", filtro.toString());
+ Relatorio relatorio = new RelatorioDesempenhoPorLinha(parametros, dataSourceRead.getConnection());
+
+ Map args = new HashMap();
+ args.put("relatorio", relatorio);
+
+ openWindow("/component/reportView.zul", Labels.getLabel("relatorioDesempenhoPorLinhaController.window.title"),
+ args, MODAL);
+ }
+
+ private void executarRelatorioTrecho() throws Exception {
+
+ Map parametros = new HashMap();
+ StringBuilder filtro = new StringBuilder();
+ List lista = new ArrayList<>();
+ Map> mapRutaTrechoAux = new HashMap<>();
+
+ for (Entry> entry : mapRutaTrecho.entrySet()) {
+ List listaAux = entry.getValue();
+ for (RutaVO rutaVO2 : (List) trechoList.getListData()) {
+ for (RutaVO rutaVO : listaAux) {
+ if (rutaVO.getRutaId().equals(rutaVO2.getRutaId())) {
+ lista.add(rutaVO2);
+ break;
+ }
+ }
+ }
+ mapRutaTrechoAux.put(entry.getKey(), lista);
+ lista = new ArrayList<>();
+ }
+
+ filtro.append("Linha: ");
+ String linhaIds = "";
+ String linhas = "";
+ List lslinhaSelecionados = new ArrayList(Arrays.asList(linhaListSelList.getData()));
+ if (lslinhaSelecionados.isEmpty()) {
+ linhas = "Todas";
+ } else {
+ for (int i = 0; i < lslinhaSelecionados.size(); i++) {
+ Ruta linha = lslinhaSelecionados.get(i);
+ linhas = linhas + linha.getDescruta() + ", ";
+
+ linhaIds = linhaIds + linha.getRutaId() + ", ";
+ }
+
+ // removendo ultima virgula
+ linhaIds = linhaIds.substring(0, linhaIds.length() - 2);
+ linhas = linhas.substring(0, linhas.length() - 2);
+ parametros.put("LINHAS", linhaIds);
+ }
+ filtro.append(linhas).append(";");
+
+ parametros.put("DATA_INICIAL", (java.util.Date) this.datInicial.getValue());
+ parametros.put("DATA_FINAL", (java.util.Date) this.datFinal.getValue());
+ parametros.put("NOME_RELATORIO", Labels.getLabel("relatorioDesempenhoPorLinhaController.window.title"));
+ parametros.put("USUARIO", UsuarioLogado.getUsuarioLogado().getNombusuario());
+ parametros.put("TRECHOS", trechoList.getListData());
+ parametros.put("MAPRUTATRECHO", mapRutaTrechoAux);
+
+ filtro.append(" Empresa: ");
+
+ Comboitem itemEmpresa = cmbEmpresa.getSelectedItem();
+ if (itemEmpresa != null) {
+ Empresa empresa = (Empresa) itemEmpresa.getValue();
+ parametros.put("EMPRESA_ID", empresa.getEmpresaId());
+ parametros.put("EMPRESA", empresa.getNombempresa());
+ filtro.append(empresa.getNombempresa() + ";");
+ } else {
+ filtro.append(" Todas;");
+ }
+
+ parametros.put("FILTROS", filtro.toString());
+ Relatorio relatorio = new RelatorioDesempenhoPorLinha(parametros, dataSourceRead.getConnection());
+
+ Map args = new HashMap();
+ args.put("relatorio", relatorio);
+
+ openWindow("/component/reportView.zul", Labels.getLabel("relatorioDesempenhoPorLinhaController.window.title"),
+ args, MODAL);
+ }
+}
\ No newline at end of file
diff --git a/src/java/com/rjconsultores/ventaboletos/web/utilerias/menu/item/relatorios/ItemMenuRelatorioDesempenhoPorLinha.java b/src/java/com/rjconsultores/ventaboletos/web/utilerias/menu/item/relatorios/ItemMenuRelatorioDesempenhoPorLinha.java
new file mode 100644
index 000000000..4b57fd3f4
--- /dev/null
+++ b/src/java/com/rjconsultores/ventaboletos/web/utilerias/menu/item/relatorios/ItemMenuRelatorioDesempenhoPorLinha.java
@@ -0,0 +1,26 @@
+package com.rjconsultores.ventaboletos.web.utilerias.menu.item.relatorios;
+
+import org.zkoss.util.resource.Labels;
+
+import com.rjconsultores.ventaboletos.web.utilerias.PantallaUtileria;
+import com.rjconsultores.ventaboletos.web.utilerias.menu.DefaultItemMenuSistema;
+
+public class ItemMenuRelatorioDesempenhoPorLinha extends DefaultItemMenuSistema {
+
+ public ItemMenuRelatorioDesempenhoPorLinha() {
+ super("indexController.mniRelatorioDesempenhoPorLinha.label");
+ }
+
+ @Override
+ public String getClaveMenu() {
+ return "COM.RJCONSULTORES.ADMINISTRACION.GUI.RELATORIOS.MENU.RELATORIODESEMPENHOPORLINHA";
+ }
+
+ @Override
+ public void ejecutar() {
+ PantallaUtileria.openWindow("/gui/relatorios/filtroRelatorioDesempenhoPorLinha.zul",
+ Labels.getLabel("relatorioDesempenhoPorLinhaController.window.title"), getArgs(), desktop);
+
+ }
+}
+
diff --git a/src/java/com/rjconsultores/ventaboletos/web/utilerias/menu/menu_original.properties b/src/java/com/rjconsultores/ventaboletos/web/utilerias/menu/menu_original.properties
index 6fcb97e45..f4c28624f 100644
--- a/src/java/com/rjconsultores/ventaboletos/web/utilerias/menu/menu_original.properties
+++ b/src/java/com/rjconsultores/ventaboletos/web/utilerias/menu/menu_original.properties
@@ -251,6 +251,7 @@ analitico.gerenciais.financeiro.relatorioOperacionalFinanceiro=com.rjconsultores
analitico.gerenciais.financeiro.relatorioResumoVendaOrgaoConcedente=com.rjconsultores.ventaboletos.web.utilerias.menu.item.relatorios.ItemMenuRelatorioResumoVendaOrgaoConcedente
analitico.gerenciais.financeiro.relatorioVendasConexaoRuta=com.rjconsultores.ventaboletos.web.utilerias.menu.item.relatorios.ItemMenuRelatorioVendasConexaoRuta
analitico.gerenciais.financeiro.relatorioVendaBilhetePorEmpresaAutorizadora=com.rjconsultores.ventaboletos.web.utilerias.menu.item.relatorios.ItemMenuVendaBilhetePorEmpresaAutorizadora
+analitico.gerenciais.financeiro.relatorioDesempenhoPorLinha=com.rjconsultores.ventaboletos.web.utilerias.menu.item.relatorios.ItemMenuRelatorioDesempenhoPorLinha
analitico.gerenciais.pacote=com.rjconsultores.ventaboletos.web.utilerias.menu.item.analitico.gerenciais.pacote.SubMenuRelatorioPacote
analitico.gerenciais.pacote.boletos=com.rjconsultores.ventaboletos.web.utilerias.menu.item.relatorios.ItemMenuRelatorioVendasPacotesBoletos
analitico.gerenciais.pacote.detalhado=com.rjconsultores.ventaboletos.web.utilerias.menu.item.relatorios.ItemMenuRelatorioVendasPacotesDetalhado
diff --git a/src/java/com/rjconsultores/ventaboletos/web/utilerias/render/RenderDesempenhoPorLinha.java b/src/java/com/rjconsultores/ventaboletos/web/utilerias/render/RenderDesempenhoPorLinha.java
new file mode 100644
index 000000000..bdc073394
--- /dev/null
+++ b/src/java/com/rjconsultores/ventaboletos/web/utilerias/render/RenderDesempenhoPorLinha.java
@@ -0,0 +1,69 @@
+/**
+ *
+ */
+package com.rjconsultores.ventaboletos.web.utilerias.render;
+
+import org.zkoss.zk.ui.event.Event;
+import org.zkoss.zk.ui.event.EventListener;
+import org.zkoss.zul.Button;
+import org.zkoss.zul.Listcell;
+import org.zkoss.zul.Listitem;
+import org.zkoss.zul.ListitemRenderer;
+
+import com.rjconsultores.ventaboletos.entidad.Empresa;
+import com.rjconsultores.ventaboletos.entidad.OrgaoConcedente;
+import com.rjconsultores.ventaboletos.entidad.PuntoVenta;
+import com.rjconsultores.ventaboletos.entidad.Ruta;
+import com.rjconsultores.ventaboletos.web.utilerias.MyListbox;
+
+/**
+ * @author Thiago
+ *
+ */
+public class RenderDesempenhoPorLinha implements ListitemRenderer {
+
+ @Override
+ public void render(Listitem lstm, Object o) throws Exception {
+ Ruta ruta = (Ruta) o;
+
+ Listcell lc = new Listcell(ruta.getNumRuta() != null ? ruta.getNumRuta().toString() : "");
+ lc.setParent(lstm);
+
+ lc = new Listcell(ruta.getPrefixo());
+ lc.setParent(lstm);
+
+ lc = new Listcell(ruta.getDescruta());
+ lc.setParent(lstm);
+
+ OrgaoConcedente orgaoConcedente = ruta.getOrgaoConcedente();
+ if (orgaoConcedente != null) {
+ lc = new Listcell(orgaoConcedente.getDescOrgao());
+ } else {
+ lc = new Listcell("-");
+ }
+ lc.setParent(lstm);
+
+ Button btn = new Button();
+
+ lc = new Listcell();
+ lc.setParent(lstm);
+
+ btn.setWidth("16");
+ btn.setHeight("16");
+ btn.setImage("/gui/img/remove.png");
+
+ btn.addEventListener("onClick", new EventListener() {
+ @Override
+ public void onEvent(Event event) throws Exception {
+ MyListbox listBox = (MyListbox) event.getTarget().getParent().getParent().getParent();
+ Listitem listItem = (Listitem) event.getTarget().getParent().getParent();
+ listBox.removeItem((Ruta) listItem.getAttribute("data"));
+ }
+ });
+
+ lc.appendChild(btn);
+
+ lstm.setAttribute("data", ruta);
+ }
+
+}
diff --git a/src/java/com/rjconsultores/ventaboletos/web/utilerias/render/RenderDesempenhoPorLinhaTrecho.java b/src/java/com/rjconsultores/ventaboletos/web/utilerias/render/RenderDesempenhoPorLinhaTrecho.java
new file mode 100644
index 000000000..02a8976ee
--- /dev/null
+++ b/src/java/com/rjconsultores/ventaboletos/web/utilerias/render/RenderDesempenhoPorLinhaTrecho.java
@@ -0,0 +1,61 @@
+/**
+ *
+ */
+package com.rjconsultores.ventaboletos.web.utilerias.render;
+
+import org.zkoss.zk.ui.event.Event;
+import org.zkoss.zk.ui.event.EventListener;
+import org.zkoss.zul.Button;
+import org.zkoss.zul.Listcell;
+import org.zkoss.zul.Listitem;
+import org.zkoss.zul.ListitemRenderer;
+
+import com.rjconsultores.ventaboletos.vo.ruta.RutaVO;
+import com.rjconsultores.ventaboletos.web.utilerias.MyListbox;
+
+/**
+ * @author Wallace
+ *
+ */
+public class RenderDesempenhoPorLinhaTrecho implements ListitemRenderer {
+
+ @Override
+ public void render(Listitem lstm, Object o) throws Exception {
+ RutaVO ruta = (RutaVO) o;
+
+ Listcell lc = new Listcell(ruta.getNumRuta().toString());
+ lc.setParent(lstm);
+
+ lc = new Listcell(ruta.getPrefixo());
+ lc.setParent(lstm);
+
+ lc = new Listcell(ruta.getDescruta());
+ lc.setParent(lstm);
+
+ lc = new Listcell(ruta.getDescOrigem());
+ lc.setParent(lstm);
+
+ Button btn = new Button();
+
+ lc = new Listcell();
+ lc.setParent(lstm);
+
+ btn.setWidth("16");
+ btn.setHeight("16");
+ btn.setImage("/gui/img/remove.png");
+
+ btn.addEventListener("onClick", new EventListener() {
+ @Override
+ public void onEvent(Event event) throws Exception {
+ MyListbox listBox = (MyListbox) event.getTarget().getParent().getParent().getParent();
+ Listitem listItem = (Listitem) event.getTarget().getParent().getParent();
+ listBox.removeItem((RutaVO) listItem.getAttribute("data"));
+ }
+ });
+
+ lc.appendChild(btn);
+
+ lstm.setAttribute("data", ruta);
+ }
+
+}
diff --git a/web/WEB-INF/i3-label_en.label b/web/WEB-INF/i3-label_en.label
index e9e1c8216..f532540ca 100644
--- a/web/WEB-INF/i3-label_en.label
+++ b/web/WEB-INF/i3-label_en.label
@@ -319,6 +319,7 @@ indexController.mniRelatoriosOperacionais.mniRelatorioMudancas.Pricing.label = R
indexController.mniRelatorios.label = Relatórios
indexController.mniRelatorioAproveitamento.label = Aproveitamento
+indexController.mniRelatorioDesempenhoPorLinha.label = Desempenho por Linha
indexController.mniRelatorioArquivoBGM.label = Arquivo BGM
indexController.mniRelatorioReceitasDespesasDiversas.label=Receitas/Despesas Diversas e Depósitos Bancários
indexController.mniLogReceitasDespesasDiversas.label=Log Receitas/Despesas Diversas e Depósitos Bancários
@@ -599,6 +600,25 @@ relatorioKmProgramadaController.lbLote.value = Lote
relatorioKmProgramadaController.lbAte.value = até
relatorioKmProgramadaController.lbGrupoRuta.label = Grupo de Linhas
+#DesempenhoPorLinha
+relatorioDesempenhoPorLinhaController.window.title = Relatório de Desempenho por linha
+relatorioDesempenhoPorLinhaController.window.title = Relatório de Aproveitamento Financeiro
+relatorioDesempenhoPorLinhaController.lbDatInicial.value = Data inicial
+relatorioDesempenhoPorLinhaController.lbDatFinal.value = Data final
+relatorioDesempenhoPorLinhaController.lbPuntoVenta.value = Agência
+relatorioDesempenhoPorLinhaController.lbEmpresa.value = Empresa
+relatorioDesempenhoPorLinhaController.btnPesquisa.label = Buscar
+relatorioDesempenhoPorLinhaController.btnLimpar.label = Limpar
+relatorioDesempenhoPorLinhaController.lbNumero.value = Número Agência
+relatorioDesempenhoPorLinhaController.window.title = Relatório de Aproveitamento Financeiro
+relatorioDesempenhoPorLinhaController.linha = Relatório por Linha
+relatorioDesempenhoPorLinhaController.trecho = Relatório por Trecho
+relatorioDesempenhoPorLinhaController.lbOrigem.value = Origem
+relatorioDesempenhoPorLinhaController.lbDestino.value = Destino
+relatorioDesempenhoPorLinhaController.lbNumRuta.label = Num. Linha
+relatorioDesempenhoPorLinhaController.lbPrefixo.label = Prefixo
+relatorioDesempenhoPorLinhaController.lbOrgao.label = Orgão Concedente
+
#Aproveitamento
relatorioAproveitamentoController.window.title = Relatório de Aproveitamento
relatorioAproveitamentoController.lbFecCorrida.value = Data Serviço
diff --git a/web/WEB-INF/i3-label_es_MX.label b/web/WEB-INF/i3-label_es_MX.label
index c359c0c12..42eef5926 100644
--- a/web/WEB-INF/i3-label_es_MX.label
+++ b/web/WEB-INF/i3-label_es_MX.label
@@ -306,6 +306,7 @@ indexController.mniRelatoriosOperacionais.mniRelatorioMudancas.Pricing.label = R
indexController.mniRelatorios.label = Reportes
indexController.mniRelatorioAproveitamento.label = Aprovechamiento
+indexController.mniRelatorioDesempenhoPorLinha.label = Desempenho por Linha
indexController.mniRelatorioArquivoBGM.label = Arquivo BGM
indexController.mniRelatorioReceitasDespesasDiversas.label=Receitas/Despesas Diversas e Depósitos Bancários
indexController.mniLogReceitasDespesasDiversas.label=Log Receitas/Despesas Diversas e Depósitos Bancários
@@ -532,6 +533,26 @@ relatorioResumoLinhasController.lbAte.value = Hasta
relatorioResumoLinhasController.lblSumarizar.value = Sumarizar por linhas (Completo)
relatorioResumoLinhasController.lblSimplificadoSumarizado.value = Sumarizar por linhas (Simplificado)
+
+#DesempenhoPorLinha
+relatorioDesempenhoPorLinhaController.window.title = Relatório de Desempenho por linha
+relatorioDesempenhoPorLinhaController.window.title = Relatório de Aproveitamento Financeiro
+relatorioDesempenhoPorLinhaController.lbDatInicial.value = Data inicial
+relatorioDesempenhoPorLinhaController.lbDatFinal.value = Data final
+relatorioDesempenhoPorLinhaController.lbPuntoVenta.value = Agência
+relatorioDesempenhoPorLinhaController.lbEmpresa.value = Empresa
+relatorioDesempenhoPorLinhaController.btnPesquisa.label = Buscar
+relatorioDesempenhoPorLinhaController.btnLimpar.label = Limpar
+relatorioDesempenhoPorLinhaController.lbNumero.value = Número Agência
+relatorioDesempenhoPorLinhaController.window.title = Relatório de Aproveitamento Financeiro
+relatorioDesempenhoPorLinhaController.linha = Relatório por Linha
+relatorioDesempenhoPorLinhaController.trecho = Relatório por Trecho
+relatorioDesempenhoPorLinhaController.lbOrigem.value = Origem
+relatorioDesempenhoPorLinhaController.lbDestino.value = Destino
+relatorioDesempenhoPorLinhaController.lbNumRuta.label = Num. Linha
+relatorioDesempenhoPorLinhaController.lbPrefixo.label = Prefixo
+relatorioDesempenhoPorLinhaController.lbOrgao.label = Orgão Concedente
+
#Aproveitamento
relatorioAproveitamentoController.window.title = Reporte de ocupación
relatorioAproveitamentoController.lbFecCorrida.value = Fecha servicio
diff --git a/web/WEB-INF/i3-label_pt_BR.label b/web/WEB-INF/i3-label_pt_BR.label
index 60780ebcb..940a00ee5 100644
--- a/web/WEB-INF/i3-label_pt_BR.label
+++ b/web/WEB-INF/i3-label_pt_BR.label
@@ -319,6 +319,7 @@ indexController.mniRelatoriosOperacionais.mniRelatorioMudancas.Pricing.label = R
indexController.mniRelatorios.label = Relatórios
indexController.mniRelatorioAproveitamento.label = Aproveitamento
+indexController.mniRelatorioDesempenhoPorLinha.label = Desempenho por Linha
indexController.mniRelatorioArquivoBGM.label = Arquivo BGM
indexController.mniRelatorioReceitasDespesasDiversas.label=Receitas/Despesas Diversas e Depósitos Bancários
indexController.mniLogReceitasDespesasDiversas.label=Log Receitas/Despesas Diversas e Depósitos Bancários
@@ -599,6 +600,25 @@ relatorioKmProgramadaController.lbLote.value = Lote
relatorioKmProgramadaController.lbAte.value = até
relatorioKmProgramadaController.lbGrupoRuta.label = Grupo de Linhas
+#DesempenhoPorLinha
+relatorioDesempenhoPorLinhaController.window.title = Relatório de Desempenho por linha
+relatorioDesempenhoPorLinhaController.window.title = Relatório de Aproveitamento Financeiro
+relatorioDesempenhoPorLinhaController.lbDatInicial.value = Data inicial
+relatorioDesempenhoPorLinhaController.lbDatFinal.value = Data final
+relatorioDesempenhoPorLinhaController.lbPuntoVenta.value = Agência
+relatorioDesempenhoPorLinhaController.lbEmpresa.value = Empresa
+relatorioDesempenhoPorLinhaController.btnPesquisa.label = Buscar
+relatorioDesempenhoPorLinhaController.btnLimpar.label = Limpar
+relatorioDesempenhoPorLinhaController.lbNumero.value = Número Agência
+relatorioDesempenhoPorLinhaController.window.title = Relatório de Aproveitamento Financeiro
+relatorioDesempenhoPorLinhaController.linha = Relatório por Linha
+relatorioDesempenhoPorLinhaController.trecho = Relatório por Trecho
+relatorioDesempenhoPorLinhaController.lbOrigem.value = Origem
+relatorioDesempenhoPorLinhaController.lbDestino.value = Destino
+relatorioDesempenhoPorLinhaController.lbNumRuta.label = Num. Linha
+relatorioDesempenhoPorLinhaController.lbPrefixo.label = Prefixo
+relatorioDesempenhoPorLinhaController.lbOrgao.label = Orgão Concedente
+
#Aproveitamento
relatorioAproveitamentoController.window.title = Relatório de Aproveitamento
relatorioAproveitamentoController.lbFecCorrida.value = Data Serviço
diff --git a/web/gui/relatorios/filtroRelatorioDesempenhoPorLinha.zul b/web/gui/relatorios/filtroRelatorioDesempenhoPorLinha.zul
new file mode 100644
index 000000000..a8cd61e54
--- /dev/null
+++ b/web/gui/relatorios/filtroRelatorioDesempenhoPorLinha.zul
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rowTrecho.setVisible(false);
+
+
+
+
+
+ rowTrecho.setVisible(true);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file