Files
OPEN_CODEX_API/src/services/fechamento/competencias.ts
T
2026-05-15 17:13:52 -03:00

223 lines
6.7 KiB
TypeScript

import axios from "axios";
import { buildCommanderHeaders, resolveCommanderBaseUrl } from "./commanderHttp";
export type CompetenciaStatus = "em_aberto" | "concluido";
export type CompetenciaItem = {
id: string;
mes: number;
ano: number;
status: CompetenciaStatus;
quantidadeFechamentos: number;
criadoEm: string;
atualizadoEm: string;
};
export type FechamentoDaCompetenciaItem = {
id: string;
competenciaId: string;
parceiroId: string;
parceiroNome: string;
parceiroCodinome: string | null;
parceiroLogoUrl: string | null;
parceiroFator?: number | null;
horasTotal: number;
status: "em_aberto" | "fechado";
versao: number;
pontuacaoTotalEntregue: number;
pontuacaoAprovada: number;
pontuacaoMeta: number;
pontuacaoPaga: number;
pontuacaoBanco: number;
exportadoFinanceiro: boolean;
fechadoPorId: string | null;
fechadoEm: string | null;
criadoEm: string;
atualizadoEm: string;
};
type ListarCompetenciasResponse = {
data: CompetenciaItem[];
};
type ListarFechamentosDaCompetenciaResponse = {
data: FechamentoDaCompetenciaItem[];
};
type CriarCompetenciaResponse = {
data: CompetenciaItem;
};
type ConcluirCompetenciaResponse = {
data: CompetenciaItem & {
concluidoPorNome: string | null;
};
};
type ReabrirCompetenciaResponse = {
data: CompetenciaItem & {
reabertoPorNome: string | null;
};
};
type ImportarCompetenciaResponse = {
data: {
competenciaId: string;
tarefasRecebidas: number;
tarefasImportadas: number;
fechamentosCriados: number;
tarefasIgnoradasSemParceiro: number;
chamadasSubtarefasAsana: number;
};
};
export type ImportacaoAsanaModo =
| "reprocessar_tudo"
| "reprocessar_alguns"
| "buscar_novos_fechamentos";
type ApiErrorShape = {
error?: {
message?: string;
};
};
class FechamentoCompetenciasService {
private handleAxiosError(error: unknown, fallback: string): never {
if (axios.isAxiosError(error)) {
if (!error.response) {
throw new Error(
"Não foi possível conectar na API do Commander. Verifique VITE_API_BASE_URL_COMMANDER e se o backend está acessível.",
);
}
const message = ((error.response.data as ApiErrorShape | undefined)?.error?.message ??
error.message ??
fallback) as string;
throw new Error(message);
}
throw new Error(fallback);
}
async listarCompetencias(params: { ano?: number; status?: CompetenciaStatus }): Promise<CompetenciaItem[]> {
try {
const headers = await buildCommanderHeaders();
const baseUrl = resolveCommanderBaseUrl();
const response = await axios.get<ListarCompetenciasResponse>(`${baseUrl}/competencias`, {
headers,
params: {
ano: params.ano,
status: params.status,
},
});
return response.data.data ?? [];
} catch (error) {
this.handleAxiosError(error, "Erro ao listar competências.");
}
}
async listarFechamentosDaCompetencia(competenciaId: string): Promise<FechamentoDaCompetenciaItem[]> {
try {
const headers = await buildCommanderHeaders();
const baseUrl = resolveCommanderBaseUrl();
const response = await axios.get<ListarFechamentosDaCompetenciaResponse>(
`${baseUrl}/competencias/${competenciaId}/fechamentos`,
{ headers },
);
return response.data.data ?? [];
} catch (error) {
this.handleAxiosError(error, "Erro ao listar fechamentos da competência.");
}
}
async criarCompetencia(input: { mes: number; ano: number }): Promise<CompetenciaItem> {
try {
const headers = await buildCommanderHeaders();
const baseUrl = resolveCommanderBaseUrl();
const response = await axios.post<CriarCompetenciaResponse>(
`${baseUrl}/competencias`,
{ mes: input.mes, ano: input.ano },
{ headers },
);
return response.data.data;
} catch (error) {
this.handleAxiosError(error, "Erro ao criar competência.");
}
}
async concluirCompetencia(competenciaId: string, concluidoPorId: string): Promise<ConcluirCompetenciaResponse["data"]> {
try {
const headers = await buildCommanderHeaders();
const baseUrl = resolveCommanderBaseUrl();
const response = await axios.post<ConcluirCompetenciaResponse>(
`${baseUrl}/competencias/${competenciaId}/concluir`,
{ concluido_por_id: concluidoPorId },
{ headers },
);
return response.data.data;
} catch (error) {
this.handleAxiosError(error, "Erro ao concluir competência.");
}
}
async reabrirCompetencia(
competenciaId: string,
reabertoPorId: string,
motivo: string,
): Promise<ReabrirCompetenciaResponse["data"]> {
try {
const headers = await buildCommanderHeaders();
const baseUrl = resolveCommanderBaseUrl();
const response = await axios.post<ReabrirCompetenciaResponse>(
`${baseUrl}/competencias/${competenciaId}/reabrir`,
{ reaberto_por_id: reabertoPorId, motivo: motivo.trim() },
{ headers },
);
return response.data.data;
} catch (error) {
this.handleAxiosError(error, "Erro ao reabrir competência.");
}
}
async excluirCompetencia(competenciaId: string, excluidoPorId: string): Promise<void> {
try {
const headers = await buildCommanderHeaders();
const baseUrl = resolveCommanderBaseUrl();
await axios.delete(`${baseUrl}/competencias/${competenciaId}`, {
headers,
data: { excluido_por_id: excluidoPorId },
});
} catch (error) {
this.handleAxiosError(error, "Erro ao excluir competência.");
}
}
async importarDoAsana(
competenciaId: string,
opcoes?: { modo?: ImportacaoAsanaModo; parceiroIds?: string[] },
): Promise<{ tarefasRecebidas: number; tarefasImportadas: number; fechamentosCriados: number; tarefasIgnoradasSemParceiro: number }> {
try {
const headers = await buildCommanderHeaders();
const baseUrl = resolveCommanderBaseUrl();
const response = await axios.post<ImportarCompetenciaResponse>(
`${baseUrl}/competencias/${competenciaId}/importar`,
{
modo: opcoes?.modo ?? "reprocessar_tudo",
parceiroIds: opcoes?.parceiroIds,
},
{ headers },
);
return {
tarefasRecebidas: response.data.data.tarefasRecebidas,
tarefasImportadas: response.data.data.tarefasImportadas,
fechamentosCriados: response.data.data.fechamentosCriados,
tarefasIgnoradasSemParceiro: response.data.data.tarefasIgnoradasSemParceiro,
};
} catch (error) {
this.handleAxiosError(error, "Erro ao importar tasks do Asana.");
}
}
}
export const fechamentoCompetenciasService = new FechamentoCompetenciasService();