let
Fato_Jornada_Comparacao = let
// =========================================================
// FONTE
// =========================================================
Jornada = Fato_Jornada_Esperada,
Intervalos = Fato_Intervalos_Dia,
Ajustes = Fato_Ajustes_Dia,
// =========================================================
// PADRONIZAÇÃO DAS CHAVES
// =========================================================
JornadaTipos = Table.TransformColumns(
Jornada,
{
{"FuncionarioID", each Int64.From(_), Int64.Type},
{"Data", each Date.From(_), type date}
}
),
IntervalosTipos = Table.TransformColumns(
Intervalos,
{
{"FuncionarioID", each Int64.From(_), Int64.Type},
{"DataJornada", each Date.From(_), type date}
}
),
AjustesTipos = Table.TransformColumns(
Ajustes,
{
{"FuncionarioID", each Int64.From(_), Int64.Type},
{"Data", each Date.From(_), type date}
}
),
// =========================================================
// MERGE DOS INTERVALOS REAIS
// =========================================================
MesclarIntervalos = Table.NestedJoin(
JornadaTipos,
{"FuncionarioID", "Data"},
IntervalosTipos,
{"FuncionarioID", "DataJornada"},
"DadosIntervalos",
JoinKind.LeftOuter
),
ExpandirIntervalos = Table.ExpandTableColumn(
MesclarIntervalos,
"DadosIntervalos",
{
"QuantidadeIntervalos",
"HorasTrabalhadas",
"Entrada1",
"Saida1",
"Entrada2",
"Saida2",
"Entrada3",
"Saida3",
"Entrada4",
"Saida4",
"QuantidadeEntradas",
"QuantidadeSaidas",
"Intervalos"
},
{
"QuantidadeIntervalos",
"HorasTrabalhadas",
"Entrada1Real",
"Saida1Real",
"Entrada2Real",
"Saida2Real",
"Entrada3Real",
"Saida3Real",
"Entrada4Real",
"Saida4Real",
"QuantidadeEntradas",
"QuantidadeSaidas",
"Intervalos"
}
),
// =========================================================
// MERGE DOS AJUSTES
// =========================================================
MesclarAjustes = Table.NestedJoin(
ExpandirIntervalos,
{"FuncionarioID", "Data"},
AjustesTipos,
{"FuncionarioID", "Data"},
"DadosAjustes",
JoinKind.LeftOuter
),
ExpandirAjustes = Table.ExpandTableColumn(
MesclarAjustes,
"DadosAjustes",
{
"QuantidadeAjustes",
"TemAjusteAbonado",
"TemAjusteDiaCompleto",
"TemAjusteContaComoFalta",
"HorasAbonadasParciais",
"HorasFaltaParciais",
"MotivosAjustes",
"AjustesDia"
},
{
"QuantidadeAjustes",
"TemAjusteAbonado",
"TemAjusteDiaCompleto",
"TemAjusteContaComoFalta",
"HorasAbonadasParciais",
"HorasFaltaParciais",
"MotivosAjustes",
"AjustesDia"
}
),
// =========================================================
// MERGE DOS FERIADOS
// =========================================================
MesclarFeriados = Table.NestedJoin(
ExpandirAjustes,
{"Data"},
Dim_Feriados,
{"Data"},
"DadosFeriado",
JoinKind.LeftOuter
),
ExpandirFeriado = Table.ExpandTableColumn(
MesclarFeriados,
"DadosFeriado",
{
"FeriadoID",
"NomeFeriado"
},
{
"FeriadoID",
"NomeFeriado"
}
),
IdentificarFeriado = Table.AddColumn(
ExpandirFeriado,
"Feriado",
each [FeriadoID] <> null,
type logical
),
// =========================================================
// VALORES PADRÃO
// =========================================================
Quantidades = Table.TransformColumns(
IdentificarFeriado,
{
{
"QuantidadeIntervalos",
each if _ = null then 0 else _,
Int64.Type
},
{
"QuantidadeEntradas",
each if _ = null then 0 else _,
Int64.Type
},
{
"QuantidadeSaidas",
each if _ = null then 0 else _,
Int64.Type
},
{
"QuantidadeAjustes",
each if _ = null then 0 else _,
Int64.Type
},
{
"HorasTrabalhadas",
each if _ = null then 0 else _,
type number
}
}
),
// =========================================================
// QUANTIDADE DE BATIDAS
// =========================================================
QuantidadeBatidas = Table.AddColumn(
Quantidades,
"QuantidadeBatidas",
each
[QuantidadeEntradas] + [QuantidadeSaidas],
Int64.Type
),
BatidasImpares = Table.AddColumn(
QuantidadeBatidas,
"BatidasImpares",
each
Number.Mod([QuantidadeBatidas], 2) <> 0,
type logical
),
BatidasDiferentes4 = Table.AddColumn(
BatidasImpares,
"BatidasDiferentes4",
each
let
Esperadas =
if [Entrada1Esperada] <> null and [Saida1Esperada] <> null then
if [Entrada2Esperada] <> null and [Saida2Esperada] <> null then
4
else
2
else
0
in
[QuantidadeBatidas] <> Esperadas,
type logical
),
SituacaoBatidas = Table.AddColumn(
BatidasDiferentes4,
"SituacaoBatidas",
each
let
Esperadas =
if [Entrada1Esperada] <> null and [Saida1Esperada] <> null then
if [Entrada2Esperada] <> null and [Saida2Esperada] <> null then
4
else
2
else
0
in
if
[TemAjusteContaComoFalta] = true
and [QuantidadeBatidas] = 0
then
"Nenhum registro"
else if Esperadas = 0 and [QuantidadeBatidas] = 0 then
"Nenhum registro"
else if Esperadas = 0 and [QuantidadeBatidas] > 0 then
"Trabalho sem jornada prevista"
else if [QuantidadeBatidas] = Esperadas then
"Quantidade correta"
else if [QuantidadeBatidas] < Esperadas then
"Quantidade incompleta"
else if [BatidasImpares] = true then
"Quantidade ímpar de registros"
else
"Quantidade acima do esperado",
type text
),
// =========================================================
// FUNÇÃO - COBERTURA DE AJUSTE
//
// Verifica quanto do período esperado é coberto
// por ajustes da API.
//
// Ajustes que contam como falta não são considerados
// como cobertura.
// =========================================================
VerificarCoberturaAjuste = (
InicioEsperado as nullable datetime,
FimEsperado as nullable datetime,
ListaAjustes as nullable table
) as record =>
let
ResultadoVazio = [
CoberturaSegundos = 0,
CoberturaCompleta = false,
Motivos = null
],
Resultado =
if
InicioEsperado = null
or FimEsperado = null
or ListaAjustes = null
or Table.RowCount(ListaAjustes) = 0
then
ResultadoVazio
else
let
AjustesValidos = Table.SelectRows(
ListaAjustes,
each
[DataInicio] <> null
and [DataFim] <> null
and [AjusteContaComoFalta] <> true
),
AjustesComSobreposicao =
Table.AddColumn(
AjustesValidos,
"SobreposicaoSegundos",
each
let
InicioAjuste =
if [AjusteDiaCompleto] = true
then
DateTime.From(
Date.From(InicioEsperado)
)
else
[DataInicio],
FimAjuste =
if [AjusteDiaCompleto] = true
then
DateTime.From(
Date.AddDays(
Date.From(InicioEsperado),
1
)
)
else
[DataFim],
Inicio =
if InicioAjuste > InicioEsperado
then InicioAjuste
else InicioEsperado,
Fim =
if FimAjuste < FimEsperado
then FimAjuste
else FimEsperado
in
if Fim > Inicio
then
Duration.TotalSeconds(
Fim - Inicio
)
else
0,
type number
),
Cobertura =
List.Sum(
List.RemoveNulls(
AjustesComSobreposicao[
SobreposicaoSegundos
]
)
),
DuracaoEsperada =
Duration.TotalSeconds(
FimEsperado - InicioEsperado
),
Motivos =
let
AjustesComCobertura =
Table.SelectRows(
AjustesComSobreposicao,
each [SobreposicaoSegundos] > 0
)
in
if Table.RowCount(AjustesComCobertura) = 0 then
null
else
Text.Combine(
List.Distinct(
List.RemoveNulls(
AjustesComCobertura[DescricaoMotivo]
)
),
" | "
),
CoberturaCompleta =
Cobertura >= DuracaoEsperada - 60
in
[
CoberturaSegundos = Cobertura,
CoberturaCompleta = CoberturaCompleta,
Motivos = Motivos
]
in
Resultado,
// =========================================================
// COBERTURA DA JANELA 1
// =========================================================
CoberturaJanela1 = Table.AddColumn(
SituacaoBatidas,
"CoberturaJanela1",
each
VerificarCoberturaAjuste(
[Entrada1Esperada],
[Saida1Esperada],
[AjustesDia]
),
type record
),
ExpandirCoberturaJanela1 = Table.ExpandRecordColumn(
CoberturaJanela1,
"CoberturaJanela1",
{
"CoberturaSegundos",
"CoberturaCompleta",
"Motivos"
},
{
"Janela1CoberturaAjusteSegundos",
"Janela1AjusteCobreTudo",
"Janela1MotivosAjuste"
}
),
// =========================================================
// COBERTURA DA JANELA 2
// =========================================================
CoberturaJanela2 = Table.AddColumn(
ExpandirCoberturaJanela1,
"CoberturaJanela2",
each
VerificarCoberturaAjuste(
[Entrada2Esperada],
[Saida2Esperada],
[AjustesDia]
),
type record
),
ExpandirCoberturaJanela2 = Table.ExpandRecordColumn(
CoberturaJanela2,
"CoberturaJanela2",
{
"CoberturaSegundos",
"CoberturaCompleta",
"Motivos"
},
{
"Janela2CoberturaAjusteSegundos",
"Janela2AjusteCobreTudo",
"Janela2MotivosAjuste"
}
),
// =========================================================
// COBERTURA GERAL DOS AJUSTES
// =========================================================
AjusteCobreJornada = Table.AddColumn(
ExpandirCoberturaJanela2,
"AjusteCobreJornada",
each
[Janela1AjusteCobreTudo] = true
or [Janela2AjusteCobreTudo] = true,
type logical
),
// =========================================================
// JORNADA PREVISTA
// =========================================================
JornadaPrevista = Table.AddColumn(
AjusteCobreJornada,
"JornadaPrevista",
each
[Entrada1Esperada] <> null
and [Saida1Esperada] <> null,
type logical
),
// =========================================================
// QUANTIDADE DE BATIDAS ESPERADAS
// =========================================================
QuantidadeBatidasEsperadas = Table.AddColumn(
JornadaPrevista,
"QuantidadeBatidasEsperadas",
each
if [Entrada1Esperada] <> null and [Saida1Esperada] <> null then
if [Entrada2Esperada] <> null and [Saida2Esperada] <> null then
4
else
2
else
0,
Int64.Type
),
// =========================================================
// BATIDAS INCOMPLETAS
// =========================================================
BatidasIncompletas = Table.AddColumn(
QuantidadeBatidasEsperadas,
"BatidasIncompletas",
each
if [QuantidadeBatidas] = 0 then
false
else if [QuantidadeBatidas] < [QuantidadeBatidasEsperadas] then
true
else
false,
type logical
),
// =========================================================
// BATIDAS ACIMA DO ESPERADO
// =========================================================
BatidasAcimaEsperado = Table.AddColumn(
BatidasIncompletas,
"BatidasAcimaEsperado",
each
if [QuantidadeBatidasEsperadas] = null then
false
else
[QuantidadeBatidas] > [QuantidadeBatidasEsperadas],
type logical
),
// =========================================================
// HORAS PREVISTAS
// =========================================================
HorasEsperadas = Table.AddColumn(
BatidasAcimaEsperado,
"HorasEsperadas",
each
if [Feriado] = true then
0
else
let
Entrada1 = [Entrada1Esperada],
Saida1 = [Saida1Esperada],
Entrada2 = [Entrada2Esperada],
Saida2 = [Saida2Esperada],
Jornada1 =
if Entrada1 <> null and Saida1 <> null then
let
Inicio =
#datetime(
2000, 1, 1,
Time.Hour(Entrada1),
Time.Minute(Entrada1),
Time.Second(Entrada1)
),
FimBase =
#datetime(
2000, 1, 1,
Time.Hour(Saida1),
Time.Minute(Saida1),
Time.Second(Saida1)
),
Fim =
if FimBase < Inicio then
FimBase + #duration(1, 0, 0, 0)
else
FimBase
in
Duration.TotalSeconds(Fim - Inicio)
else
0,
Jornada2 =
if Entrada2 <> null and Saida2 <> null then
let
Inicio =
#datetime(
2000, 1, 1,
Time.Hour(Entrada2),
Time.Minute(Entrada2),
Time.Second(Entrada2)
),
FimBase =
#datetime(
2000, 1, 1,
Time.Hour(Saida2),
Time.Minute(Saida2),
Time.Second(Saida2)
),
Fim =
if FimBase < Inicio then
FimBase + #duration(1, 0, 0, 0)
else
FimBase
in
Duration.TotalSeconds(Fim - Inicio)
else
0
in
(Jornada1 + Jornada2) / 3600,
type number
),
// =========================================================
// HORAS ABONADAS
//
// Usa a cobertura efetivamente calculada pelos ajustes.
//
// Isso é importante porque o mesmo período usado para
// determinar a cobertura do ajuste será descontado da
// jornada prevista.
// =========================================================
HorasAbonadas = Table.AddColumn(
HorasEsperadas,
"HorasAbonadas",
each
if [Feriado] = true then
0
else if [TemAjusteAbonado] <> true then
0
else if
[TemAjusteDiaCompleto] = true
and [TemAjusteContaComoFalta] = false
then
[HorasEsperadas]
else if [HorasAbonadasParciais] = null then
0
else
[HorasAbonadasParciais],
type number
),
// =========================================================
// HORAS FALTA
// =========================================================
HorasFalta = Table.AddColumn(
HorasAbonadas,
"HorasFalta",
each
if [Feriado] = true then
0
else if [TemAjusteContaComoFalta] = true then
if [QuantidadeBatidas] = 0 then
[HorasEsperadas]
else if [HorasFaltaParciais] = null then
0
else
[HorasFaltaParciais]
else
0,
type number
),
// =========================================================
// HORAS PREVISTAS AJUSTADAS
// =========================================================
HorasPrevistasAjustadas = Table.AddColumn(
HorasFalta,
"HorasPrevistasAjustadas",
each
if [Feriado] = true then
0
else if
[TemAjusteDiaCompleto] = true
and [TemAjusteAbonado] = true
and [TemAjusteContaComoFalta] = false
then
0
else if [HorasEsperadas] - [HorasAbonadas] < 0 then
0
else
[HorasEsperadas] - [HorasAbonadas],
type number
),
// =========================================================
// HORAS FICTAS - HORA NOTURNA REDUZIDA
//
// Período noturno: 22:00 até 05:00.
//
// A função considera tanto:
// - 22:00 até 00:00 do próprio dia
// - 00:00 até 05:00 do dia seguinte
//
// Isso também permite reconhecer trabalho entre 00:00 e
// 05:00 mesmo quando a jornada começou no dia anterior.
// =========================================================
CalcularHorasFictas =
(Entrada as nullable datetime, Saida as nullable datetime) as number =>
let
Resultado =
if Entrada = null or Saida = null then
0
else
let
// Se a saída estiver cronologicamente
// antes da entrada, considera o dia seguinte.
SaidaAjustada =
if Saida < Entrada then
Saida + #duration(1,0,0,0)
else
Saida,
DataEntrada =
Date.From(Entrada),
// =====================================================
// JANELA NOTURNA DO DIA DA ENTRADA
// 22:00 até 05:00 do dia seguinte
// =====================================================
InicioNoturnoAtual =
DateTime.From(DataEntrada)
+ #duration(0,22,0,0),
FimNoturnoAtual =
DateTime.From(
Date.AddDays(DataEntrada, 1)
)
+ #duration(0,5,0,0),
InicioSobreposicaoAtual =
if Entrada > InicioNoturnoAtual then
Entrada
else
InicioNoturnoAtual,
FimSobreposicaoAtual =
if SaidaAjustada < FimNoturnoAtual then
SaidaAjustada
else
FimNoturnoAtual,
MinutosNoturnosAtual =
if FimSobreposicaoAtual > InicioSobreposicaoAtual then
Duration.TotalMinutes(
FimSobreposicaoAtual
- InicioSobreposicaoAtual
)
else
0,
// =====================================================
// JANELA NOTURNA DO DIA ANTERIOR
// 22:00 do dia anterior até 05:00 do dia da entrada
//
// Necessária para casos como:
// 00:01 → 07:00
// =====================================================
DataAnterior =
Date.AddDays(
DataEntrada,
-1
),
InicioNoturnoAnterior =
DateTime.From(DataAnterior)
+ #duration(0,22,0,0),
FimNoturnoAnterior =
DateTime.From(DataEntrada)
+ #duration(0,5,0,0),
InicioSobreposicaoAnterior =
if Entrada > InicioNoturnoAnterior then
Entrada
else
InicioNoturnoAnterior,
FimSobreposicaoAnterior =
if SaidaAjustada < FimNoturnoAnterior then
SaidaAjustada
else
FimNoturnoAnterior,
MinutosNoturnosAnterior =
if FimSobreposicaoAnterior > InicioSobreposicaoAnterior then
Duration.TotalMinutes(
FimSobreposicaoAnterior
- InicioSobreposicaoAnterior
)
else
0,
// Soma das duas possíveis janelas noturnas
MinutosNoturnos =
MinutosNoturnosAtual
+ MinutosNoturnosAnterior,
// 60 minutos reais = 52,5 minutos fictos.
// Acréscimo = 60 / 52,5 - 1
MinutosFictos =
Number.RoundDown(
MinutosNoturnos *
((60 / 52.5) - 1),
0
),
HorasFictas =
MinutosFictos / 60
in
HorasFictas
in
Resultado,
HorasFictasCalculadas =
Table.AddColumn(
HorasPrevistasAjustadas,
"HorasFictas",
each
if [Intervalos] = null then
0
else
let
RegistrosIntervalos =
Table.ToRecords([Intervalos]),
FictasPorIntervalo =
List.Transform(
RegistrosIntervalos,
each
CalcularHorasFictas(
_[Entrada],
_[Saida]
)
),
TotalHorasFictas =
List.Sum(
List.RemoveNulls(
FictasPorIntervalo
)
)
in
TotalHorasFictas,
type number
),
// =========================================================
// FIM DE SEMANA - TRABALHO REALIZADO
// =========================================================
TrabalhoFimDeSemana = Table.AddColumn(
HorasFictasCalculadas,
"TrabalhoFimDeSemana",
each
(
[DiaSemana] = 1
or [DiaSemana] = 7
)
and [QuantidadeBatidas] > 0,
type logical
),
FimSemanaFormatacao = Table.AddColumn(
TrabalhoFimDeSemana,
"FimSemanaFormatacao",
each if [TrabalhoFimDeSemana] = true then 1 else 0,
Int64.Type
),
// =========================================================
// SALDO DA JORNADA
//
// Mantém o saldo baseado na jornada real da escala.
// Não utilizar este saldo diretamente para determinar
// atraso/hora extra, pois existem escalas de 08:29.
// =========================================================
SaldoHoras = Table.AddColumn(
FimSemanaFormatacao,
"SaldoHoras",
each
if [TrabalhoFimDeSemana] = true
and [HorasTrabalhadas] <> null
then
Number.Round(
[HorasTrabalhadas]
+ [HorasFictas],
6
)
else if [JornadaPrevista] = true
and [HorasTrabalhadas] <> null
then
Number.Round(
[HorasTrabalhadas]
+ [HorasFictas]
- [HorasPrevistasAjustadas],
6
)
else
null,
type number
),
// =========================================================
// BASE DE CONTROLE DE ATRASO / HORA EXTRA
//
// REGRA ESPECÍFICA:
// Para jornadas de 08:29, o controle de atraso/hora extra
// utiliza 08:48 como jornada de referência.
//
// Para todas as demais jornadas, mantém a jornada
// atualmente utilizada pelo modelo.
// =========================================================
HorasBaseControle = Table.AddColumn(
SaldoHoras,
"HorasBaseControle",
each
if [TrabalhoFimDeSemana] = true then
0
else if [JornadaPrevista] <> true then
null
else if [Feriado] = true then
0
else if
[TemAjusteDiaCompleto] = true
and [TemAjusteAbonado] = true
and [TemAjusteContaComoFalta] <> true
then
0
else
let
JornadaMinutos =
Number.Round(
[HorasEsperadas] * 60,
0
),
JornadaEh0829 =
JornadaMinutos = 509,
Base =
if JornadaEh0829 then
8.8
else
[HorasPrevistasAjustadas],
BaseAjustada =
if JornadaEh0829 then
if Base - [HorasAbonadas] < 0 then
0
else
Base - [HorasAbonadas]
else
Base
in
BaseAjustada,
type number
),
// =========================================================
// SALDO DE CONTROLE
//
// Positivo = horas acima da base
// Negativo = horas abaixo da base
//
// Inclui as horas fictas.
// =========================================================
SaldoControleHoras = Table.AddColumn(
HorasBaseControle,
"SaldoControleHoras",
each
if [TrabalhoFimDeSemana] = true
and [HorasTrabalhadas] <> null
then
Number.Round(
[HorasTrabalhadas]
+ [HorasFictas],
6
)
else if [JornadaPrevista] = true
and [HorasTrabalhadas] <> null
then
Number.Round(
[HorasTrabalhadas]
+ [HorasFictas]
- [HorasBaseControle],
6
)
else
null,
type number
),
// =========================================================
// ATRASO
//
// Tolerância: 10 minutos.
//
// Até -00:10 = não caracteriza atraso.
// Abaixo de -00:10 = atraso.
// =========================================================
AtrasoHoras = Table.AddColumn(
SaldoControleHoras,
"AtrasoHoras",
each
if [JornadaPrevista] <> true
or [HorasTrabalhadas] = null
then
null
else if
[TemAjusteContaComoFalta] = true
and [QuantidadeBatidas] = 0
then
0
else
let
SaldoSegundos =
Number.Round(
[SaldoControleHoras] * 3600,
0
)
in
if SaldoSegundos < -600 then
Number.Abs([SaldoControleHoras])
else
0,
type number
),
AtrasoMinutos = Table.AddColumn(
AtrasoHoras,
"AtrasoMinutos",
each
if [AtrasoHoras] = null
then null
else [AtrasoHoras] * 60,
type number
),
AtrasoAcimaTolerancia = Table.AddColumn(
AtrasoMinutos,
"AtrasoAcimaTolerancia",
each
if [AtrasoMinutos] = null
then false
else [AtrasoMinutos] > 10,
type logical
),
// =========================================================
// HORAS EXTRAS
//
// Para jornadas de 08:29:
// Base = 08:48
// Tolerância = 10 minutos
//
// Para as demais jornadas:
// mantém a base atual do modelo.
// =========================================================
HoraExtraHoras = Table.AddColumn(
AtrasoAcimaTolerancia,
"HoraExtraHoras",
each
if [HorasTrabalhadas] = null then
null
else if [TrabalhoFimDeSemana] = true then
[HorasTrabalhadas] + [HorasFictas]
else if [JornadaPrevista] <> true then
[HorasTrabalhadas] + [HorasFictas]
else if
Number.Round(
[SaldoControleHoras] * 3600,
0
) > 600
then
[SaldoControleHoras]
else
0,
type number
),
HoraExtraMinutos = Table.AddColumn(
HoraExtraHoras,
"HoraExtraMinutos",
each
if [HoraExtraHoras] = null
then null
else [HoraExtraHoras] * 60,
type number
),
HoraExtraAcimaTolerancia = Table.AddColumn(
HoraExtraMinutos,
"HoraExtraAcimaTolerancia",
each
if [HoraExtraMinutos] = null
then false
else [HoraExtraMinutos] > 10,
type logical
),
// =========================================================
// HORA EXTRA ACIMA DO LIMITE
//
// Limite RH: 01:12 (72 minutos).
// =========================================================
HoraExtraAcimaLimite = Table.AddColumn(
HoraExtraAcimaTolerancia,
"HoraExtraAcimaLimite",
each
if [HoraExtraMinutos] = null
then false
else [HoraExtraMinutos] > 72,
type logical
),
// =========================================================
// SALDO CONSIDERADO
// =========================================================
SaldoConsideradoHoras = Table.AddColumn(
HoraExtraAcimaLimite,
"SaldoConsideradoHoras",
each
if [SaldoHoras] = null then
null
else if [JornadaPrevista] <> true then
[HoraExtraHoras]
else
let
SaldoSegundos =
Number.Round(
[SaldoHoras] * 3600,
0
)
in
if SaldoSegundos < -600 then
[SaldoHoras]
else if SaldoSegundos > 600 then
[SaldoHoras]
else
0,
type number
),
// =========================================================
// SITUAÇÃO DA JORNADA
// =========================================================
SituacaoJornada = Table.AddColumn(
SaldoConsideradoHoras,
"SituacaoJornada",
each
if
[TemAjusteContaComoFalta] = true
and [QuantidadeBatidas] = 0
then
"Falta não justificada"
else if
[TemAjusteContaComoFalta] = true
and [QuantidadeBatidas] > 0
then
"Atraso por jornada não cumprida"
else if
[TemAjusteAbonado] = true
and [AjusteCobreJornada] = true
and [QuantidadeBatidas] = 0
then
"Coberta por ajuste"
else if
[Feriado] = true
and [QuantidadeBatidas] > 0
then
"Trabalhou no feriado"
else if
[Feriado] = true
and [QuantidadeBatidas] = 0
then
"Feriado"
else if
[JornadaPrevista] <> true
and [QuantidadeBatidas] > 0
then
"Trabalhada sem jornada prevista"
else if
[JornadaPrevista] <> true
and [QuantidadeBatidas] = 0
then
"Sem jornada prevista"
else if
[QuantidadeBatidas] = [QuantidadeBatidasEsperadas]
then
"Completa"
else if
[QuantidadeBatidas] = 0
then
"Sem registro de ponto"
else if
[QuantidadeBatidas] < [QuantidadeBatidasEsperadas]
then
"Quantidade de batidas incompleta"
else if
[QuantidadeBatidas] > [QuantidadeBatidasEsperadas]
then
"Quantidade de batidas acima do esperado"
else
"Inconsistente",
type text
),
// =========================================================
// NECESSIDADE DE ANÁLISE DE 4 BATIDAS
//
// Uma jornada totalmente coberta por ajuste não deve
// ser apontada como falta de 4 batidas.
// =========================================================
NecessitaAnalise4Batidas = Table.AddColumn(
SituacaoJornada,
"NecessitaAnalise4Batidas",
each
if [JornadaPrevista] <> true then
false
else if [Feriado] = true then
false
else if
[TemAjusteContaComoFalta] = true
and [QuantidadeBatidas] = 0
then
false
else if
[AjusteCobreJornada] = true
and [QuantidadeBatidas] = 0
then
false
else if
[Feriado] = true
and [QuantidadeBatidas] = 0
then
false
else
[QuantidadeBatidas] <> [QuantidadeBatidasEsperadas],
type logical
),
// =========================================================
// INTERVALOS EXTRAS
// =========================================================
IntervalosExtras = Table.AddColumn(
NecessitaAnalise4Batidas,
"IntervalosExtras",
each
if [QuantidadeIntervalos] > 2
then [QuantidadeIntervalos] - 2
else 0,
Int64.Type
),
IntervaloAlmocoHoras = Table.AddColumn(
IntervalosExtras,
"IntervaloAlmocoHoras",
each
if [QuantidadeBatidas] <> 4 then
null
else if [Saida1Real] = null or [Entrada2Real] = null then
null
else
Duration.TotalHours(
[Entrada2Real] - [Saida1Real]
),
type number
),
AlmocoAbaixoMinimo = Table.AddColumn(
IntervaloAlmocoHoras,
"AlmocoAbaixoMinimo",
each
if [IntervaloAlmocoHoras] = null then
false
else
[IntervaloAlmocoHoras] < 1,
type logical
),
InterjornadaSelecionada =
Table.SelectColumns(
Fato_Interjornada,
{
"FuncionarioID",
"DataJornadaAtual",
"IntervaloInterjornadaHoras"
}
),
InterjornadaRenomeada =
Table.RenameColumns(
InterjornadaSelecionada,
{
{"DataJornadaAtual", "Data"}
}
),
MergeInterjornada =
Table.NestedJoin(
AlmocoAbaixoMinimo,
{
"FuncionarioID",
"Data"
},
InterjornadaRenomeada,
{
"FuncionarioID",
"Data"
},
"Interjornada",
JoinKind.LeftOuter
),
ExpandirInterjornada =
Table.ExpandTableColumn(
MergeInterjornada,
"Interjornada",
{
"IntervaloInterjornadaHoras"
},
{
"IntervaloInterjornadaHoras"
}
),
// =========================================================
// FIM DE SEMANA - OCORRÊNCIAS
//
// Considera somente sábados e domingos pertencentes
// a meses que não atenderam à regra de fim de semana.
// =========================================================
FimDeSemanaOcorrencias =
Table.SelectRows(
Fato_FimDeSemana_Detalhe,
each
[AtendeuRegraFimDeSemana] = false
),
FimDeSemanaSelecionado =
Table.SelectColumns(
FimDeSemanaOcorrencias,
{
"FuncionarioID",
"Data"
}
),
FimDeSemanaComFlag =
Table.AddColumn(
FimDeSemanaSelecionado,
"FimDeSemanaOcorrencia",
each true,
type logical
),
MergeFimDeSemana =
Table.NestedJoin(
ExpandirInterjornada,
{
"FuncionarioID",
"Data"
},
FimDeSemanaComFlag,
{
"FuncionarioID",
"Data"
},
"FimDeSemana",
JoinKind.LeftOuter
),
ExpandirFimDeSemana =
Table.ExpandTableColumn(
MergeFimDeSemana,
"FimDeSemana",
{
"FimDeSemanaOcorrencia"
},
{
"FimDeSemanaOcorrencia"
}
),
FimDeSemanaOcorrenciaFinal =
Table.ReplaceValue(
ExpandirFimDeSemana,
null,
false,
Replacer.ReplaceValue,
{"FimDeSemanaOcorrencia"}
)
in
FimDeSemanaOcorrenciaFinal,
#"Colunas Renomeadas" = Table.RenameColumns(Fato_Jornada_Comparacao,{{"FimDeSemanaOcorrencia", "Fim de Semana"}})
in
#"Colunas Renomeadas"
To embed this project on your website, copy the following code and paste it into your website's HTML: