Compare commits
13 Commits
feat-style
...
ajustes_ge
| Author | SHA1 | Date | |
|---|---|---|---|
| b76c308aab | |||
| 67b2091d96 | |||
| 1b1d2fb97e | |||
| 16ede85bc2 | |||
|
|
a951f61676 | ||
|
|
98d12d40ef | ||
| 457e89e386 | |||
|
|
10454b38ea | ||
| 6936a59c21 | |||
|
|
813d614648 | ||
| 196ef90643 | |||
|
|
1a56f2ab64 | ||
|
|
52e6805c09 |
@@ -9,12 +9,21 @@
|
|||||||
|
|
||||||
let tempoAtual = $state<Date>(new Date());
|
let tempoAtual = $state<Date>(new Date());
|
||||||
let sincronizado = $state(false);
|
let sincronizado = $state(false);
|
||||||
|
let sincronizando = $state(false);
|
||||||
let usandoServidorExterno = $state(false);
|
let usandoServidorExterno = $state(false);
|
||||||
let offsetSegundos = $state(0);
|
let offsetSegundos = $state(0);
|
||||||
let erro = $state<string | null>(null);
|
let erro = $state<string | null>(null);
|
||||||
let intervalId: ReturnType<typeof setInterval> | null = null;
|
let intervalId: ReturnType<typeof setInterval> | null = null;
|
||||||
|
let intervaloSincronizacao: ReturnType<typeof setInterval> | null = null;
|
||||||
|
let sincronizacaoEmAndamento = $state(false); // Flag para evitar múltiplas sincronizações simultâneas
|
||||||
|
|
||||||
async function atualizarTempo() {
|
async function atualizarTempo() {
|
||||||
|
// Evitar múltiplas sincronizações simultâneas
|
||||||
|
if (sincronizacaoEmAndamento) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sincronizacaoEmAndamento = true;
|
||||||
|
sincronizando = true;
|
||||||
try {
|
try {
|
||||||
const config = await client.query(api.configuracaoRelogio.obterConfiguracao, {});
|
const config = await client.query(api.configuracaoRelogio.obterConfiguracao, {});
|
||||||
// Usar gmtOffset da configuração, sem valor padrão, pois 0 é um valor válido
|
// Usar gmtOffset da configuração, sem valor padrão, pois 0 é um valor válido
|
||||||
@@ -25,7 +34,12 @@
|
|||||||
|
|
||||||
if (config.usarServidorExterno) {
|
if (config.usarServidorExterno) {
|
||||||
try {
|
try {
|
||||||
const resultado = await client.action(api.configuracaoRelogio.sincronizarTempo, {});
|
// Adicionar timeout de 10 segundos para sincronização
|
||||||
|
const sincronizacaoPromise = client.action(api.configuracaoRelogio.sincronizarTempo, {});
|
||||||
|
const timeoutPromise = new Promise<never>((_, reject) =>
|
||||||
|
setTimeout(() => reject(new Error('Timeout na sincronização (10s)')), 10000)
|
||||||
|
);
|
||||||
|
const resultado = await Promise.race([sincronizacaoPromise, timeoutPromise]);
|
||||||
if (resultado.sucesso && resultado.timestamp) {
|
if (resultado.sucesso && resultado.timestamp) {
|
||||||
timestampBase = resultado.timestamp;
|
timestampBase = resultado.timestamp;
|
||||||
sincronizado = true;
|
sincronizado = true;
|
||||||
@@ -43,7 +57,11 @@
|
|||||||
usandoServidorExterno = false;
|
usandoServidorExterno = false;
|
||||||
erro = 'Usando relógio do PC (falha na sincronização)';
|
erro = 'Usando relógio do PC (falha na sincronização)';
|
||||||
} else {
|
} else {
|
||||||
throw error;
|
// Mesmo sem fallback configurado, usar PC como última opção
|
||||||
|
timestampBase = obterTempoPC();
|
||||||
|
sincronizado = false;
|
||||||
|
usandoServidorExterno = false;
|
||||||
|
erro = 'Usando relógio do PC (servidor indisponível)';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -71,6 +89,9 @@
|
|||||||
tempoAtual = new Date(obterTempoPC());
|
tempoAtual = new Date(obterTempoPC());
|
||||||
sincronizado = false;
|
sincronizado = false;
|
||||||
erro = 'Erro ao obter tempo do servidor';
|
erro = 'Erro ao obter tempo do servidor';
|
||||||
|
} finally {
|
||||||
|
sincronizando = false;
|
||||||
|
sincronizacaoEmAndamento = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,17 +102,34 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await atualizarTempo();
|
// Inicializar com relógio do PC imediatamente para não bloquear a interface
|
||||||
// Sincronizar a cada 30 segundos
|
tempoAtual = new Date(obterTempoPC());
|
||||||
setInterval(atualizarTempo, 30000);
|
sincronizado = false;
|
||||||
|
erro = 'Usando relógio do PC';
|
||||||
// Atualizar display a cada segundo
|
// Atualizar display a cada segundo
|
||||||
intervalId = setInterval(atualizarRelogio, 1000);
|
intervalId = setInterval(atualizarRelogio, 1000);
|
||||||
|
// Sincronizar em background (não bloquear) após um pequeno delay para garantir que a UI está renderizada
|
||||||
|
setTimeout(() => {
|
||||||
|
atualizarTempo().catch((error) => {
|
||||||
|
console.error('Erro ao sincronizar tempo em background:', error);
|
||||||
|
});
|
||||||
|
}, 100);
|
||||||
|
// Sincronizar a cada 30 segundos
|
||||||
|
intervaloSincronizacao = setInterval(() => {
|
||||||
|
atualizarTempo().catch((error) => {
|
||||||
|
console.error('Erro ao sincronizar tempo periódico:', error);
|
||||||
|
});
|
||||||
|
}, 30000);
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
if (intervalId) {
|
if (intervalId) {
|
||||||
clearInterval(intervalId);
|
clearInterval(intervalId);
|
||||||
}
|
}
|
||||||
|
if (intervaloSincronizacao) {
|
||||||
|
clearInterval(intervaloSincronizacao);
|
||||||
|
}
|
||||||
|
sincronizacaoEmAndamento = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
const horaFormatada = $derived.by(() => {
|
const horaFormatada = $derived.by(() => {
|
||||||
@@ -131,13 +169,18 @@
|
|||||||
|
|
||||||
<!-- Status de Sincronização -->
|
<!-- Status de Sincronização -->
|
||||||
<div
|
<div
|
||||||
class="flex items-center gap-2 rounded-full px-4 py-2 {sincronizado
|
class="flex items-center gap-2 rounded-full px-4 py-2 {sincronizando
|
||||||
|
? 'bg-info/20 text-info border-info/30 border animate-pulse'
|
||||||
|
: sincronizado
|
||||||
? 'bg-success/20 text-success border-success/30 border'
|
? 'bg-success/20 text-success border-success/30 border'
|
||||||
: erro
|
: erro
|
||||||
? 'bg-warning/20 text-warning border-warning/30 border'
|
? 'bg-warning/20 text-warning border-warning/30 border'
|
||||||
: 'bg-base-300/50 text-base-content/60 border-base-300 border'}"
|
: 'bg-base-300/50 text-base-content/60 border-base-300 border'}"
|
||||||
>
|
>
|
||||||
{#if sincronizado}
|
{#if sincronizando}
|
||||||
|
<span class="loading loading-spinner loading-sm text-info"></span>
|
||||||
|
<span class="text-sm font-semibold">Sincronizando com servidor...</span>
|
||||||
|
{:else if sincronizado}
|
||||||
<CheckCircle2 class="h-4 w-4" strokeWidth={2.5} />
|
<CheckCircle2 class="h-4 w-4" strokeWidth={2.5} />
|
||||||
<span class="text-sm font-semibold">
|
<span class="text-sm font-semibold">
|
||||||
{#if usandoServidorExterno}
|
{#if usandoServidorExterno}
|
||||||
|
|||||||
@@ -444,3 +444,9 @@ export function adicionarRodape(doc: jsPDF): void {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -82,4 +82,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -82,4 +82,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
116
packages/backend/convex/_generated/api.d.ts
vendored
116
packages/backend/convex/_generated/api.d.ts
vendored
@@ -352,6 +352,10 @@ export declare const components: {
|
|||||||
lastRequest?: null | number;
|
lastRequest?: null | number;
|
||||||
};
|
};
|
||||||
model: "rateLimit";
|
model: "rateLimit";
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
data: { count: number; key: string; lastRequest: number };
|
||||||
|
model: "ratelimit";
|
||||||
};
|
};
|
||||||
onCreateHandle?: string;
|
onCreateHandle?: string;
|
||||||
select?: Array<string>;
|
select?: Array<string>;
|
||||||
@@ -729,6 +733,32 @@ export declare const components: {
|
|||||||
| Array<number>
|
| Array<number>
|
||||||
| null;
|
| null;
|
||||||
}>;
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "ratelimit";
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field: "key" | "count" | "lastRequest" | "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
};
|
};
|
||||||
onDeleteHandle?: string;
|
onDeleteHandle?: string;
|
||||||
paginationOpts: {
|
paginationOpts: {
|
||||||
@@ -1113,6 +1143,32 @@ export declare const components: {
|
|||||||
| Array<number>
|
| Array<number>
|
||||||
| null;
|
| null;
|
||||||
}>;
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "ratelimit";
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field: "key" | "count" | "lastRequest" | "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
};
|
};
|
||||||
onDeleteHandle?: string;
|
onDeleteHandle?: string;
|
||||||
},
|
},
|
||||||
@@ -1134,7 +1190,8 @@ export declare const components: {
|
|||||||
| "oauthAccessToken"
|
| "oauthAccessToken"
|
||||||
| "oauthConsent"
|
| "oauthConsent"
|
||||||
| "jwks"
|
| "jwks"
|
||||||
| "rateLimit";
|
| "rateLimit"
|
||||||
|
| "ratelimit";
|
||||||
offset?: number;
|
offset?: number;
|
||||||
paginationOpts: {
|
paginationOpts: {
|
||||||
cursor: string | null;
|
cursor: string | null;
|
||||||
@@ -1186,7 +1243,8 @@ export declare const components: {
|
|||||||
| "oauthAccessToken"
|
| "oauthAccessToken"
|
||||||
| "oauthConsent"
|
| "oauthConsent"
|
||||||
| "jwks"
|
| "jwks"
|
||||||
| "rateLimit";
|
| "rateLimit"
|
||||||
|
| "ratelimit";
|
||||||
select?: Array<string>;
|
select?: Array<string>;
|
||||||
where?: Array<{
|
where?: Array<{
|
||||||
connector?: "AND" | "OR";
|
connector?: "AND" | "OR";
|
||||||
@@ -1695,6 +1753,33 @@ export declare const components: {
|
|||||||
| Array<number>
|
| Array<number>
|
||||||
| null;
|
| null;
|
||||||
}>;
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "ratelimit";
|
||||||
|
update: { count?: number; key?: string; lastRequest?: number };
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field: "key" | "count" | "lastRequest" | "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
};
|
};
|
||||||
onUpdateHandle?: string;
|
onUpdateHandle?: string;
|
||||||
paginationOpts: {
|
paginationOpts: {
|
||||||
@@ -2183,6 +2268,33 @@ export declare const components: {
|
|||||||
| Array<number>
|
| Array<number>
|
||||||
| null;
|
| null;
|
||||||
}>;
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "ratelimit";
|
||||||
|
update: { count?: number; key?: string; lastRequest?: number };
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field: "key" | "count" | "lastRequest" | "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
};
|
};
|
||||||
onUpdateHandle?: string;
|
onUpdateHandle?: string;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export type Doc<TableName extends TableNames> = DocumentByName<
|
|||||||
* Convex documents are uniquely identified by their `Id`, which is accessible
|
* Convex documents are uniquely identified by their `Id`, which is accessible
|
||||||
* on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids).
|
* on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids).
|
||||||
*
|
*
|
||||||
* Documents can be loaded using `db.get(tableName, id)` in query and mutation functions.
|
* Documents can be loaded using `db.get(id)` in query and mutation functions.
|
||||||
*
|
*
|
||||||
* IDs are just strings at runtime, but this type can be used to distinguish them from other
|
* IDs are just strings at runtime, but this type can be used to distinguish them from other
|
||||||
* strings when type checking.
|
* strings when type checking.
|
||||||
|
|||||||
@@ -1848,7 +1848,14 @@ async function atualizarBancoHoras(
|
|||||||
|
|
||||||
// Atualizar banco de horas mensal
|
// Atualizar banco de horas mensal
|
||||||
const mes = data.substring(0, 7); // YYYY-MM
|
const mes = data.substring(0, 7); // YYYY-MM
|
||||||
await calcularBancoHorasMensal(ctx, funcionarioId, mes);
|
|
||||||
|
// Verificar se estamos editando um mês passado
|
||||||
|
const hoje = new Date();
|
||||||
|
const mesAtual = `${hoje.getFullYear()}-${String(hoje.getMonth() + 1).padStart(2, '0')}`;
|
||||||
|
const estaEditandoMesPassado = mes < mesAtual;
|
||||||
|
|
||||||
|
// Se estamos editando um mês passado, recalcular em cascata para atualizar meses seguintes
|
||||||
|
await calcularBancoHorasMensal(ctx, funcionarioId, mes, estaEditandoMesPassado);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1979,14 +1986,74 @@ export const obterBancoHorasFuncionario = query({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recalcula meses seguintes em cascata quando um mês anterior é atualizado
|
||||||
|
* Isso garante que os saldos iniciais dos meses seguintes sejam atualizados corretamente
|
||||||
|
*/
|
||||||
|
async function recalcularMesesSeguintes(
|
||||||
|
ctx: MutationCtx,
|
||||||
|
funcionarioId: Id<'funcionarios'>,
|
||||||
|
mesAtualizado: string // YYYY-MM do mês que foi atualizado
|
||||||
|
): Promise<void> {
|
||||||
|
const hoje = new Date();
|
||||||
|
const mesAtual = `${hoje.getFullYear()}-${String(hoje.getMonth() + 1).padStart(2, '0')}`;
|
||||||
|
|
||||||
|
// Se o mês atualizado já é o mês atual ou futuro, não precisa recalcular nada
|
||||||
|
if (mesAtualizado >= mesAtual) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recalcular todos os meses do mês seguinte ao atualizado até o mês atual
|
||||||
|
// Calcular primeiro mês a recalcular (mês seguinte ao atualizado)
|
||||||
|
const [anoAtualizado, mesNumAtualizado] = mesAtualizado.split('-').map(Number);
|
||||||
|
let anoIter = anoAtualizado;
|
||||||
|
let mesNumIter = mesNumAtualizado + 1;
|
||||||
|
if (mesNumIter > 12) {
|
||||||
|
mesNumIter = 1;
|
||||||
|
anoIter += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continuar enquanto o mês iterado for menor ou igual ao mês atual
|
||||||
|
while (true) {
|
||||||
|
const mesIterStr = `${anoIter}-${String(mesNumIter).padStart(2, '0')}`;
|
||||||
|
|
||||||
|
// Se passou do mês atual, parar
|
||||||
|
if (mesIterStr > mesAtual) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verificar se existe registro mensal para este mês
|
||||||
|
const bancoMensalExistente = await ctx.db
|
||||||
|
.query('bancoHorasMensal')
|
||||||
|
.withIndex('by_funcionario_mes', (q) =>
|
||||||
|
q.eq('funcionarioId', funcionarioId).eq('mes', mesIterStr)
|
||||||
|
)
|
||||||
|
.first();
|
||||||
|
|
||||||
|
// Se existe registro, recalcular (o saldo inicial mudou porque o mês anterior mudou)
|
||||||
|
if (bancoMensalExistente) {
|
||||||
|
await calcularBancoHorasMensal(ctx, funcionarioId, mesIterStr, false); // false = não recalcular cascata novamente
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avançar para o próximo mês
|
||||||
|
mesNumIter += 1;
|
||||||
|
if (mesNumIter > 12) {
|
||||||
|
mesNumIter = 1;
|
||||||
|
anoIter += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calcula e atualiza banco de horas mensal para um funcionário
|
* Calcula e atualiza banco de horas mensal para um funcionário
|
||||||
* Esta função deve ser chamada após atualizações no banco de horas diário
|
* Esta função deve ser chamada após atualizações no banco de horas diário
|
||||||
|
* @param recalcularCascata - Se true, recalcula automaticamente os meses seguintes (padrão: true)
|
||||||
*/
|
*/
|
||||||
async function calcularBancoHorasMensal(
|
async function calcularBancoHorasMensal(
|
||||||
ctx: MutationCtx,
|
ctx: MutationCtx,
|
||||||
funcionarioId: Id<'funcionarios'>,
|
funcionarioId: Id<'funcionarios'>,
|
||||||
mes: string // YYYY-MM
|
mes: string, // YYYY-MM
|
||||||
|
recalcularCascata: boolean = true // Por padrão, recalcula em cascata
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// Buscar todos os bancoHoras do mês
|
// Buscar todos os bancoHoras do mês
|
||||||
const dataInicio = `${mes}-01`;
|
const dataInicio = `${mes}-01`;
|
||||||
@@ -2106,6 +2173,11 @@ async function calcularBancoHorasMensal(
|
|||||||
atualizadoEm: agora
|
atualizadoEm: agora
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recalcular meses seguintes em cascata se solicitado
|
||||||
|
if (recalcularCascata) {
|
||||||
|
await recalcularMesesSeguintes(ctx, funcionarioId, mes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2611,7 +2683,14 @@ export const ajustarBancoHoras = mutation({
|
|||||||
|
|
||||||
// Recalcular banco de horas mensal após ajuste
|
// Recalcular banco de horas mensal após ajuste
|
||||||
const mes = hoje.substring(0, 7); // YYYY-MM
|
const mes = hoje.substring(0, 7); // YYYY-MM
|
||||||
await calcularBancoHorasMensal(ctx, args.funcionarioId, mes);
|
|
||||||
|
// Verificar se estamos ajustando um mês passado
|
||||||
|
const hojeDate = new Date();
|
||||||
|
const mesAtual = `${hojeDate.getFullYear()}-${String(hojeDate.getMonth() + 1).padStart(2, '0')}`;
|
||||||
|
const estaAjustandoMesPassado = mes < mesAtual;
|
||||||
|
|
||||||
|
// Se estamos ajustando um mês passado, recalcular em cascata para atualizar meses seguintes
|
||||||
|
await calcularBancoHorasMensal(ctx, args.funcionarioId, mes, estaAjustandoMesPassado);
|
||||||
|
|
||||||
// Criar registro de homologação (mantido para compatibilidade)
|
// Criar registro de homologação (mantido para compatibilidade)
|
||||||
const homologacaoId = await ctx.db.insert('homologacoesPonto', {
|
const homologacaoId = await ctx.db.insert('homologacoesPonto', {
|
||||||
@@ -3872,7 +3951,14 @@ export const criarAjusteBancoHoras = mutation({
|
|||||||
|
|
||||||
// Recalcular banco de horas mensal
|
// Recalcular banco de horas mensal
|
||||||
const mes = args.dataAplicacao.substring(0, 7);
|
const mes = args.dataAplicacao.substring(0, 7);
|
||||||
await calcularBancoHorasMensal(ctx, args.funcionarioId, mes);
|
|
||||||
|
// Verificar se estamos aplicando ajuste em um mês passado
|
||||||
|
const hoje = new Date();
|
||||||
|
const mesAtual = `${hoje.getFullYear()}-${String(hoje.getMonth() + 1).padStart(2, '0')}`;
|
||||||
|
const estaAplicandoEmMesPassado = mes < mesAtual;
|
||||||
|
|
||||||
|
// Se estamos aplicando em um mês passado, recalcular em cascata para atualizar meses seguintes
|
||||||
|
await calcularBancoHorasMensal(ctx, args.funcionarioId, mes, estaAplicandoEmMesPassado);
|
||||||
|
|
||||||
return { ajusteId, success: true };
|
return { ajusteId, success: true };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user