Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Mapa de Apontamentos - GenericMap

O Mapa de Apontamentos tem como objetivo principal exibir Dados de Apontamentos referentes a uma Entidade Principal.

Pré-requisitos

São pré-requisitos para esse módulo:

  1. Painel para exibir os detalhes dos Apontamentos;
  2. Tabelas "nfs_mapa_generico" e "nfs_mapa_generico_relatorio" criadas na seguinte estrutura:
CREATE TABLE `nfs_mapa_generico` (
  `SEQ_DB` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `EMPRESA` int(11) DEFAULT NULL,
  `FILIAL` int(11) DEFAULT NULL,
  `LOCAL` int(11) DEFAULT NULL,
  `TABLENAME` varchar(100) DEFAULT NULL,
  `TITLE` varchar(100) DEFAULT NULL,
  `MAIN_TABLE` varchar(200) DEFAULT NULL,
  `DISPLAY_FIELDS` varchar(1000) DEFAULT NULL,
  `OPTIONS` varchar(500) DEFAULT NULL,
  `REPORT_DAYS` varchar(500) DEFAULT NULL,
  `REPORT_TYPES` varchar(500) DEFAULT NULL,
  `QUERY_STATEMENTS` text,
  `SUBQUERY_STATEMENTS` text,
  `JORNADA_QUERY` text,
  `FILTERS` varchar(1000) DEFAULT NULL,
  `LEGENDS` varchar(1000) DEFAULT NULL,
  `INDICATORS` varchar(1000) DEFAULT NULL,
  `ENABLED` int(1) DEFAULT NULL,
  PRIMARY KEY (`SEQ_DB`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `nfs_mapa_generico_relatorio` (
  `SEQ_DB` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `EMPRESA` int(11) DEFAULT NULL,
  `FILIAL` int(11) DEFAULT NULL,
  `LOCAL` int(11) DEFAULT NULL,
  `MAPA_GENERICO_SEQ_DB` bigint(20) unsigned DEFAULT NULL,
  `TIPO_RELATORIO` varchar(20) DEFAULT NULL,
  `QUERY_STATEMENTS` text,
  `DISPLAY_FIELDS` varchar(1000) DEFAULT NULL,
  `SUBQUERY_STATEMENTS` text,
  `ENABLED` int(1) DEFAULT NULL,
  PRIMARY KEY (`SEQ_DB`),
  KEY `idx_nfs_mapa_generico_relatorio` (`SEQ_DB`),
  KEY `fk_nfs_mapa_generico_relatorio_seq_db` (`MAPA_GENERICO_SEQ_DB`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  1. Caso não esteja habilitado, habilitar módulo "Rotas Personalizada";
  2. *Criar rota personalizada para "/custom/mapa/<tablename>";

*devemos passar como tablename o nome que definimos como TABLENAME para o mapa genérico na tabela nfs_mapa_generico ; { .is-warning }

Construção da consulta

Todo o processo de construção da consulta para este módulo usou como base a consulta do BoBAgro, que consiste do resultado de 3 subconsultas, sendo:

  1. A primeira subconsulta obtem os dados dos apontamentos que são iniciados e finalizados no mesmo dia:
-- 1ª Subconsulta
INI_DH = '01/01/2019 08:00:00'
FIM_DH = '01/01/2019 16:59:59'
  1. A segunda e terceira subconsultas obtem os dados dos apontamentos que são iniciados e terminados em dias diferentes. Assim a segunda subconsulta obtem os dados parciais do apontamento até as 23h59'59 do mesmo dia, e a terceira subconsulta os dados parcias restantes do mesmo apontamento:
DT_INI = '01/01/2019 22:00:00'
DT_FIM = '02/01/2019 06:00:00'

-- 2ª Subconsulta
DT_INI = '01/01/2019 22:00:00' e DT_FIM = '01/01/2019 23:59:59'
-- 3ª Subconsulta
DT_INI = '02/01/2019 00:00:00' e DT_FIM = '02/01/2019 06:00:00'

Tabela nfs_mapa_generico

Possui as definições principais do ambiente, sendo:

1. TABLENAME:

Apelido/Nome da entidade definido para o mapa genérico; (sera usado para acessar o mapa generico como descrito no 4º item dos pré-requisitos desse módulo)

TABLENAME ='EQUIPAMENTO'

2. TITLE:

Título do Mapa exibido no topo do módulo;

TITLE ='Mapa de Apontamento Máquina'

3. MAIN_TABLE:

Nome da tabela principal (usada como link entre para o Painel QIG);

MAIN_TABLE ='EQUIPAMENTO'

4. DISPLAY_FIELDS:

Configuração JSON de exibição dos dados principais;

{
  "KEY": "idEquipamento",
  "TITLE": "codigoEquipamento",
  "FIELD_LINK" : "idEquipamento",
  "DATAS": {
    "INI": "dataAbertura",
    "FIM": "dataFinal"
  },
  "COLUNAS": {
    "descricaoModelo": "Modelo",
    "codigoEquipamento": "Equipamento"
  },
  "INDICADOR": "produtiva",
  "TOOLTIP": {
    "codigoOperacao": "Código Atividade",
    "descOperacao": "Descrição Atividade",
    "codigoOperador": "Código Operador",
    "nomeOperador": "Nome Operador"
  }
}

Onde:

  • KEY: chave principal da consulta;
  • TITLE: título do gráfico gerado;
  • FIELD_LINK: Usado para quando o Detalhes não é o mesmo dados que KEY, no caso se for um Mapa de Apontamentos de Mão de Obra, onde o Boletim é por Encarregado e o Mapa deve ser pelo operador, com isso para não ficar o LINK para o Operador, deve ser passado o SEQ_DB do encarregado para poder abrir seu Detalhes;
  • DATAS: alias das colunas INI_DH e FIM_DH das subconsultas;
  • COLUNAS: labels exibidas nas tabela de resultados;
  • INDICADOR: atividade Produtiva ou Improdutiva;
  • TOOLTIP: colunas:labels exibidas no tooltip do gráfico.
  1. OPTIONS: dados opcionais (por ora, usado apenas um valor de Jornada de Trabalho Padrão);
{
  "JORNADA_PADRAO": 12
}

6. REPORT_DAYS:

Configuração JSON para perído de dias processados no relatório (esse valor usa a data fornecida como referência);

{
  "5": {
    "label": "-5 dias",
    "value": 5,
    "selected": true
  },
  "10": {
    "label": "-10 dias",
    "value": 10,
    "selected": false
  },
  "15": {
    "label": "-15 dias",
    "value": 15,
    "selected": false
  }
}

Onde:

  • label: label exibida no drop-down;
  • value: quantidade de dias;
  • selected: se pré-selecionado ou não.

7. REPORT_TYPES:

Configuração JSON para tipos de relatório gerado. Cada tipo especificado requer de um registro na tabela nfs_mapa_generico_relatorio com detalhes do relatório gerado);

{
  "tipoPorcentagem": {
    "label": "Porcentagem",
    "value": "porcentagem",
    "selected": true
  },
  "tipoHoras": {
    "label": "Horas",
    "value": "horas",
    "selected": false
  },
  "tipoProducao": {
    "value": "producao",
    "label": "Produção",
    "selected": false
  }
}

Onde:

  • label: label do drop-down;
  • value: link com tipo de relatório em nfs_mapa_generico_relatorio;
  • selected: se pré-selecionado ou não.

8. QUERY_STATEMENTS:

Statements usados para montar a consulta principal (comentados inline para melhor entendimento);

{
  "SELECT": [
    "e.SEQ_DB as idEquipamento", // chave principal da consulta
    "e.CODIGO as codigoEquipamento", // colunas exibidas nas tabela de resultados
    "m.SEQ_DB as idModelo",
    "m.DESCRICAO as descricaoModelo", // colunas exibidas nas tabela de resultados
    "dados.dataAbertura", // datas de referência
    "dados.dataFinal",
    "codigoOperacao", // colunas usadas no tooltip e indicador
    "descOperacao",
    "produtiva",
    "codigoOperador",
    "nomeOperador"
  ],
  "FROM": [], // consulta baseada em subquery
  "SUBQUERY": ["dados", "idEquipamento"], // resultado da subquery com chave
  "JOIN": [
    "right join app_equipamento e on e.SEQ_DB = dados.idEquipamento",
    "inner join app_classe_operacional c on e.CLASSE_OPERACIONAL_SEQ_DB = c.SEQ_DB",
    "inner join app_modelo m on e.MODELO_SEQ_DB = m.SEQ_DB"
  ],
  "WHERE": [
    "e.ATIVO = 1 and e.DELETED = 0 and e.EMPRESA in (:empresa, 9999) and e.FILIAL in (:filial, 9999) and e.LOCAL in (:local, 9999)",
    "c.ATIVO = 1 and c.DELETED = 0 and c.EMPRESA in (:empresa, 9999) and c.FILIAL in (:filial, 9999) and c.LOCAL in (:local, 9999)",
    "m.ATIVO = 1 and m.DELETED = 0 and m.EMPRESA in (:empresa, 9999) and m.FILIAL in (:filial, 9999) and m.LOCAL in (:local, 9999)"
  ],
  "ORDER_BY": [
    "dados.idModelo",
    "dados.codigoEquipamento",
    "dados.dataAbertura"
  ]
}

9. SUBQUERY_STATEMENTS:

Statements usados para montar subconsultas (comentados inline para melhor entendimento);

{
  "SELECT": [
    // resultado das subquery's
    "eq.SEQ_DB as idEquipamento",
    "eq.CODIGO as codigoEquipamento",
    "cl.SEQ_DB as idClasse",
    "mo.SEQ_DB as idModelo",
    "mo.DESCRICAO as descricaoModelo",
    "se.SEQ_DB as idRegional",
    "coalesce(atv.CODIGO, '') as codigoOperacao",
    "coalesce(atv.DESCRICAO, '') as descOperacao",
    "coalesce(atv.FLAG_PRODUTIVA, 0) as produtiva",
    "coalesce(op.CRACHA, '') as codigoOperador",
    "coalesce(op.NOME, '') as nomeOperador"
  ],
  "FROM": [
    // tabela principal das subquery's
    ["app_apontamento_maquina", "ap"]
  ],
  "JOIN": [
    // relacionamentos de cada subquery
    "inner join app_boletim_maquina bo on bo.SEQ_DB = ap.SEQ_DB_DEVICE_MASTER_SEQ_DB",
    "inner join app_equipamento eq on eq.SEQ_DB = bo.EQUIPAMENTO_SEQ_DB",
    "inner join app_modelo mo on mo.SEQ_DB = eq.MODELO_SEQ_DB",
    "inner join app_classe_operacional cl on cl.SEQ_DB = eq.CLASSE_OPERACIONAL_SEQ_DB",
    "inner join app_setor se on se.SEQ_DB = ap.SETOR_SEQ_DB",
    "left join app_atividade atv on atv.SEQ_DB = ap.ATIVIDADE_SEQ_DB",
    "left join app_operador op on op.SEQ_DB = bo.OPERADOR_SEQ_DB"
  ],
  "WHERE": [
    // filtros (só apontamentos fechados)
    "ap.ATIVO = 1 and ap.DELETED = 0 and ap.EMPRESA in (:empresa, 9999) and ap.FILIAL in (:filial, 9999) and ap.LOCAL in (:local, 9999) and ap.FIM_DH is not null"
  ],
  "GROUP_BY": [
    "idEquipamento",
    "codigoEquipamento",
    "idClasse",
    "idModelo",
    "descricaoModelo",
    "ap.FIM_DH",
    "ap.INI_DH",
    "idRegional",
    "codigoOperacao",
    "descOperacao",
    "produtiva",
    "codigoOperador",
    "nomeOperador"
  ],
  "UNION": [
    {
      // diferenças entre as subquery's
      "SELECT": [
        // subquery 1: apontamentos iniciados e finalizados no mesmo dia
        "ap.INI_DH as dataAbertura",
        "ap.FIM_DH as dataFinal"
      ],
      "WHERE": [
        "ap.INI_DH between concat(:de, ' 00:00:00') and concat(:ate, ' 23:59:59')",
        "date(ap.INI_DH) = date(ap.FIM_DH)"
      ]
    },
    {
      "SELECT": [
        // subquery 2: apontamentos iniciados e finalizados no próximo dia (até fim do dia)
        "ap.INI_DH as dataAbertura",
        "concat(date(ap.INI_DH), ' 23:59:59') as dataFinal"
      ],
      "WHERE": [
        "(ap.INI_DH between concat(:de, ' 00:00:00') and concat(:ate, ' 23:59:59') or ap.FIM_DH between concat(:de, ' 00:00:00') and concat(:ate, ' 23:59:59'))",
        "ap.INI_DH >= concat(:de, ' 00:00:00')",
        "date(ap.INI_DH) < date(ap.FIM_DH)"
      ]
    },
    {
      "SELECT": [
        // subquery 2: apontamentos iniciados e finalizados no próximo dia (0h em diante)
        "concat(date_add(date(ap.INI_DH), interval 1 day), ' 00:00:00') as dataAbertura",
        "ap.FIM_DH as dataFinal"
      ],
      "WHERE": [
        "ap.INI_DH >= concat(:de, ' 00:00:00')",
        "ap.FIM_DH <= concat(:ate, ' 23:59:59')",
        "date(ap.INI_DH) < date(ap.FIM_DH)"
      ]
    }
  ]
}

10. JORNADA_QUERY:

QueryBuilder para obter jornada de trabalho da entidade (são retornadas as jornadas de trabalho de todos os dias);

{
  "SELECT": ["ej.EQUIPAMENTO_SEQ_DB AS ID", "jor.*"],
  "FROM": [["equipamento_jornada", "ej"]],
  "JOIN": [["ej", "jornada", "jor", "jor.SEQ_DB = ej.JORNADA_SEQ_DB"]],
  "WHERE": [
    "ej.EQUIPAMENTO_SEQ_DB in (:lista)",
    "ej.INI_VIGENCIA <= :data",
    "(ej.FIM_VIGENCIA >= :data or ej.FIM_VIGENCIA is null)"
  ]
}

IMPORTANTE: As cláusulas (SELECT, FROM etc.) devem está em CAIXA ALTA; em futuras versões esses parâmetros serão normalizados, seguindo as definições do QueryBuilder. {.is-danger}

Caso queira utilizar algum campo em especifico ao invés de utilizar uma tabela de jornadas, podemos especificar esse campo definindo no registro(s) o valor JORNADA_POR_CAMPO igual a 1 e adicionando o alias JORNADA_VALOR no campo a ser usado como o valor de jornada, exemplo:

{
    "SELECT": [
        "eqp.SEQ_DB AS ID",
        "eqp.DISPONIBILIDADE AS JORNADA_VALOR",
        "1 as JORNADA_POR_CAMPO"
    ],
    "FROM": [
        ["eqp", "eqp"]
    ],
    "WHERE": [
        "eqp.SEQ_DB in (:lista)"
    ]
}

11. FILTERS:

Filtros disponíveis para composição do relatório;

{
  "classe_operacional": {
    "label": "Classe Operacional",
    "query_alias": "c",
    "subquery_alias": "cl",
    "id": "SEQ_DB",
    "descricao": "DESCRICAO",
    "multiple": true,
    "subfilter": "equipamento"
  },
  "modelo": {
    "label": "Modelo",
    "query_alias": "m",
    "subquery_alias": "mo",
    "id": "SEQ_DB",
    "descricao": "DESCRICAO",
    "multiple": true,
    "subfilter": "equipamento"
  },
  "equipamento": {
    "label": "Equipamento",
    "query_alias": "e",
    "subquery_alias": "eq",
    "id": "SEQ_DB",
    "descricao": "DESCRICAO",
    "multiple": true,
    "subfilter": ""
  },
  "setor": {
    "label": "Setor / Regional",
    "query_alias": "",
    "subquery_alias": "se",
    "id": "SEQ_DB",
    "descricao": "DESCRICAO",
    "multiple": true,
    "subfilter": ""
  }
}

Onde:

  • label: label do formulário de filtro;
  • query_alias: alias para consulta principal (preenchido se aplicável);
  • subquery_alias: alias para subquery (preenchido se aplicável);
  • id: valor para filtro;
  • descricao: descrição para filtro;
  • multiple: se permite filtrar por mais de um valor;
  • subfilter: preenchido se valores filtram outros filtros.

Se as chaves query_alias e subquery_alias forem preenchidas os filtros serão aplicados na consulta principal e/ou na subquery, respectivamente. {.is-danger}

12. LEGENDS:

Legendas principais para apontamentos em relação à jornada de trabalho da entidade;

{
  "zero": {
    "label": "0%", // label da legenda
    "color": "#FF5050", // cor da legenda
    "eval": "[percent] == 0" // operção lógica sobre percentual obtido na consulta
  },
  "insatisfatorio": {
    "label": "> 0%",
    "color": "#E59400",
    "eval": "[percent] > 0 && [percent] < 50"
  },
  "satisfatorio": {
    "label": ">= 50%",
    "color": "#ffff00",
    "eval": "[percent] >= 50 && [percent] < 90"
  },
  "otimo": {
    "label": ">= 90%",
    "color": "#92D050",
    "eval": "[percent] >= 90"
  }
}

Onde:

  • label: label da legenda;
  • color: cor da legenda.
  • eval: operção lógica sobre percentual obtido na consulta.
  1. INDICATORS: Indicadores exibidos no gráfico (atividade produtiva ou não, ou demais indicadores).
{
  "produtiva": {
    "value": 1,
    "label": "Produtiva",
    "color": "#92D050"
  },
  "improdutiva": {
    "value": 0,
    "label": "Produtiva",
    "color": "#FF5050"
  }
}

Onde:

  • value: valor obtido da consulta;
  • label: label exibido no legenda;
  • color: cor da legenda.

Tabela nfs_mapa_generico_relatorio

Possui as definições de cada tipo de relatório gerado (coluna REPORT_TYPES da nfs_mapa_generico), sendo:

1. MAPA_GENERICO_SEQ_DB:

FK da tabela nfs_mapa_generico;

MAPA_GENERICO_SEQ_DB=1

2. TIPO_RELATORIO:

valor do tipo de relatório selecionado;

TIPO_RELATORIO='porcentagem'

3. QUERY_STATEMENTS:

coluna(s) da consulta principal que será usada na construção do tipo de relatório;

{
  "SELECT": [
    "timestampdiff(second, cast(dataAbertura as datetime), cast(dataFinal as datetime)) as tempoApontado"
  ]
}

Ou, para o tipo producao da entidade equipamento da BoBAgro, usa-se os seguintes dados:

{
  "SELECT": ["producao as tempoApontado", "divisao"]
}

Observações Normalmente deve-se especificar aqui o campo que será usado como valor de referência para o relatório. Nos exemplos acima temos o campo tempoApontamento que é o valor em segundos usado para determinar o percentual de apontamento por Jornada de Trabalho da entidade. No segundo exemplo temos a coluna divisao, que é usada para criar um agrupamento adicional (além do agrupamento por dia); nesse exemplo, o agrupamento seria o Código da Fazenda e o Código do Talhão descritos no SUBQUERY_STATEMENTS a seguir.

4. DISPLAY_FIELDS:

definições de exibição e/ou agrupamento dos dados de acordo com o tipo de relatório;

{
  "MAIN": "tempoApontado",
  "TIPO": "absolute",
  "DIVISAO": ""
}

DICA

  • MAIN: refere-se ao valor de referência para o relatório;
  • TIPO: tipo de formatação/exibição do dados. Os valores previstos são "absolute" (valor do campo MAIN convertido em horas, por exemplo, ou producao, no tipo de relatório "producao"*), "percent" (valor exibido em percentual em relação a Jornada de Trabalho da Entidade) ou "html" (este é usando quando existe agrupamento de dados, p.ex., tipo de relatório producao, onde os dados são agrupados por Fazenda/Talhão);
  • DIVISAO: especificado quando existe agrupamento de dados além do dia.

5. SUBQUERY_STATEMENTS:

Statements que serão usando nas subconsultas. Caso as subquery's de um determinado tipo de relatório requera mais colunas/relacionamento/agrupamento, estes são especificados aqui;

{
  "SELECT": [
    "sum(pr.producao) as producao",
    "concat(fz.CODIGO, '-', coalesce(tl.CODIGO, '')) as divisao "
  ],
  "JOIN": [
    "left join app_apontamento_maquina_producao pr on pr.SEQ_DB_DEVICE_MASTER_SEQ_DB = bo.SEQ_DB and pr.ATIVIDADE_SEQ_DB = atv.SEQ_DB and pr.ATIVO = 1 and pr.DELETED = 0 and pr.EMPRESA in (:empresa, 9999) and pr.FILIAL in (:filial, 9999) and pr.LOCAL in (:local, 9999)",
    "left join app_fazenda fz on fz.SEQ_DB = ap.FAZENDA_SEQ_DB and fz.ATIVO = 1 and fz.DELETED = 0 and fz.EMPRESA in (:empresa, 9999) and fz.FILIAL in (:filial, 9999) and fz.LOCAL in (:local, 9999)",
    "left join app_talhao tl on tl.SEQ_DB = pr.TALHAO_SEQ_DB and tl.ATIVO = 1 and tl.DELETED = 0 and tl.EMPRESA in (:empresa, 9999) and tl.FILIAL in (:filial, 9999) and tl.LOCAL in (:local, 9999)"
  ],
  "GROUP_BY": ["divisao"]
}

Referências

Como referência, segue duas consultas geradas de acordo com os dados usados nos exemplos:

  1. Entidade "EQUIPAMENTO" e Tipo de Relatório "porcentagem" no período 23/01/2019 a 27/01/2019
select
  e.SEQ_DB as idEquipamento,
  e.CODIGO as codigoEquipamento,
  m.SEQ_DB as idModelo,
  m.DESCRICAO as descricaoModelo,
  dados.dataAbertura,
  dados.dataFinal,
  codigoOperacao,
  descOperacao,
  produtiva,
  codigoOperador,
  nomeOperador,
  timestampdiff(second,
  cast(dataAbertura as datetime),
  cast(dataFinal as datetime)) as tempoApontado
from (
  select
    eq.SEQ_DB as idEquipamento,
    eq.CODIGO as codigoEquipamento,
    cl.SEQ_DB as idClasse,
    mo.SEQ_DB as idModelo,
    mo.DESCRICAO as descricaoModelo,
    coalesce(atv.CODIGO, '') as codigoOperacao,
    coalesce(atv.DESCRICAO, '') as descOperacao,
    coalesce(atv.FLAG_PRODUTIVA, 0) as produtiva,
    coalesce(op.CRACHA, '') as codigoOperador,
    coalesce(op.NOME, '') as nomeOperador,
    se.SEQ_DB as idRegional,
    ap.INI_DH as dataAbertura,
    ap.FIM_DH as dataFinal
  from app_apontamento_maquina as ap
  inner join app_boletim_maquina bo on bo.SEQ_DB = ap.SEQ_DB_DEVICE_MASTER_SEQ_DB
  inner join app_equipamento eq on eq.SEQ_DB = bo.EQUIPAMENTO_SEQ_DB
  inner join app_modelo mo on mo.SEQ_DB = eq.MODELO_SEQ_DB
  inner join app_classe_operacional cl on cl.SEQ_DB = eq.CLASSE_OPERACIONAL_SEQ_DB
  inner join app_setor se on se.SEQ_DB = ap.SETOR_SEQ_DB
  left join app_atividade atv on atv.SEQ_DB = ap.ATIVIDADE_SEQ_DB
  left join app_operador op on op.SEQ_DB = bo.OPERADOR_SEQ_DB
  where
    ap.ATIVO = 1 and ap.DELETED = 0 and ap.EMPRESA in (1, 9999) and ap.FILIAL in (1, 9999) and ap.LOCAL in (1, 9999)
    and ap.FIM_DH is not null
    and ap.INI_DH between '2019-01-23 00:00:00' and '2019-01-27 23:59:59'
    and date(ap.INI_DH) = date(ap.FIM_DH)
  group by
    idEquipamento,
    codigoEquipamento,
    idClasse,
    idModelo,
    descricaoModelo,
    ap.FIM_DH,
    ap.INI_DH,
    idRegional,
    codigoOperacao,
    descOperacao,
    produtiva,
    codigoOperador,
    nomeOperador
  union all
  select
    eq.SEQ_DB as idEquipamento,
    eq.CODIGO as codigoEquipamento,
    cl.SEQ_DB as idClasse,
    mo.SEQ_DB as idModelo,
    mo.DESCRICAO as descricaoModelo,
    coalesce(atv.CODIGO, '') as codigoOperacao,
    coalesce(atv.DESCRICAO, '') as descOperacao,
    coalesce(atv.FLAG_PRODUTIVA, 0) as produtiva,
    coalesce(op.CRACHA, '') as codigoOperador,
    coalesce(op.NOME, '') as nomeOperador,
    se.SEQ_DB as idRegional,
    ap.INI_DH as dataAbertura,
    concat(date(ap.INI_DH), ' 23:59:59') as dataFinal
  from app_apontamento_maquina as ap
  inner join app_boletim_maquina bo on bo.SEQ_DB = ap.SEQ_DB_DEVICE_MASTER_SEQ_DB
  inner join app_equipamento eq on eq.SEQ_DB = bo.EQUIPAMENTO_SEQ_DB
  inner join app_modelo mo on mo.SEQ_DB = eq.MODELO_SEQ_DB
  inner join app_classe_operacional cl on cl.SEQ_DB = eq.CLASSE_OPERACIONAL_SEQ_DB
  inner join app_setor se on se.SEQ_DB = ap.SETOR_SEQ_DB
  left join app_atividade atv on atv.SEQ_DB = ap.ATIVIDADE_SEQ_DB
  left join app_operador op on op.SEQ_DB = bo.OPERADOR_SEQ_DB
  where
    ap.ATIVO = 1 and ap.DELETED = 0 and ap.EMPRESA in (1, 9999) and ap.FILIAL in (1, 9999) and ap.LOCAL in (1, 9999)
    and ap.FIM_DH is not null
    and (ap.INI_DH between '2019-01-23 00:00:00' and '2019-01-27 23:59:59' or ap.FIM_DH between '2019-01-23 00:00:00' and '2019-01-27 23:59:59')
    and ap.INI_DH >= '2019-01-23 00:00:00'
    and date(ap.INI_DH) < date(ap.FIM_DH)
  group by
    idEquipamento,
    codigoEquipamento,
    idClasse,
    idModelo,
    descricaoModelo,
    ap.FIM_DH,
    ap.INI_DH,
    idRegional,
    codigoOperacao,
    descOperacao,
    produtiva,
    codigoOperador,
    nomeOperador
  union all
  select
    eq.SEQ_DB as idEquipamento,
    eq.CODIGO as codigoEquipamento,
    cl.SEQ_DB as idClasse,
    mo.SEQ_DB as idModelo,
    mo.DESCRICAO as descricaoModelo,
    coalesce(atv.CODIGO, '') as codigoOperacao,
    coalesce(atv.DESCRICAO, '') as descOperacao,
    coalesce(atv.FLAG_PRODUTIVA, 0) as produtiva,
    coalesce(op.CRACHA, '') as codigoOperador,
    coalesce(op.NOME, '') as nomeOperador,
    se.SEQ_DB as idRegional,
    concat(date_add(date(ap.INI_DH), interval 1 day), ' 00:00:00') as dataAbertura,
    ap.FIM_DH as dataFinal
  from app_apontamento_maquina as ap
  inner join app_boletim_maquina bo on bo.SEQ_DB = ap.SEQ_DB_DEVICE_MASTER_SEQ_DB
  inner join app_equipamento eq on eq.SEQ_DB = bo.EQUIPAMENTO_SEQ_DB
  inner join app_modelo mo on mo.SEQ_DB = eq.MODELO_SEQ_DB
  inner join app_classe_operacional cl on cl.SEQ_DB = eq.CLASSE_OPERACIONAL_SEQ_DB
  inner join app_setor se on se.SEQ_DB = ap.SETOR_SEQ_DB
  left join app_atividade atv on atv.SEQ_DB = ap.ATIVIDADE_SEQ_DB
  left join app_operador op on op.SEQ_DB = bo.OPERADOR_SEQ_DB
  where
    ap.ATIVO = 1 and ap.DELETED = 0 and ap.EMPRESA in (1, 9999) and ap.FILIAL in (1, 9999) and ap.LOCAL in (1, 9999)
    and ap.FIM_DH is not null
    and ap.INI_DH >= '2019-01-23 00:00:00'
    and ap.FIM_DH <= '2019-01-27 23:59:59'
    and date(ap.INI_DH) < date(ap.FIM_DH)
  group by
    idEquipamento,
    codigoEquipamento,
    idClasse,
    idModelo,
    descricaoModelo,
    ap.FIM_DH,
    ap.INI_DH,
    idRegional,
    codigoOperacao,
    descOperacao,
    produtiva,
    codigoOperador,
    nomeOperador
) dados
right join app_equipamento e on e.SEQ_DB = dados.idEquipamento
inner join app_classe_operacional c on e.CLASSE_OPERACIONAL_SEQ_DB = c.SEQ_DB
inner join app_modelo m on e.MODELO_SEQ_DB = m.SEQ_DB
where
  e.ATIVO = 1 and e.DELETED = 0 and e.EMPRESA in (1, 9999) and e.FILIAL in (1, 9999) and e.LOCAL in (1, 9999)
  and c.ATIVO = 1 and c.DELETED = 0 and c.EMPRESA in (1, 9999) and c.FILIAL in (1, 9999) and c.LOCAL in (1, 9999)
  and m.ATIVO = 1 and m.DELETED = 0 and m.EMPRESA in (1, 9999) and m.FILIAL in (1, 9999) and m.LOCAL in (1, 9999)
order by
  dados.idModelo,
  dados.codigoEquipamento,
  dados.dataAbertura;
  1. Entidade "EQUIPAMENTO" e Tipo de Relatório "producao":
select
  e.SEQ_DB as idEquipamento,
  e.CODIGO as codigoEquipamento,
  m.SEQ_DB as idModelo,
  m.DESCRICAO as descricaoModelo,
  dados.dataAbertura,
  dados.dataFinal,
  codigoOperacao,
  descOperacao,
  produtiva,
  codigoOperador,
  nomeOperador,
  producao as tempoApontado,
  divisao
from (
  select
    eq.SEQ_DB as idEquipamento,
    eq.CODIGO as codigoEquipamento,
    cl.SEQ_DB as idClasse,
    mo.SEQ_DB as idModelo,
    mo.DESCRICAO as descricaoModelo,
    coalesce(atv.CODIGO, '') as codigoOperacao,
    coalesce(atv.DESCRICAO, '') as descOperacao,
    coalesce(atv.FLAG_PRODUTIVA, 0) as produtiva,
    coalesce(op.CRACHA, '') as codigoOperador,
    coalesce(op.NOME, '') as nomeOperador,
    se.SEQ_DB as idRegional,
    sum(pr.producao) as producao,
    concat(fz.CODIGO, '-', coalesce(tl.CODIGO, '')) as divisao,
    ap.INI_DH as dataAbertura,
    ap.FIM_DH as dataFinal
  from app_apontamento_maquina as ap
  inner join app_boletim_maquina bo on bo.SEQ_DB = ap.SEQ_DB_DEVICE_MASTER_SEQ_DB
  inner join app_equipamento eq on eq.SEQ_DB = bo.EQUIPAMENTO_SEQ_DB
  inner join app_modelo mo on mo.SEQ_DB = eq.MODELO_SEQ_DB
  inner join app_classe_operacional cl on cl.SEQ_DB = eq.CLASSE_OPERACIONAL_SEQ_DB
  inner join app_setor se on se.SEQ_DB = ap.SETOR_SEQ_DB
  left join app_atividade atv on atv.SEQ_DB = ap.ATIVIDADE_SEQ_DB
  left join app_operador op on op.SEQ_DB = bo.OPERADOR_SEQ_DB
  left join app_apontamento_maquina_producao pr on pr.SEQ_DB_DEVICE_MASTER_SEQ_DB = bo.SEQ_DB and pr.ATIVIDADE_SEQ_DB = atv.SEQ_DB
  left join app_fazenda fz on fz.SEQ_DB = ap.FAZENDA_SEQ_DB
  left join app_talhao tl on tl.SEQ_DB = pr.TALHAO_SEQ_DB
  where
    ap.ATIVO = 1 and ap.DELETED = 0 and ap.EMPRESA in (1, 9999) and ap.FILIAL in (1, 9999) and ap.LOCAL in (1, 9999)
    and ap.FIM_DH is not null
    and ap.INI_DH between '2019-01-23 00:00:00' and '2019-01-27 23:59:59'
    and date(ap.INI_DH) = date(ap.FIM_DH)
  group by
    idEquipamento,
    codigoEquipamento,
    idClasse,
    idModelo,
    descricaoModelo,
    ap.FIM_DH,
    ap.INI_DH,
    idRegional,
    codigoOperacao,
    descOperacao,
    produtiva,
    codigoOperador,
    nomeOperador,
    divisao
  union all
  select
    eq.SEQ_DB as idEquipamento,
    eq.CODIGO as codigoEquipamento,
    cl.SEQ_DB as idClasse,
    mo.SEQ_DB as idModelo,
    mo.DESCRICAO as descricaoModelo,
    coalesce(atv.CODIGO, '') as codigoOperacao,
    coalesce(atv.DESCRICAO, '') as descOperacao,
    coalesce(atv.FLAG_PRODUTIVA, 0) as produtiva,
    coalesce(op.CRACHA, '') as codigoOperador,
    coalesce(op.NOME, '') as nomeOperador,
    se.SEQ_DB as idRegional,
    sum(pr.producao) as producao,
    concat(fz.CODIGO, '-', coalesce(tl.CODIGO, '')) as divisao,
    ap.INI_DH as dataAbertura,
    concat(date(ap.INI_DH), ' 23:59:59') as dataFinal
  from app_apontamento_maquina as ap
  inner join app_boletim_maquina bo on bo.SEQ_DB = ap.SEQ_DB_DEVICE_MASTER_SEQ_DB
  inner join app_equipamento eq on eq.SEQ_DB = bo.EQUIPAMENTO_SEQ_DB
  inner join app_modelo mo on mo.SEQ_DB = eq.MODELO_SEQ_DB
  inner join app_classe_operacional cl on cl.SEQ_DB = eq.CLASSE_OPERACIONAL_SEQ_DB
  inner join app_setor se on se.SEQ_DB = ap.SETOR_SEQ_DB
  left join app_atividade atv on atv.SEQ_DB = ap.ATIVIDADE_SEQ_DB
  left join app_operador op on op.SEQ_DB = bo.OPERADOR_SEQ_DB
  left join app_apontamento_maquina_producao pr on pr.SEQ_DB_DEVICE_MASTER_SEQ_DB = bo.SEQ_DB and pr.ATIVIDADE_SEQ_DB = atv.SEQ_DB
  left join app_fazenda fz on fz.SEQ_DB = ap.FAZENDA_SEQ_DB
  left join app_talhao tl on tl.SEQ_DB = pr.TALHAO_SEQ_DB
  where
    ap.ATIVO = 1 and ap.DELETED = 0 and ap.EMPRESA in (1, 9999) and ap.FILIAL in (1, 9999) and ap.LOCAL in (1, 9999)
    and ap.FIM_DH is not null
    and (ap.INI_DH between '2019-01-23 00:00:00' and '2019-01-27 23:59:59' or ap.FIM_DH between '2019-01-23 00:00:00' and '2019-01-27 23:59:59')
    and ap.INI_DH >= '2019-01-23 00:00:00'
    and date(ap.INI_DH) < date(ap.FIM_DH)
  group by
    idEquipamento,
    codigoEquipamento,
    idClasse,
    idModelo,
    descricaoModelo,
    ap.FIM_DH,
    ap.INI_DH,
    idRegional,
    codigoOperacao,
    descOperacao,
    produtiva,
    codigoOperador,
    nomeOperador,
    divisao
  union all
  select
    eq.SEQ_DB as idEquipamento,
    eq.CODIGO as codigoEquipamento,
    cl.SEQ_DB as idClasse,
    mo.SEQ_DB as idModelo,
    mo.DESCRICAO as descricaoModelo,
    coalesce(atv.CODIGO, '') as codigoOperacao,
    coalesce(atv.DESCRICAO, '') as descOperacao,
    coalesce(atv.FLAG_PRODUTIVA, 0) as produtiva,
    coalesce(op.CRACHA, '') as codigoOperador,
    coalesce(op.NOME, '') as nomeOperador,
    se.SEQ_DB as idRegional,
    sum(pr.producao) as producao,
    concat(fz.CODIGO, '-', coalesce(tl.CODIGO, '')) as divisao,
    concat(date_add(date(ap.INI_DH), interval 1 day), ' 00:00:00') as dataAbertura,
    ap.FIM_DH as dataFinal
  from app_apontamento_maquina as ap
  inner join app_boletim_maquina bo on bo.SEQ_DB = ap.SEQ_DB_DEVICE_MASTER_SEQ_DB
  inner join app_equipamento eq on eq.SEQ_DB = bo.EQUIPAMENTO_SEQ_DB
  inner join app_modelo mo on mo.SEQ_DB = eq.MODELO_SEQ_DB
  inner join app_classe_operacional cl on cl.SEQ_DB = eq.CLASSE_OPERACIONAL_SEQ_DB
  inner join app_setor se on se.SEQ_DB = ap.SETOR_SEQ_DB
  left join app_atividade atv on atv.SEQ_DB = ap.ATIVIDADE_SEQ_DB
  left join app_operador op on op.SEQ_DB = bo.OPERADOR_SEQ_DB
  left join app_apontamento_maquina_producao pr on pr.SEQ_DB_DEVICE_MASTER_SEQ_DB = bo.SEQ_DB and pr.ATIVIDADE_SEQ_DB = atv.SEQ_DB
  left join app_fazenda fz on fz.SEQ_DB = ap.FAZENDA_SEQ_DB
  left join app_talhao tl on tl.SEQ_DB = pr.TALHAO_SEQ_DB
  where
    ap.ATIVO = 1 and ap.DELETED = 0 and ap.EMPRESA in (1, 9999) and ap.FILIAL in (1, 9999) and ap.LOCAL in (1, 9999)
    and ap.FIM_DH is not null
    and ap.INI_DH >= '2019-01-23 00:00:00'
    and ap.FIM_DH <= '2019-01-27 23:59:59'
    and date(ap.INI_DH) < date(ap.FIM_DH)
  group by
    idEquipamento,
    codigoEquipamento,
    idClasse,
    idModelo,
    descricaoModelo,
    ap.FIM_DH,
    ap.INI_DH,
    idRegional,
    codigoOperacao,
    descOperacao,
    produtiva,
    codigoOperador,
    nomeOperador,
    divisao
) dados
right join app_equipamento e on e.SEQ_DB = dados.idEquipamento
inner join app_classe_operacional c on e.CLASSE_OPERACIONAL_SEQ_DB = c.SEQ_DB
inner join app_modelo m on e.MODELO_SEQ_DB = m.SEQ_DB
where
  e.ATIVO = 1 and e.DELETED = 0 and e.EMPRESA in (1, 9999) and e.FILIAL in (1, 9999) and e.LOCAL in (1, 9999)
  and c.ATIVO = 1 and c.DELETED = 0 and c.EMPRESA in (1, 9999) and c.FILIAL in (1, 9999) and c.LOCAL in (1, 9999)
  and m.ATIVO = 1 and m.DELETED = 0 and m.EMPRESA in (1, 9999) and m.FILIAL in (1, 9999) and m.LOCAL in (1, 9999)
order by
  dados.idModelo,
  dados.codigoEquipamento,
  dados.dataAbertura;

Exemplo de um Mapa de Apontamento por de Mão de Obra

Caracteriza-se Mão de Obra nesse caso onde tem Encarregado e o mesmo aponta 1 ou mais operadores.

INSERT INTO nfs_mapa_generico_relatorio (SEQ_DB, MAPA_GENERICO_SEQ_DB, TIPO_RELATORIO, QUERY_STATEMENTS, DISPLAY_FIELDS, SUBQUERY_STATEMENTS, ENABLED) VALUES(1, 1, 'porcentagem', '{
    "SELECT": [
        "timestampdiff(second, cast(dataAbertura as datetime), cast(dataFinal as datetime)) as tempoApontado"
    ]
}', '{
    "MAIN": "tempoApontado",
    "TIPO": "percent",
    "DIVISAO": ""
}', NULL, 1);
INSERT INTO nfs_mapa_generico_relatorio (SEQ_DB, MAPA_GENERICO_SEQ_DB, TIPO_RELATORIO, QUERY_STATEMENTS, DISPLAY_FIELDS, SUBQUERY_STATEMENTS, ENABLED) VALUES(2, 1, 'horas', '{
    "SELECT": [
        "timestampdiff(second, cast(dataAbertura as datetime), cast(dataFinal as datetime)) as tempoApontado"
    ]
}', '{
    "MAIN": "tempoApontado",
    "TIPO": "absolute",
    "DIVISAO": ""
}', NULL, 1);


INSERT INTO nfs_mapa_generico (SEQ_DB, EMPRESA, FILIAL, `LOCAL`, TABLENAME, TITLE, MAIN_TABLE, DISPLAY_FIELDS, `OPTIONS`, REPORT_DAYS, REPORT_TYPES, QUERY_STATEMENTS, SUBQUERY_STATEMENTS, JORNADA_QUERY, FILTERS, LEGENDS, INDICATORS, ENABLED) VALUES(1, 1, 9999, 9999, 'EFETIVO_FUNCIONARIO', 'Mapa de Apontamentos de Mão de Obra', 'EFETIVO_FUNCIONARIO', '{
	"KEY": "idFuncionario",
	"TITLE": "crachaFuncionario",
	"FIELD_LINK": "idEncarregado",
	"DATAS": {
		"INI": "dataAbertura",
		"FIM": "dataFinal"
	},
	"COLUNAS": {
		"nomeFuncionario": "Funcionário",
		"cargoFuncionario": "Cargo"
	},
	"INDICADOR": "produtiva",
	"TOOLTIP": {
		"crachaFuncionario": "Crachá Funcionário",
		"nomeFuncionario": "Nome Funcionário",
		"nomeEncarregado": "Encarregado",
		"atividade": "Atividade/Perda"
	}
}', '{
	"JORNADA_PADRAO": 8
}', '{
	"5": {
		"label": "-5 dias",
		"value": 5,
		"selected": true
	},
	"10": {
		"label": "-10 dias",
		"value": 10,
		"selected": false
	},
	"15": {
		"label": "-15 dias",
		"value": 15,
		"selected": false
	}
}', '{
	"tipoPorcentagem": {
		"value": "porcentagem",
		"label": "Porcentagem",
		"selected": true
	},
	"tipoHoras": {
		"value": "horas",
		"label": "Horas",
		"selected": false
	}
}', '{
	"SELECT": [
		"dados.idApontamento",
		"car.SEQ_DB as idCargoFuncionario",
		"car.DESCRICAO as cargoFuncionario",
		"enc.SEQ_DB as idEncarregado",
		"ff.SEQ_DB as idFuncionario",
		"ff.CRACHA as crachaFuncionario",
		"ff.NOME as nomeFuncionario",
		"coalesce(enc.CRACHA, '') as crachaEncarregado",
		"coalesce(enc.NOME, '') as nomeEncarregado",
		"dados.atividade",
		"dados.produtiva",
		"dados.dataAbertura",
		"dados.dataFinal"
	],
	"FROM": [],
	"SUBQUERY": ["dados", "idFuncionario"],
	"JOIN": [
		"inner join app_efetivo_funcionario ff on ff.SEQ_DB = dados.idFuncionario",
		"inner join app_efetivo_funcionario enc on enc.SEQ_DB = dados.idEncarregado",
		"left join app_efetivo_funcao car on car.SEQ_DB = dados.idCargoFuncionario"
	],
	"WHERE": [
		"ff.ATIVO = 1 and ff.DELETED = 0 and ff.EMPRESA in (:empresa, 9999) and ff.FILIAL in (:filial, 9999) and ff.LOCAL in (:local, 9999)",
		"enc.ATIVO = 1 and enc.DELETED = 0 and enc.EMPRESA in (:empresa, 9999) and enc.FILIAL in (:filial, 9999) and enc.LOCAL in (:local, 9999)",
		"car.ATIVO = 1 and car.DELETED = 0 and car.EMPRESA in (:empresa, 9999) and car.FILIAL in (:filial, 9999) and car.LOCAL in (:local, 9999)"
	],
	"ORDER_BY": [
		"dados.dataAbertura",
		"nomeFuncionario"
	]
}', '{
	"SELECT": [
		"ap.SEQ_DB as idApontamento",
		"f.SEQ_DB as idFuncionario",
		"coalesce(f.CRACHA, '') as crachaFuncionario",
		"coalesce(f.NOME, '') as nomeFuncionario",
		"e.SEQ_DB as idEncarregado",
		"coalesce(e.CRACHA, '') as crachaEncarregado",
		"coalesce(e.NOME, '') as nomeEncarregado",
		"ca.SEQ_DB as idCargoFuncionario",
		"coalesce(ca.DESCRICAO, '') as cargoFuncionario",
		"if(ap.TIPO_APONTAMENTO = 1, 1, 0) produtiva",
		"case when (ap.OPER_SEQ_DB IS NULL) then coalesce(i.DESCRICAO, '') when (ap.OPER_SEQ_DB IS NOT NULL AND ap.INTERFERENCIA_SEQ_DB IS NOT NULL) then coalesce(i.DESCRICAO, '') else coalesce(ati.DESCRICAO, '') end as atividade"
	],
    	"FROM": [
		["app_mo_apt", "ap"]
	],
    	"JOIN": [
		"inner join app_mo_boletim bo on bo.SEQ_DB = ap.SEQ_DB_DEVICE_MASTER_SEQ_DB ",
		"inner join app_efetivo_funcionario f ON ap.OPERADOR_SEQ_DB = f.SEQ_DB",
		"inner join app_efetivo_funcionario e ON ap.EFETIVO_FUNCIONARIO_SEQ_DB = e.SEQ_DB",
		"left join app_oper ati ON ap.OPER_SEQ_DB = ati.SEQ_DB",
		"left join app_interferencia i ON ap.INTERFERENCIA_SEQ_DB = i.SEQ_DB",
		"left join app_efetivo_funcao ca ON f.EFETIVO_FUNCAO_SEQ_DB = ca.SEQ_DB"
	],
    	"WHERE": [
		"ap.ATIVO = 1 and ap.DELETED = 0 and ap.EMPRESA in (:empresa, 9999) and ap.FILIAL in (:filial, 9999) and ap.LOCAL in (:local, 9999) and ap.FIM_DH is not null"
	],
    	"GROUP_BY": [
		"idApontamento",
		"idFuncionario",
		"crachaFuncionario",
		"nomeFuncionario",
		"idCargoFuncionario",
		"cargoFuncionario",
		"idEncarregado",
		"crachaEncarregado",
		"nomeEncarregado",
		"atividade",
		"ap.TIPO_APONTAMENTO",
		"ap.FIM_DH",
		"ap.INI_DH"
	],
	"UNION": [{
		"SELECT": [
			"ap.INI_DH as dataAbertura",
			"ap.FIM_DH as dataFinal"
		],
		"WHERE": [
			"ap.INI_DH between concat(:de, ' 00:00:00') and concat(:ate, ' 23:59:59')",
			"date(ap.INI_DH) = date(ap.FIM_DH)"
		]
	},{
		"SELECT": [
			"ap.INI_DH as dataAbertura",
			"concat(date(ap.INI_DH), ' 23:59:59') as dataFinal"
		],
		"WHERE": [
      "(ap.INI_DH between concat(:de, ' 00:00:00') and concat(:ate, ' 23:59:59') or ap.FIM_DH between concat(:de, ' 00:00:00') and concat(:ate, ' 23:59:59'))",
      "ap.INI_DH >= concat(:de, ' 00:00:00')",
			"date(ap.INI_DH) < date(ap.FIM_DH)"
		]
	},{
		"SELECT": [
			"concat(date_add(date(ap.INI_DH), interval 1 day), '' 00:00:00'') as dataAbertura",
			"ap.FIM_DH as dataFinal"
		],
		"WHERE": [
     	"ap.INI_DH >= concat(:de, ' 00:00:00')",
      "ap.FIM_DH <= concat(:ate, ' 23:59:59')",
			"date(ap.INI_DH) < date(ap.FIM_DH)"
		]
	}]
}', '{}', '{
	"efetivo_funcionario": {
		"label": "Funcionário",
		"query_alias": "ff",
		"subquery_alias": "f",
		"id": "SEQ_DB",
		"descricao": "NOME",
		"multiple": true,
		"subfilter": ""
	},
	"efetivo_funcao": {
		"label": "Cargo",
		"query_alias": "car",
		"subquery_alias": "ca",
		"id": "SEQ_DB",
		"descricao": "DESCRICAO",
		"multiple": true,
		"subfilter": "funcionario"
	}
}', '{
	"zero": {
		"label": "0%",
		"color": "#FF5050",
		"eval": "[percent] == 0"
	},
	"insatisfatorio": {
		"label": "> 0%",
		"color": "#E59400",
		"eval": "[percent] > 0 && [percent] < 50"
	},
	"satisfatorio": {
		"label": ">= 50%",
		"color": "#ffff00",
		"eval": "[percent] >= 50 && [percent] < 90"
	},
	"otimo": {
		"label": ">= 90%",
		"color": "#92D050",
		"eval": "[percent] >= 90"
	}
}', '{
    "produtiva": {
        "value": 1,
        "label": "Produtiva",
        "color": "#92D050"
    },
    "improdutiva": {
        "value": 0,
        "label": "Improdutiva",
        "color": "#FF5050"
    }
}', 1);

Resultado em SQL:

Prestar atenção no WHERE que estão filtras pela empresa, filial, local, período e funcionario (808) da civilmaster-mo;

select
	dados.idApontamento,
	car.SEQ_DB as idCargoFuncionario,
	car.DESCRICAO as cargoFuncionario,
	enc.SEQ_DB as idEncarregado,
	ff.SEQ_DB as idFuncionario,
	ff.CRACHA as crachaFuncionario,
	ff.NOME as nomeFuncionario,
	coalesce(enc.CRACHA, '') as crachaEncarregado,
	coalesce(enc.NOME, '') as nomeEncarregado,
	dados.atividade,
	dados.dataAbertura,
	dados.dataFinal,
	timestampdiff(second,
	cast(dataAbertura as datetime),
	cast(dataFinal as datetime)) as tempoApontado
from
	(
	select
		ap.SEQ_DB as idApontamento,
		f.SEQ_DB as idFuncionario,
		coalesce(f.CRACHA, '') as crachaFuncionario,
		coalesce(f.NOME, '') as nomeFuncionario,
		e.SEQ_DB as idEncarregado,
		coalesce(e.CRACHA, '') as crachaEncarregado,
		coalesce(e.NOME, '') as nomeEncarregado,
		ca.SEQ_DB as idCargoFuncionario,
		coalesce(ca.DESCRICAO, '') as cargoFuncionario,
		case
			when (ap.OPER_SEQ_DB is null) then coalesce(i.DESCRICAO, '')
			when (ap.OPER_SEQ_DB is not null
			and ap.INTERFERENCIA_SEQ_DB is not null) then coalesce(i.DESCRICAO, '')
			else coalesce(ati.DESCRICAO, '')
		end as atividade,
		ap.INI_DH as dataAbertura,
		ap.FIM_DH as dataFinal
	from app_mo_apt as ap
	inner join app_mo_boletim bo on bo.SEQ_DB = ap.SEQ_DB_DEVICE_MASTER_SEQ_DB
	inner join app_efetivo_funcionario f on ap.OPERADOR_SEQ_DB = f.SEQ_DB
	inner join app_efetivo_funcionario e on ap.EFETIVO_FUNCIONARIO_SEQ_DB = e.SEQ_DB
	left join app_oper ati on ap.OPER_SEQ_DB = ati.SEQ_DB
	left join app_interferencia i on ap.INTERFERENCIA_SEQ_DB = i.SEQ_DB
	left join app_efetivo_funcao ca on f.EFETIVO_FUNCAO_SEQ_DB = ca.SEQ_DB
	where
		ap.ATIVO = 1
		and ap.DELETED = 0
		and ap.EMPRESA in (1, 9999)
		and ap.FILIAL in (1, 9999)
		and ap.LOCAL in (9, 9999)
		and ap.FIM_DH is not null
		and f.SEQ_DB in (880)
		and ap.INI_DH between '2023-03-10 00:00:00' and '2023-03-14 23:59:59'
		and date(ap.INI_DH) = date(ap.FIM_DH)
	group by
		idApontamento,
		idFuncionario,
		crachaFuncionario,
		nomeFuncionario,
		idCargoFuncionario,
		cargoFuncionario,
		idEncarregado,
		crachaEncarregado,
		nomeEncarregado,
		atividade,
		ap.FIM_DH,
		ap.INI_DH
union all
	select
		ap.SEQ_DB as idApontamento,
		f.SEQ_DB as idFuncionario,
		coalesce(f.CRACHA, '') as crachaFuncionario,
		coalesce(f.NOME, '') as nomeFuncionario,
		e.SEQ_DB as idEncarregado,
		coalesce(e.CRACHA, '') as crachaEncarregado,
		coalesce(e.NOME, '') as nomeEncarregado,
		ca.SEQ_DB as idCargoFuncionario,
		coalesce(ca.DESCRICAO, '') as cargoFuncionario,
		case
			when (ap.OPER_SEQ_DB is null) then coalesce(i.DESCRICAO, '')
			when (ap.OPER_SEQ_DB is not null
				and ap.INTERFERENCIA_SEQ_DB is not null) then coalesce(i.DESCRICAO, '')
			else coalesce(ati.DESCRICAO, '')
		end as atividade,
		ap.INI_DH as dataAbertura,
		concat(date(ap.INI_DH), ' 23:59:59') as dataFinal
	from app_mo_apt as ap
	inner join app_mo_boletim bo on bo.SEQ_DB = ap.SEQ_DB_DEVICE_MASTER_SEQ_DB
	inner join app_efetivo_funcionario f on ap.OPERADOR_SEQ_DB = f.SEQ_DB
	inner join app_efetivo_funcionario e on ap.EFETIVO_FUNCIONARIO_SEQ_DB = e.SEQ_DB
	left join app_oper ati on ap.OPER_SEQ_DB = ati.SEQ_DB
	left join app_interferencia i on ap.INTERFERENCIA_SEQ_DB = i.SEQ_DB
	left join app_efetivo_funcao ca on f.EFETIVO_FUNCAO_SEQ_DB = ca.SEQ_DB
	where
		ap.ATIVO = 1
		and ap.DELETED = 0
		and ap.EMPRESA in (1, 9999)
		and ap.FILIAL in (1, 9999)
		and ap.LOCAL in (9, 9999)
		and ap.FIM_DH is not null
		and f.SEQ_DB in (880)
		and (ap.INI_DH between '2023-03-10 00:00:00' and '2023-03-14 23:59:59'
			or ap.FIM_DH between '2023-03-10 00:00:00' and '2023-03-14 23:59:59')
		and ap.INI_DH >= '2023-03-10 23:59:59'
		and date(ap.INI_DH) < date(ap.FIM_DH)
	group by
		idApontamento,
		idFuncionario,
		crachaFuncionario,
		nomeFuncionario,
		idCargoFuncionario,
		cargoFuncionario,
		idEncarregado,
		crachaEncarregado,
		nomeEncarregado,
		atividade,
		ap.FIM_DH,
		ap.INI_DH
union all
	select
		ap.SEQ_DB as idApontamento,
		f.SEQ_DB as idFuncionario,
		coalesce(f.CRACHA, '') as crachaFuncionario,
		coalesce(f.NOME, '') as nomeFuncionario,
		e.SEQ_DB as idEncarregado,
		coalesce(e.CRACHA, '') as crachaEncarregado,
		coalesce(e.NOME, '') as nomeEncarregado,
		ca.SEQ_DB as idCargoFuncionario,
		coalesce(ca.DESCRICAO, '') as cargoFuncionario,
		case
			when (ap.OPER_SEQ_DB is null) then coalesce(i.DESCRICAO, '')
			when (ap.OPER_SEQ_DB is not null
				and ap.INTERFERENCIA_SEQ_DB is not null) then coalesce(i.DESCRICAO, '')
			else coalesce(ati.DESCRICAO, '')
		end as atividade,
		concat(date_add(date(ap.INI_DH), interval 1 day), ' 00:00:00') as dataAbertura,
		ap.FIM_DH as dataFinal
	from app_mo_apt as ap
	inner join app_mo_boletim bo on bo.SEQ_DB = ap.SEQ_DB_DEVICE_MASTER_SEQ_DB
	inner join app_efetivo_funcionario f on ap.OPERADOR_SEQ_DB = f.SEQ_DB
	inner join app_efetivo_funcionario e on ap.EFETIVO_FUNCIONARIO_SEQ_DB = e.SEQ_DB
	left join app_oper ati on ap.OPER_SEQ_DB = ati.SEQ_DB
	left join app_interferencia i on ap.INTERFERENCIA_SEQ_DB = i.SEQ_DB
	left join app_efetivo_funcao ca on f.EFETIVO_FUNCAO_SEQ_DB = ca.SEQ_DB
	where
		ap.ATIVO = 1
		and ap.DELETED = 0
		and ap.EMPRESA in (1, 9999)
		and ap.FILIAL in (1, 9999)
		and ap.LOCAL in (9, 9999)
		and ap.FIM_DH is not null
		and f.SEQ_DB in (880)
		and ap.INI_DH >= '2023-03-10 00:00:00'
		and ap.FIM_DH <= '2023-03-14 23:59:59'
		and date(ap.INI_DH) < date(ap.FIM_DH)
	group by
		idApontamento,
		idFuncionario,
		crachaFuncionario,
		nomeFuncionario,
		idCargoFuncionario,
		cargoFuncionario,
		idEncarregado,
		crachaEncarregado,
		nomeEncarregado,
		atividade
) dados
inner join app_efetivo_funcionario ff on ff.SEQ_DB = dados.idFuncionario
inner join app_efetivo_funcionario enc on enc.SEQ_DB = dados.idEncarregado
left join app_efetivo_funcao car on car.SEQ_DB = dados.idCargoFuncionario
where
	ff.ATIVO = 1
	and ff.DELETED = 0
	and ff.EMPRESA in (1, 9999)
	and ff.FILIAL in (1, 9999)
	and ff.LOCAL in (9, 9999)
	and enc.ATIVO = 1
	and enc.DELETED = 0
	and enc.EMPRESA in (1, 9999)
	and enc.FILIAL in (1, 9999)
	and enc.LOCAL in (9, 9999)
	and car.ATIVO = 1
	and car.DELETED = 0
	and car.EMPRESA in (1, 9999)
	and car.FILIAL in (1, 9999)
	and car.LOCAL in (9, 9999)
	and ((ff.SEQ_DB in (880)) or (dados.idFuncionario in (880)))
order by
	dados.dataAbertura,
	nomeFuncionario

Definindo cor e texto dos indicadores

Através dos ALIAS indicatorColor e indicatorLegend configurados ao montar o mapa, pode ser especificado qual a cor e texto da legenda:

1. Alterando as SUBQUERY_STATEMENTS

Configuração de cor da legenda subquery statements
  • 1 - Faço o inner join da tabela grupo atividades
  • 2 - Retorno no nome do grupo como indicatorLegend e a cor do grupo como indicatorColor

2. Configuração da QUERY_STATEMENTS

Após a definição dos aliases na SUBQUERY_STATEMENTS, basta trazer o resultado na QUERY para que os efeitos sejam aplicados no mapa de apontamentos

Configuração de cor da legenda query statements

Neste caso criei uma coluna da tabela de grupo de atividade onde defino a cor

Grupo de atividades e definição das cores

Resultado:

Mapa de apontamentos com as novas cores

3. Extras

Criação da coluna de cores no grupo de atividades:

INSERT INTO nfs_core_ds_tabela_campo(TABELA_NOME, NOME, SEQ, SYS, SEND_XMOVA, GRID, GRID_MOBILE, DESCRICAO, DESCRICAO_RESUMIDA, TIPO, OBRIGATORIO, TAMANHO, TAMANHO_DECIMAL, MASCARA, INSERT_UPDATE, DISABLED, HINT, LINK, VALIDACAO, OPCOES, VALOR_DEFAULT, VALIDACAO_VIEW, FILTRO_VIEW, TOOLTIP_MESSAGE, PROPERTIES, CONFIG)
VALUES('GRUPO_ATIVIDADE', 'COR', 4, 0, 1, 1, 1, 'Cor', 'Cor', 'COLOR', NULL, NULL, NULL, NULL, 'IU', '0', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);