Untitled

Anonymous
plain_text
04/27/2026 7:36 PM
12.4 KB
15
Indexable
private async obterCustosMaoObra({ filtro }: QueryCustom<BuscarCustosFiltroDto>, agrupamento: string) {
    // obter custo por hora de cada propriedade
    const custoHoraMaoObra: { safraId: number; propriedadeId: number; competencia: string; custoPorHora: number }[] =
      [];
    let tipoCalculo: 'geral' | 'competencia' = undefined;

    for (const safraId of filtro['safra.id']) {
      // se tem valor lançado para a safra inteira
      const valorMaoObraSafra = await this.dataSource.getRepository(ValoresMaoObra)
        .createQueryBuilder('valorMaoObra')
        .leftJoinAndSelect('valorMaoObra.propriedades', 'propriedade')
        .leftJoinAndSelect('propriedade.unidadesProdutivas', 'unidadeProdutiva')
        .leftJoinAndSelect(
          'unidadeProdutiva.culturas',
          'cultivo',
          '(cultivo.dataEncerramentoProducao >= NOW() OR cultivo.dataEncerramentoProducao IS NULL)',
        )
        .where('valorMaoObra.safraId = :safraId', { safraId: safraId })
        .andWhere(`competencia = '00/0000'`)
        .getOne();

      if (valorMaoObraSafra) {
        tipoCalculo = 'geral';
        const valorRateadoSafra: { propriedadeId: number; valor: number }[] = [];

        const areaPropriedades = this.obterAreaPropriedades(valorMaoObraSafra.propriedades);

        // faz o rateio do valor pela área cada propriedade
        for (const propriedade of valorMaoObraSafra.propriedades) {
          const areaPropriedade = this.obterAreaPropriedade(propriedade);

          valorRateadoSafra.push({
            propriedadeId: propriedade.id,
            valor: (valorMaoObraSafra.valorTotal / areaPropriedades) * areaPropriedade,
          });
        }

        // busca todas as atividades da safra atual para obter o total de horas
        const horasRateadasSafra = await this.obterHorasHomemRateio(`${this.nomeTabela}.safraId = :safraId`, {
          safraId: safraId,
        });

        valorRateadoSafra.forEach((valorSafra) => {
          const horasPropriedade = horasRateadasSafra.find(
            (horaSafra) => horaSafra.propriedadeId === valorSafra.propriedadeId,
          )?.horas;

          custoHoraMaoObra.push({
            safraId: +safraId,
            propriedadeId: valorSafra.propriedadeId,
            custoPorHora: horasPropriedade ? valorSafra.valor / horasPropriedade : 0,
            competencia: '00/0000',
          });
        });
      } else {
        tipoCalculo = 'competencia';
        // se tem valor lançado para cada mês
        const valorRateadoMes: { propriedadeId: number; competencia: string; valor: number }[] = [];
        const horasRateadasMes: { propriedadeId: number; competencia: string; horas: number }[] = [];

        const valoresMaoObraMes = await this.dataSource.getRepository(ValoresMaoObra)
          .createQueryBuilder('valorMaoObra')
          .leftJoinAndSelect('valorMaoObra.propriedades', 'propriedade')
          .leftJoinAndSelect('propriedade.unidadesProdutivas', 'unidadeProdutiva')
          .leftJoinAndSelect(
            'unidadeProdutiva.culturas',
            'cultivo',
            '(cultivo.dataEncerramentoProducao >= NOW() OR cultivo.dataEncerramentoProducao IS NULL)',
          )
          .where('valorMaoObra.safraId = :safraId', { safraId: safraId })
          .andWhere(`competencia <> '00/0000'`)
          .getMany();

        // percorre os valores encontrados e busca as atividades do mês da competencia e da safra corrente para obter o total de horas
        for (const valorMes of valoresMaoObraMes) {
          const areaPropriedades = this.obterAreaPropriedades(valorMes.propriedades);

          // faz o rateio do valor pela área cada propriedade
          for (const propriedade of valorMes.propriedades) {
            const areaPropriedade = this.obterAreaPropriedade(propriedade);

            valorRateadoMes.push({
              propriedadeId: propriedade.id,
              competencia: valorMes.competencia,
              valor: (valorMes.valorTotal / areaPropriedades) * areaPropriedade,
            });
          }

          // busca todas as atividades da safra/competência atual para obter o total de horas
          const horasRateio = await this.obterHorasHomemRateio(
            `${this.nomeTabela}.safraId = :safraId AND 
            TO_CHAR(${this.nomeTabela}.dataInicial, 'MM/YYYY') = :competencia AND
            propriedade.id IN (:...propriedadeIds)`,
            {
              safraId: safraId,
              competencia: valorMes.competencia,
              propriedadeIds: valorMes.propriedades.map((p) => p.id),
            },
          );

          horasRateadasMes.push(...horasRateio.map((hora) => ({ ...hora, competencia: valorMes.competencia })));
        }

        valorRateadoMes.forEach((valorMesAtual) => {
          const propriedadeCalculada = custoHoraMaoObra.find(
            (custo) =>
              custo.propriedadeId === valorMesAtual.propriedadeId &&
              custo.safraId === +safraId &&
              custo.competencia === valorMesAtual.competencia,
          );

          // como é feito um cálculo geral para a propriedade, não tem necessidade de adicionar mais de uma vez ao array final
          if (!propriedadeCalculada) {
            const somatorioHoras = somarArray(
              horasRateadasMes
                .filter(
                  (horaMes) =>
                    horaMes.propriedadeId === valorMesAtual.propriedadeId &&
                    horaMes.competencia === valorMesAtual.competencia,
                )
                .map((horaMes) => +horaMes.horas),
            );
            const somatorioValor = somarArray(
              valorRateadoMes
                .filter(
                  (valorMes) =>
                    valorMes.propriedadeId === valorMesAtual.propriedadeId &&
                    valorMes.competencia === valorMesAtual.competencia,
                )
                .map((valor) => +valor.valor),
            );
            const custoPorHora = somatorioHoras ? somatorioValor / somatorioHoras : 0;

            custoHoraMaoObra.push({
              safraId: +safraId,
              propriedadeId: valorMesAtual.propriedadeId,
              custoPorHora: custoPorHora,
              competencia: valorMesAtual.competencia,
            });
          }
        });
      }
    }

    // para buscar o total de horas do filtro precisa ratear as horasHomem pela área dos cultivos
    const { condicoes, parametros } = this.montarCondicoes(filtro, this.nomeTabela);

    const queryBuilder = this.createQueryBuilder(this.nomeTabela)
      .select(agrupamento, 'agrupamento')
      .addSelect('propriedade.id AS "propriedadeId"')
      .addSelect('safra.id AS "safraId"')
      .addSelect(
        `ROUND(
          SUM(
            CASE WHEN COALESCE(${this.nomeTabela}."areaTotal", 0) > 0 THEN
              ${this.nomeTabela}.horasHomem / ${this.nomeTabela}."areaTotal" * cultivo.area
            ELSE 0
            END
          )
        , 2)`,
        'horasHomem',
      )
      .leftJoin(`${this.nomeTabela}.unidadesProdutivasCulturas`, 'cultivo')
      .leftJoin('cultivo.unidadeProdutiva', 'unidadeProdutiva')
      .leftJoin('unidadeProdutiva.propriedade', 'propriedade')
      .leftJoin('cultivo.cultura', 'cultura')
      .leftJoin('cultivo.variedade', 'variedade')
      .leftJoin('cultivo.variedadeClone', 'variedadeClone')
      .leftJoin(`${this.nomeTabela}.safra`, 'safra')

      .where(`${this.nomeTabela}.organizacaoId = :organizacaoId`, {
        organizacaoId: this.getContexto().organizacao,
      })
      .andWhere(`${this.nomeTabela}.empresaId = :empresaId`, {
        empresaId: this.getContexto().empresa,
      });

    if (condicoes && parametros) {
      queryBuilder.andWhere(condicoes, parametros);
    }

    queryBuilder.groupBy('safra.id').addGroupBy('propriedade.id').addGroupBy(agrupamento);

    queryBuilder.orderBy('safra.id', 'ASC').addOrderBy('propriedade.id', 'ASC');

    if (tipoCalculo === 'competencia') {
      queryBuilder.addSelect(`TO_CHAR(${this.nomeTabela}.dataInicial, 'MM/YYYY')`, 'competencia');
      queryBuilder.addGroupBy('competencia');
      queryBuilder.addOrderBy('competencia', 'ASC');
    }

    const lancamentosFiltro = await queryBuilder.getRawMany();

    const result: { agrupamento: string; custosMaoObra: number }[] = [];

    lancamentosFiltro
      .map((lancamento) => {
        const custoPorHora =
          tipoCalculo === 'geral'
            ? custoHoraMaoObra.find(
              (c) => c.safraId === lancamento.safraId && c.propriedadeId === lancamento.propriedadeId,
            )?.custoPorHora
            : custoHoraMaoObra.find(
              (c) =>
                c.safraId === lancamento.safraId &&
                c.propriedadeId === lancamento.propriedadeId &&
                c.competencia === lancamento.competencia,
            )?.custoPorHora;

        return {
          ...lancamento,
          custosMaoObra: lancamento.horasHomem * (custoPorHora || 0),
        };
      })
      .forEach((r, i, array) => {
        const agrupamentoCalculado = result.find((res) => res.agrupamento === r.agrupamento);

        if (!agrupamentoCalculado) {
          const custosAgrupamento = somarArray(
            array.filter((a) => a.agrupamento === r.agrupamento).map((a) => a.custosMaoObra),
          );

          result.push({
            agrupamento: r.agrupamento,
            custosMaoObra: custosAgrupamento,
          });
        }
      });

    return result;
  }
Editor is loading...
Leave a Comment