init commit
All checks were successful
build-api-image / build (push) Successful in 51s

This commit is contained in:
Antonio Lopes dos Santos
2026-08-04 16:52:02 -03:00
commit afec302c3e
11594 changed files with 1636728 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,351 @@
<?php
namespace App\Services\Almoxarifado;
use App\Enums\Almoxarifado\SaidaTipo;
use App\Exceptions\Almoxarifado\BaixaEstoqueIndisponivelException;
use App\Exceptions\Almoxarifado\EstoqueIndisponivelException;
use App\Models\Almoxarifado\EntradaItem;
use App\Models\Almoxarifado\MotivoBaixa;
use App\Models\Almoxarifado\Saida;
use App\Models\Almoxarifado\SaidaItem;
use App\Models\Cadastro\Material\Material;
use App\Models\Cadastro\SujeitoAtencao\Usuario;
use App\Services\Cadastro\Material\MaterialService;
use App\Services\Service;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
class BaixaService extends Service
{
public static function datatable()
{
$materiais = DB::table('cadastro_material')
->join(
'cadastro_grupo',
'cadastro_grupo.id',
'cadastro_material.grupo_id'
)
->join(
'cadastro_apresentacao',
'cadastro_apresentacao.id',
'cadastro_material.apresentacao_id'
)
->leftJoin(
'cadastro_subgrupo',
'cadastro_subgrupo.id',
'cadastro_material.subgrupo_id'
)
->leftJoin(
'cadastro_unidade_medida as apresentacao_unidade_medida',
'apresentacao_unidade_medida.id',
'cadastro_material.apresentacao_unidade_medida_id'
)
->leftJoin('almoxarifado_entrada_item', function ($join) {
$join
->on('almoxarifado_entrada_item.material_id', 'cadastro_material.id')
->whereExists(function ($query) {
$query
->select(DB::raw('1'))
->from('almoxarifado_entrada')
->whereColumn('almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->where('almoxarifado_entrada.finalizada', true)
->where('almoxarifado_entrada.centro_custo_id', self::getCurrentCentroCusto()->id);
});
})
->whereNull('cadastro_material.deleted_at')
->where(function ($query) {
$query->where(function ($query) {
$query
->whereNull('cadastro_material.subgrupo_id')
->whereExists(function ($query) {
$query
->select(DB::raw(1))
->from('almoxarifado_parametrizacao_controle_estoque_grupo')
->whereColumn('almoxarifado_parametrizacao_controle_estoque_grupo.grupo_id', 'cadastro_material.grupo_id')
->where('almoxarifado_parametrizacao_controle_estoque_grupo.centro_custo_id', self::getCurrentCentroCusto()->id);
});
})->orWhere(function ($query) {
$query
->whereNotNull('cadastro_material.subgrupo_id')
->whereExists(function ($query) {
$query
->select(DB::raw(1))
->from('almoxarifado_parametrizacao_controle_estoque_subgrupo')
->join(
'almoxarifado_parametrizacao_controle_estoque_grupo',
'almoxarifado_parametrizacao_controle_estoque_grupo.id',
'almoxarifado_parametrizacao_controle_estoque_subgrupo.parametrizacao_controle_estoque_grupo_id'
)
->whereColumn('almoxarifado_parametrizacao_controle_estoque_subgrupo.subgrupo_id', 'cadastro_material.subgrupo_id')
->where('almoxarifado_parametrizacao_controle_estoque_grupo.centro_custo_id', self::getCurrentCentroCusto()->id);
});
});
})
->select(
'cadastro_material.id',
'cadastro_material.codigo_material',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
) . " as descricao"),
'cadastro_material.is_ativo',
'cadastro_grupo.nome AS grupo',
'cadastro_subgrupo.nome AS subgrupo',
)
->distinct();
return datatables()
->of($materiais)
->filterColumn('descricao', function ($query, $keyword) {
$query->whereRaw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
) . " like ?", ["%{$keyword}%"]);
})
->skipTotalRecords()
->toJson();
}
public static function history()
{
$saidas = DB::table('almoxarifado_saida')
->join(
'almoxarifado_saida_item',
'almoxarifado_saida_item.saida_id',
'almoxarifado_saida.id'
)
->join(
'almoxarifado_saida_baixa',
'almoxarifado_saida_baixa.saida_id',
'almoxarifado_saida.id'
)
->join(
'cadastro_lotacao as baixa_lotacao',
'baixa_lotacao.id',
'almoxarifado_saida_baixa.created_lotacao_id'
)
->join(
'cadastro_usuario as baixa_usuario',
'baixa_usuario.id',
'baixa_lotacao.usuario_id'
)
->join(
'cadastro_cidadao as baixa_cidadao',
'baixa_cidadao.id',
'baixa_usuario.cidadao_id'
)
->join(
'almoxarifado_motivo_baixa',
'almoxarifado_motivo_baixa.id',
'almoxarifado_saida_baixa.motivo_id'
)
->leftJoin(
'cadastro_usuario',
'cadastro_usuario.id',
'almoxarifado_saida_baixa.usuario_solicitante_id'
)
->leftJoin(
'cadastro_cidadao',
'cadastro_cidadao.id',
'cadastro_usuario.cidadao_id'
)
->select(
'almoxarifado_saida_item.id AS saida_item_id',
DB::raw("DATE_FORMAT(almoxarifado_saida.created_at, '%d/%m/%Y') AS data"),
'almoxarifado_motivo_baixa.descricao AS motivo_descricao',
'almoxarifado_saida_baixa.justificativa',
'baixa_cidadao.nome AS usuario_baixa_nome',
'cadastro_cidadao.nome AS usuario_solicitante_nome',
DB::raw('(
SELECT SUM(se.quantidade_saida)
FROM almoxarifado_saida_item_entrada_item se
WHERE se.saida_item_id = almoxarifado_saida_item.id
) as quantidade'),
DB::raw("DATE_FORMAT(almoxarifado_saida_item.estornado_em, '%d/%m/%Y') as data_estorno"),
DB::raw('IF (almoxarifado_saida_item.estornado_em IS NULL, 0, 1) AS estornado'),
)
->addSelect([
'usuario_estorno_nome' => function ($query) {
$query->select('entrada_item_estorno_cidadao.nome')
->from('almoxarifado_saida_item_entrada_item as saida_item_entrada_item')
->leftJoin(
'almoxarifado_entrada_item as entrada_item_estorno',
'entrada_item_estorno.id',
'saida_item_entrada_item.entrada_item_estornado_id'
)
->leftJoin(
'cadastro_lotacao as entrada_item_estorno_lotacao',
'entrada_item_estorno_lotacao.id',
'entrada_item_estorno.created_lotacao_id'
)
->leftJoin(
'cadastro_usuario as entrada_item_estorno_usuario',
'entrada_item_estorno_usuario.id',
'entrada_item_estorno_lotacao.usuario_id'
)
->leftJoin(
'cadastro_cidadao as entrada_item_estorno_cidadao',
'entrada_item_estorno_cidadao.id',
'entrada_item_estorno_usuario.cidadao_id'
)
->whereColumn('saida_item_entrada_item.saida_item_id', 'almoxarifado_saida_item.id')
->limit(1);
},
])
->where('almoxarifado_saida.tipo_id', SaidaTipo::BAIXA)
->where('almoxarifado_saida_item.material_id', request()->query('material_id'))
->where('almoxarifado_saida.centro_custo_id', self::getCurrentCentroCusto()->id);
return datatables()
->of($saidas)
->filterColumn('almoxarifado_saida.created_at', function ($query, $keyword) {
$query->whereRaw("DATE_FORMAT(almoxarifado_saida.created_at, '%d/%m/%Y') like ?", ["%{$keyword}%"]);
})
->toJson();
}
public static function create($materialId)
{
$material = Material::findOrFail($materialId);
$estoque = AlmoxarifadoService::getEstoque($material->id);
$entradaItens = collect($estoque['por_entrada'])->map(function ($entradaItem) {
$entradaItem->quantidade_saida = 0;
return $entradaItem;
});
return [
'form' => [
'motivos' => MotivoBaixa::orderBy('descricao')
->get(['id', 'tipo_id', 'descricao', 'justificar']),
'possui_entrada_com_lote' => !is_null($entradaItens->whereNotNull('lote')->first()),
],
'model' => [
'motivo_id' => null,
'justificativa' => null,
'usuario_solicitante' => null,
'estoque' => $estoque['total'],
'quantidade' => null,
'escolheu_entrada_item_manualmente' => false,
'entrada_itens' => $entradaItens,
],
];
}
public static function store()
{
self::validate();
$saida = new Saida();
DB::transaction(function () use (&$saida) {
try {
$saida = AlmoxarifadoService::saveSaidaDeBaixa(self::getParams());
}
catch (EstoqueIndisponivelException $e) {
throw new BaixaEstoqueIndisponivelException();
}
});
return $saida->itens()->first();
}
private static function getParams()
{
return [
'material_id' => request()->material_id,
'motivo_id' => request()->motivo_id,
'justificativa' => request()->justificativa,
'usuario_solicitante_id' => request()->usuario_solicitante_id,
'quantidade' => (int) request()->quantidade,
'entrada_itens' => collect(request()->entrada_itens)->map(fn ($entradaItem) => [
'entrada_item_id' => $entradaItem['entrada_item_id'],
'quantidade_saida' => (int) $entradaItem['quantidade_saida'],
]),
'escolheu_entrada_item_manualmente' => request()->escolheu_entrada_item_manualmente,
];
}
public static function reverse($saidaItemId)
{
$saidaItem = SaidaItem::findOrFail($saidaItemId);
DB::transaction(function () use ($saidaItem) {
AlmoxarifadoService::estornarSaidaItens(collect([
['id' => $saidaItem->id]
]));
});
}
public static function validate()
{
$rules = [
'material_id' => [
'required',
'integer',
Rule::exists(Material::class, 'id'),
],
'motivo_id' => [
'required',
'integer',
Rule::exists(MotivoBaixa::class, 'id'),
],
'justificativa' => [
'nullable',
'string',
'max:100',
],
'usuario_solicitante_id' => [
'nullable',
'integer',
Rule::exists(Usuario::class, 'id'),
],
'quantidade' => [
'required',
'integer',
'min:1',
],
'escolheu_entrada_item_manualmente' => [
'required',
'boolean',
],
'entrada_itens' => [
'present',
'array',
],
'entrada_itens.*.entrada_item_id' => [
'required',
'integer',
Rule::exists(EntradaItem::class, 'id'),
],
'entrada_itens.*.quantidade_saida' => [
'required',
'integer',
'min:1',
],
];
$messages = [];
request()->validate($rules, $messages);
}
}

View File

@@ -0,0 +1,664 @@
<?php
namespace App\Services\Almoxarifado;
use App\Exceptions\Almoxarifado\FechamentoBalanceteNaoPermitidoException;
use App\Models\Almoxarifado\BalanceteFechamento;
use App\Models\Cadastro\Grupo\Grupo;
use App\Models\Cadastro\OrigemProgramatica;
use App\Services\Cadastro\Material\MaterialService;
use App\Services\Service;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
class BalanceteService extends Service
{
public static function checkDate($data)
{
$data = Carbon::createFromFormat('Y-m-d', $data)->setDay(1)->setTime(0, 0, 0);
$mesFechado = BalanceteFechamento::where('ano', $data->year)
->where('mes', (int) $data->month)
->exists();
if (!$mesFechado) {
$primeiroBalancete = BalanceteFechamento::orderBy('ano')->orderBy('mes')->first();
if (!is_null($primeiroBalancete)) {
$dataPrimeiroBalancete = Carbon::create($primeiroBalancete->ano, $primeiroBalancete->mes);
$mesFechado = $data <= $dataPrimeiroBalancete;
}
}
return [
'mes_fechado' => $mesFechado
];
}
public static function index()
{
$periodo = [
'inicio' => Carbon::createFromFormat('d/m/Y', request()->inicio)->setTime(0, 0, 0),
'fim' => Carbon::createFromFormat('d/m/Y', request()->fim)->setTime(23, 59, 59),
];
$balancete = self::getBalancete($periodo, request()->grupo_id, request()->subgrupo_id, request()->origem_programatica_id);
self::formatarSaldos($balancete);
return $balancete;
}
public static function formatarSaldos($balancete)
{
$balancete['por_material']->each(function ($balancete) {
$balancete->saldo_anterior_financeiro = self::getSaldoFormatado($balancete->saldo_anterior_financeiro);
$balancete->saldo_entrada_financeiro = self::getSaldoFormatado($balancete->saldo_entrada_financeiro);
$balancete->saldo_saida_financeiro = self::getSaldoFormatado($balancete->saldo_saida_financeiro);
$balancete->saldo_atual_financeiro = self::getSaldoFormatado($balancete->saldo_atual_financeiro);
unset($balancete->grupo_id, $balancete->subgrupo_id);
});
$balancete['por_subgrupo']->each(function ($balancete) {
$balancete->saldo_anterior_financeiro = self::getSaldoFormatado($balancete->saldo_anterior_financeiro);
$balancete->saldo_entrada_financeiro = self::getSaldoFormatado($balancete->saldo_entrada_financeiro);
$balancete->saldo_saida_financeiro = self::getSaldoFormatado($balancete->saldo_saida_financeiro);
$balancete->saldo_atual_financeiro = self::getSaldoFormatado($balancete->saldo_atual_financeiro);
unset($balancete->grupo_id, $balancete->subgrupo_id);
});
$balancete['por_grupo']->each(function ($balancete) {
$balancete->saldo_anterior_financeiro = self::getSaldoFormatado($balancete->saldo_anterior_financeiro);
$balancete->saldo_entrada_financeiro = self::getSaldoFormatado($balancete->saldo_entrada_financeiro);
$balancete->saldo_saida_financeiro = self::getSaldoFormatado($balancete->saldo_saida_financeiro);
$balancete->saldo_atual_financeiro = self::getSaldoFormatado($balancete->saldo_atual_financeiro);
unset($balancete->grupo_id);
});
$balancete['totalizadores']['saldo_anterior_financeiro'] = self::getSaldoFormatado(
$balancete['totalizadores']['saldo_anterior_financeiro']
);
$balancete['totalizadores']['saldo_entrada_financeiro'] = self::getSaldoFormatado(
$balancete['totalizadores']['saldo_entrada_financeiro']
);
$balancete['totalizadores']['saldo_saida_financeiro'] = self::getSaldoFormatado(
$balancete['totalizadores']['saldo_saida_financeiro']
);
$balancete['totalizadores']['saldo_atual_financeiro'] = self::getSaldoFormatado(
$balancete['totalizadores']['saldo_atual_financeiro']
);
}
private static function getSaldoFormatado($valor)
{
$precisao = 2;
$fator = (int) str_pad('1', $precisao + 1, '0');
return number_format(floor($valor * $fator) / $fator, $precisao, ',', '.');
}
public static function list()
{
$dataUltimoBalanceteFechado = self::getDataUltimoBalanceteFechado();
$dataBalanceteAberto = self::getDataBalanceteAberto();
if (!is_null($dataUltimoBalanceteFechado)) {
$dataUltimoBalanceteFechado = $dataUltimoBalanceteFechado->translatedFormat('F \de Y');
}
return [
'additionals' => [
'data_atual' => Carbon::now()->format('d/m/Y'),
'data_ultimo_balancete_fechado' => $dataUltimoBalanceteFechado,
'data_balancete_aberto' => self::getDataBalanceteAberto()->translatedFormat('F \de Y'),
'permite_fechar' => !$dataBalanceteAberto->isCurrentMonth(),
],
'form' => [
'grupos' => Grupo::orderBy('nome')
->get()
->map(fn ($grupo) => [
'id' => $grupo->id,
'nome' => $grupo->nome,
'subgrupos' => $grupo->subgrupos()
->orderBy('nome')
->get(['id', 'nome'])
]),
'origens_programaticas' => OrigemProgramatica::orderBy('nome')->get(['id', 'nome']),
],
'model' => [
'periodo' => [
'start' => null,
'end' => null,
],
'grupo_id' => null,
'subgrupo_id' => null,
'origem_programatica_id' => null,
],
];
}
public static function store()
{
$dataBalanceteAberto = self::getDataBalanceteAberto();
$saldo = self::getSaldo($dataBalanceteAberto);
if ($dataBalanceteAberto->isCurrentMonth()) {
throw new FechamentoBalanceteNaoPermitidoException;
}
return BalanceteFechamento::create([
'mes' => $dataBalanceteAberto->month,
'ano' => $dataBalanceteAberto->year,
'saldo_fisico' => $saldo['fisico'],
'saldo_financeiro' => $saldo['financeiro'],
]);
}
private static function getSaldo($dataBalanceteAberto)
{
$totais = self::getBalancete([
'inicio' => $dataBalanceteAberto->modify('first day of this month')->setTime(0, 0, 0),
'fim' => $dataBalanceteAberto->copy()->modify('last day of this month')->setTime(23, 59, 59),
])['totalizadores'];
return [
'fisico' => $totais['saldo_atual_fisico'],
'financeiro' => $totais['saldo_atual_financeiro'],
];
}
public static function getBalancete($periodo, $grupoId = null, $subgrupoId = null, $origemProgramaticaId = null)
{
$inicio = $periodo['inicio'];
$fim = $periodo['fim'];
$periodo = [$inicio, $fim];
$totalizadores = collect([
'saldo_anterior_fisico' => 0,
'saldo_anterior_financeiro' => 0.0,
'saldo_entrada_fisico' => 0,
'saldo_entrada_financeiro' => 0.0,
'saldo_saida_fisico' => 0,
'saldo_saida_financeiro' => 0.0,
'saldo_atual_fisico' => 0,
'saldo_atual_financeiro' => 0.0,
]);
$balancetePorGrupo = collect();
$balancetePorSubgrupo = collect();
$balancetePorMaterial = DB::table('cadastro_material as material')
->join('cadastro_apresentacao as apresentacao', 'apresentacao.id', 'material.apresentacao_id')
->join('cadastro_grupo as grupo', 'grupo.id', 'material.grupo_id')
->leftJoin(
'cadastro_unidade_medida as apresentacao_unidade_medida',
'apresentacao_unidade_medida.id',
'material.apresentacao_unidade_medida_id'
)
->leftJoin('cadastro_subgrupo as subgrupo', 'subgrupo.id', 'material.subgrupo_id')
->whereNull('material.deleted_at')
->when($grupoId, fn ($q, $id) => $q->where('material.grupo_id', $id))
->when($subgrupoId, fn ($q, $id) => $q->where('material.subgrupo_id', $id))
->where(function ($query) use ($periodo, $origemProgramaticaId, $inicio) {
$query
->whereExists(function ($query) use ($periodo, $origemProgramaticaId) {
$query->select(DB::raw(1))
->from('almoxarifado_entrada_item as entrada_item')
->join('almoxarifado_entrada as entrada', 'entrada.id', 'entrada_item.entrada_id')
->whereColumn('entrada_item.material_id', 'material.id')
->where('entrada.finalizada', true)
->where(function ($query) use ($periodo, $origemProgramaticaId) {
$query
->whereExists(function ($query) use ($periodo, $origemProgramaticaId) {
$query->select(DB::raw(1))
->from('almoxarifado_entrada_documento as documento')
->whereColumn('documento.entrada_id', 'entrada.id')
->whereBetween('documento.data', $periodo)
->when($origemProgramaticaId, fn ($q, $id) => $q->where('documento.origem_programatica_id', $id));
})
->when(is_null($origemProgramaticaId), function ($query) use ($periodo) {
$query
->orWhere(function ($query) use ($periodo) {
$query
->whereNotExists(function ($query) {
$query->select(DB::raw(1))
->from('almoxarifado_entrada_documento as documento')
->whereColumn('documento.entrada_id', 'entrada.id');
})
->whereBetween('entrada.created_at', $periodo);
});
});
});
})
->orWhereExists(function ($query) use ($periodo, $origemProgramaticaId) {
$query->select(DB::raw(1))
->from('almoxarifado_saida_item as saida_item')
->join('almoxarifado_saida as saida', 'saida.id', 'saida_item.saida_id')
->whereColumn('saida_item.material_id', 'material.id')
->where('saida.finalizada', true)
->whereBetween('saida.created_at', $periodo)
->when(!is_null($origemProgramaticaId), function ($query) use ($origemProgramaticaId) {
$query->whereExists(fn ($q) => $q
->selectRaw(1)
->from('almoxarifado_saida_item_entrada_item as saida_item_entrada_item')
->join('almoxarifado_entrada_item as entrada_item', 'entrada_item.id', 'saida_item_entrada_item.entrada_item_id')
->join('almoxarifado_entrada as entrada', 'entrada.id', 'entrada_item.entrada_id')
->join('almoxarifado_entrada_documento as entrada_documento', 'entrada_documento.entrada_id', 'entrada.id')
->whereColumn('saida_item_entrada_item.saida_item_id', 'saida_item.id')
->where('entrada_documento.origem_programatica_id', $origemProgramaticaId)
);
});
})
->orWhereExists(function ($query) use ($inicio, $origemProgramaticaId) {
$query->select(DB::raw(1))
->from('almoxarifado_entrada_item as entrada_item')
->join('almoxarifado_entrada as entrada', 'entrada.id', 'entrada_item.entrada_id')
->whereColumn('entrada_item.material_id', 'material.id')
->where('entrada.finalizada', true)
->where(function ($q) use ($inicio, $origemProgramaticaId) {
$q->whereExists(function ($q2) use ($inicio, $origemProgramaticaId) {
$q2->select(DB::raw(1))
->from('almoxarifado_entrada_documento as documento')
->whereColumn('documento.entrada_id', 'entrada.id')
->where('documento.data', '<', $inicio)
->when($origemProgramaticaId, fn ($f, $id) =>
$f->where('documento.origem_programatica_id', $id)
);
})
->when(is_null($origemProgramaticaId), function ($q2) use ($inicio) {
$q2->orWhere(function ($q3) use ($inicio) {
$q3->whereNotExists(function ($q4) {
$q4->select(DB::raw(1))
->from('almoxarifado_entrada_documento as documento')
->whereColumn('documento.entrada_id', 'entrada.id');
})
->where('entrada.created_at', '<', $inicio);
});
});
});
});
})
->select(
'material.codigo_material as material_codigo',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'material',
'apresentacao',
'apresentacao_unidade_medida'
) . " as material_descricao"),
'grupo.id as grupo_id',
'grupo.nome as grupo_nome',
'subgrupo.id as subgrupo_id',
'subgrupo.nome as subgrupo_nome'
)
->addSelect([
'saldo_anterior_fisico' => function ($query) use ($inicio, $origemProgramaticaId) {
$query->selectRaw("COALESCE((
SELECT SUM(entrada_item.quantidade - COALESCE((
SELECT SUM(COALESCE(saida_item_entrada_item.quantidade_saida, 0))
FROM almoxarifado_saida_item_entrada_item AS saida_item_entrada_item
WHERE saida_item_entrada_item.entrada_item_id = entrada_item.id
AND EXISTS (
SELECT 1
FROM almoxarifado_saida_item AS saida_item
JOIN almoxarifado_saida AS saida
ON saida.id = saida_item.saida_id
WHERE saida_item.id = saida_item_entrada_item.saida_item_id
AND saida.finalizada = 1
AND saida.created_at < '{$inicio}'
)
), 0))
FROM almoxarifado_entrada_item AS entrada_item
JOIN almoxarifado_entrada AS entrada
ON entrada.id = entrada_item.entrada_id
WHERE entrada_item.material_id = material.id
AND entrada.finalizada = 1
AND (
EXISTS (
SELECT 1
FROM almoxarifado_entrada_documento AS documento
WHERE documento.entrada_id = entrada.id
AND documento.data < '{$inicio}'
AND documento.data IS NOT NULL
" . (is_null($origemProgramaticaId) ? '' : "AND documento.origem_programatica_id = {$origemProgramaticaId}") . "
)
" . (is_null($origemProgramaticaId)
? "or (
NOT EXISTS (
SELECT 1
FROM almoxarifado_entrada_documento AS documento
WHERE documento.entrada_id = entrada.id
AND documento.data IS NOT NULL
)
AND entrada.created_at < '{$inicio}'
)"
: '')
. "
)
), 0)");
},
'saldo_anterior_financeiro' => function ($query) use ($inicio, $origemProgramaticaId) {
$query->selectRaw("COALESCE((
SELECT SUM((entrada_item.quantidade * entrada_item.valor_unitario) - COALESCE((
SELECT SUM(COALESCE(saida_item_entrada_item.quantidade_saida * entrada_item.valor_unitario, 0))
FROM almoxarifado_saida_item_entrada_item AS saida_item_entrada_item
WHERE saida_item_entrada_item.entrada_item_id = entrada_item.id
AND EXISTS (
SELECT 1
FROM almoxarifado_saida_item AS saida_item
JOIN almoxarifado_saida AS saida
ON saida.id = saida_item.saida_id
WHERE saida_item.id = saida_item_entrada_item.saida_item_id
AND saida.finalizada = 1
AND saida.created_at < '{$inicio}'
)
), 0))
FROM almoxarifado_entrada_item AS entrada_item
JOIN almoxarifado_entrada AS entrada
ON entrada.id = entrada_item.entrada_id
WHERE entrada_item.material_id = material.id
AND entrada.finalizada = 1
AND (
EXISTS (
SELECT 1
FROM almoxarifado_entrada_documento AS documento
WHERE documento.entrada_id = entrada.id
AND documento.data < '{$inicio}'
AND documento.data IS NOT NULL
" . (is_null($origemProgramaticaId) ? '' : "AND documento.origem_programatica_id = {$origemProgramaticaId}") . "
)
" . (is_null($origemProgramaticaId)
? "or (
NOT EXISTS (
SELECT 1
FROM almoxarifado_entrada_documento AS documento
WHERE documento.entrada_id = entrada.id
AND documento.data IS NOT NULL
)
AND entrada.created_at < '{$inicio}'
)"
: '')
. "
)
), 0)");
},
'saldo_entrada_fisico' => function ($query) use ($periodo, $origemProgramaticaId) {
$query->select(DB::raw('COALESCE(SUM(entrada_item.quantidade), 0)'))
->from('almoxarifado_entrada_item as entrada_item')
->join('almoxarifado_entrada as entrada', 'entrada.id', 'entrada_item.entrada_id')
->whereColumn('entrada_item.material_id', 'material.id')
->where('entrada.finalizada', true)
->where(function ($query) use ($periodo, $origemProgramaticaId) {
$query
->whereExists(function ($query) use ($periodo, $origemProgramaticaId) {
$query->select(DB::raw(1))
->from('almoxarifado_entrada_documento as documento')
->whereColumn('documento.entrada_id', 'entrada.id')
->whereBetween('documento.data', $periodo)
->when($origemProgramaticaId, fn ($q, $id) => $q->where('documento.origem_programatica_id', $id));
})
->when(is_null($origemProgramaticaId), function ($query) use ($periodo) {
$query
->orWhere(function ($query) use ($periodo) {
$query
->whereNotExists(function ($query) {
$query->select(DB::raw(1))
->from('almoxarifado_entrada_documento as documento')
->whereColumn('documento.entrada_id', 'entrada.id')
->whereNotNull('documento.data');
})
->whereBetween('entrada.created_at', $periodo);
});
});
});
},
'saldo_entrada_financeiro' => function ($query) use ($periodo, $origemProgramaticaId) {
$query->select(DB::raw('COALESCE(SUM(entrada_item.quantidade * entrada_item.valor_unitario), 0)'))
->from('almoxarifado_entrada_item as entrada_item')
->join('almoxarifado_entrada as entrada', 'entrada.id', 'entrada_item.entrada_id')
->whereColumn('entrada_item.material_id', 'material.id')
->where('entrada.finalizada', true)
->where(function ($query) use ($periodo, $origemProgramaticaId) {
$query
->whereExists(function ($query) use ($periodo, $origemProgramaticaId) {
$query->select(DB::raw(1))
->from('almoxarifado_entrada_documento as documento')
->whereColumn('documento.entrada_id', 'entrada.id')
->whereBetween('documento.data', $periodo)
->when($origemProgramaticaId, fn ($q, $id) => $q->where('documento.origem_programatica_id', $id));
})
->when(is_null($origemProgramaticaId), function ($query) use ($periodo) {
$query
->orWhere(function ($query) use ($periodo) {
$query
->whereNotExists(function ($query) {
$query->select(DB::raw(1))
->from('almoxarifado_entrada_documento as documento')
->whereColumn('documento.entrada_id', 'entrada.id');
})
->whereBetween('entrada.created_at', $periodo);
});
});
});
},
'saldo_saida_fisico' => function ($query) use ($periodo, $origemProgramaticaId) {
$query->select(DB::raw('COALESCE(SUM(saida_item_entrada_item.quantidade_saida), 0)'))
->from('almoxarifado_saida_item_entrada_item as saida_item_entrada_item')
->join(
'almoxarifado_saida_item as saida_item',
'saida_item.id',
'saida_item_entrada_item.saida_item_id'
)
->join('almoxarifado_saida as saida', 'saida.id', 'saida_item.saida_id')
->whereColumn('saida_item.material_id', 'material.id')
->where('saida.finalizada', true)
->whereBetween('saida.created_at', $periodo)
->when(!is_null($origemProgramaticaId), function ($query) use ($origemProgramaticaId) {
$query->whereExists(fn ($q) => $q
->selectRaw(1)
->from('almoxarifado_entrada_item as entrada_item')
->join('almoxarifado_entrada as entrada', 'entrada.id', 'entrada_item.entrada_id')
->join('almoxarifado_entrada_documento as entrada_documento', 'entrada_documento.entrada_id', 'entrada.id')
->whereColumn('entrada_item.id', 'saida_item_entrada_item.entrada_item_id')
->where('entrada_documento.origem_programatica_id', $origemProgramaticaId)
);
});
},
'saldo_saida_financeiro' => function ($query) use ($periodo, $origemProgramaticaId) {
$query->select(DB::raw(
'COALESCE(SUM(saida_item_entrada_item.quantidade_saida * entrada_item.valor_unitario), 0)'
))
->from('almoxarifado_entrada_item as entrada_item')
->join(
'almoxarifado_saida_item_entrada_item as saida_item_entrada_item',
'saida_item_entrada_item.entrada_item_id',
'entrada_item.id'
)
->join(
'almoxarifado_saida_item as saida_item',
'saida_item.id',
'saida_item_entrada_item.saida_item_id'
)
->join('almoxarifado_saida as saida', 'saida.id', 'saida_item.saida_id')
->whereColumn('saida_item.material_id', 'material.id')
->where('saida.finalizada', true)
->whereBetween('saida.created_at', $periodo)
->when(!is_null($origemProgramaticaId), function ($query) use ($origemProgramaticaId) {
$query->whereExists(fn ($q) => $q
->selectRaw(1)
->from('almoxarifado_entrada as entrada')
->join('almoxarifado_entrada_documento as entrada_documento', 'entrada_documento.entrada_id', 'entrada.id')
->whereColumn('entrada.id', 'entrada_item.entrada_id')
->where('entrada_documento.origem_programatica_id', $origemProgramaticaId)
);
});
}
])
->get()
->map(function ($item) use ($balancetePorSubgrupo, $balancetePorGrupo, $totalizadores) {
$item->saldo_atual_fisico = $item->saldo_anterior_fisico
+ $item->saldo_entrada_fisico
- $item->saldo_saida_fisico;
$item->saldo_atual_financeiro = $item->saldo_anterior_financeiro
+ $item->saldo_entrada_financeiro
- $item->saldo_saida_financeiro;
self::addBalancetePorSubgrupo($balancetePorSubgrupo, $item);
self::addBalancetePorGrupo($balancetePorGrupo, $item);
$totalizadores['saldo_anterior_fisico'] += $item->saldo_anterior_fisico;
$totalizadores['saldo_anterior_financeiro'] += $item->saldo_anterior_financeiro;
$totalizadores['saldo_entrada_fisico'] += $item->saldo_entrada_fisico;
$totalizadores['saldo_entrada_financeiro'] += $item->saldo_entrada_financeiro;
$totalizadores['saldo_saida_fisico'] += $item->saldo_saida_fisico;
$totalizadores['saldo_saida_financeiro'] += $item->saldo_saida_financeiro;
$totalizadores['saldo_atual_fisico'] += $item->saldo_atual_fisico;
$totalizadores['saldo_atual_financeiro'] += $item->saldo_atual_financeiro;
return $item;
});
return collect([
'por_material' => $balancetePorMaterial,
'por_subgrupo' => $balancetePorSubgrupo,
'por_grupo' => $balancetePorGrupo,
'totalizadores' => $totalizadores,
]);
}
private static function addBalancetePorSubgrupo($balancetePorSubgrupo, $item)
{
$balancetePorSubgrupoItem = $balancetePorSubgrupo
->where('grupo_id', $item->grupo_id)
->where('subgrupo_id', $item->subgrupo_id)
->first();
if (is_null($balancetePorSubgrupoItem)) {
$balancetePorSubgrupoItem = (object) [
'grupo_id' => $item->grupo_id,
'subgrupo_id' => $item->subgrupo_id,
'subgrupo_nome' => $item->subgrupo_nome,
'grupo_nome' => $item->grupo_nome,
'saldo_anterior_fisico' => 0,
'saldo_anterior_financeiro' => 0.0,
'saldo_entrada_fisico' => 0,
'saldo_entrada_financeiro' => 0.0,
'saldo_saida_fisico' => 0,
'saldo_saida_financeiro' => 0.0,
'saldo_atual_fisico' => 0,
'saldo_atual_financeiro' => 0.0,
];
$balancetePorSubgrupo->push($balancetePorSubgrupoItem);
}
$balancetePorSubgrupoItem->saldo_anterior_fisico += $item->saldo_anterior_fisico;
$balancetePorSubgrupoItem->saldo_anterior_financeiro += $item->saldo_anterior_financeiro;
$balancetePorSubgrupoItem->saldo_entrada_fisico += $item->saldo_entrada_fisico;
$balancetePorSubgrupoItem->saldo_entrada_financeiro += $item->saldo_entrada_financeiro;
$balancetePorSubgrupoItem->saldo_saida_fisico += $item->saldo_saida_fisico;
$balancetePorSubgrupoItem->saldo_saida_financeiro += $item->saldo_saida_financeiro;
$balancetePorSubgrupoItem->saldo_atual_fisico += $item->saldo_atual_fisico;
$balancetePorSubgrupoItem->saldo_atual_financeiro += $item->saldo_atual_financeiro;
}
private static function addBalancetePorGrupo($balancetePorGrupo, $item)
{
$balancetePorGrupoItem = $balancetePorGrupo->firstWhere('grupo_id', $item->grupo_id);
if (is_null($balancetePorGrupoItem)) {
$balancetePorGrupoItem = (object) [
'grupo_id' => $item->grupo_id,
'grupo_nome' => $item->grupo_nome,
'saldo_anterior_fisico' => 0,
'saldo_anterior_financeiro' => 0.0,
'saldo_entrada_fisico' => 0,
'saldo_entrada_financeiro' => 0.0,
'saldo_saida_fisico' => 0,
'saldo_saida_financeiro' => 0.0,
'saldo_atual_fisico' => 0,
'saldo_atual_financeiro' => 0.0,
];
$balancetePorGrupo->push($balancetePorGrupoItem);
}
$balancetePorGrupoItem->saldo_anterior_fisico += $item->saldo_anterior_fisico;
$balancetePorGrupoItem->saldo_anterior_financeiro += $item->saldo_anterior_financeiro;
$balancetePorGrupoItem->saldo_entrada_fisico += $item->saldo_entrada_fisico;
$balancetePorGrupoItem->saldo_entrada_financeiro += $item->saldo_entrada_financeiro;
$balancetePorGrupoItem->saldo_saida_fisico += $item->saldo_saida_fisico;
$balancetePorGrupoItem->saldo_saida_financeiro += $item->saldo_saida_financeiro;
$balancetePorGrupoItem->saldo_atual_fisico += $item->saldo_atual_fisico;
$balancetePorGrupoItem->saldo_atual_financeiro += $item->saldo_atual_financeiro;
}
private static function getDataUltimoBalanceteFechado()
{
$balancete = self::getUltimoBalanceteFechado();
return is_null($balancete) ? null : Carbon::create($balancete->ano, $balancete->mes);
}
private static function getDataBalanceteAberto()
{
$ultimoBalanceteFechado = self::getUltimoBalanceteFechado();
return is_null($ultimoBalanceteFechado)
? Carbon::now()->day(1)->subMonths(3)
: Carbon::create($ultimoBalanceteFechado->ano, $ultimoBalanceteFechado->mes)
->modify('last day of this month')
->addDay();
}
private static function getUltimoBalanceteFechado()
{
return BalanceteFechamento::orderByDesc('ano')
->orderByDesc('mes')
->first();
}
}

View File

@@ -0,0 +1,239 @@
<?php
namespace App\Services\Almoxarifado;
use App\Models\Almoxarifado\Dispensacao;
use App\Models\Almoxarifado\DispensacaoItem;
use App\Models\Cadastro\SujeitoAtencao\Paciente;
use App\Models\Intranet\Cliente;
use App\Services\Service;
use App\Utils\MaskUtil;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
class DispensacaoService extends Service
{
public static function create($pacienteId)
{
$receita = new Dispensacao();
$receita->fill(array_fill_keys($receita->getFillable(), null));
$item = new DispensacaoItem();
$item->fill(array_fill_keys($item->getFillable(), null));
$item->id = null;
$item->entregue = null;
$item->continuo = false;
$item->estoque = 0;
$item->escolheu_entrada_item_manualmente = false;
$item->entrada_itens = [];
$item->possui_entrada_com_lote = false;
$item->supervisor_id = null;
$paciente = self::getPaciente($pacienteId);
$currentLotacao = self::getCurrentLotacao();
$cliente = Cliente::where('link', app('config')->get('database.default'))->firstOrFail();
return [
'form' => [
'data_atual' => Carbon::now()->format('d/m/Y'),
'centro_custo_id' => self::getCurrentCentroCusto()->id,
'paciente' => $paciente,
'historico' => self::getHistorico($pacienteId),
'cliente' => [
'sistema' => [
'ramo_atividade' => [
'nome' => $cliente->sistema->ramoAtividade->nome ?? null,
],
'nome' => $cliente->sistema->nome ?? null,
'versao' => $cliente->sistema->versao ?? null,
],
'municipio' => [
'estado' => [
'uf' => $cliente->municipio->estado->uf ?? null,
],
'nome' => $cliente->municipio->nome ?? null,
],
'nome' => $cliente->nome ?? null,
'email' => $cliente->email ?? null,
'site' => $cliente->site ?? null,
'logotipo' => $cliente->logotipo ?? null,
],
'usuario' => $currentLotacao->usuario->cidadao->nome,
'unidade' => $currentLotacao->infraestrutura->unidade->nome_fantasia,
'telefone' => MaskUtil::getPhoneMasked($currentLotacao->infraestrutura->telefone)
],
'model' => [
'medico_solicitante' => null,
'item' => $item->toArray(),
'items' => [],
'paciente' => [
'id' => $paciente->id,
'observacao' => $paciente->observacao,
'save' => null,
],
]
];
}
public static function getHistorico($id)
{
$dispensacoes = Dispensacao::where('paciente_id', $id)
->select(
'*',
DB::raw('almoxarifado_dispensacao.id AS id')
)
->join('cadastro_lotacao', 'cadastro_lotacao.id', 'almoxarifado_dispensacao.created_lotacao_id')
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_lotacao.infraestrutura_id')
->join('cadastro_unidade', 'cadastro_unidade.id', 'cadastro_infraestrutura.unidade_id')
->when(!request()->complete, fn($q) => $q->whereHas('itens', fn($q) => $q->where('dispensado_em', '>=', Carbon::now()->subMonth(6)->startOfDay())))
->orderByDesc('data_dispensacao')
->get();
return $dispensacoes->map(function($dispensacao) {
return [
'id' => $dispensacao->id,
'data_dispensacao' => Carbon::parse($dispensacao->data_dispensacao)->format('d/m/Y'),
'nome_fantasia' => $dispensacao->nome_fantasia,
'infraestrutura' => $dispensacao->nome,
'medico_solicitante' => $dispensacao->usuario->nome,
'observacao' => $dispensacao->observacao,
'items' => self::getHistoricoItems($dispensacao->id),
];
})->values()->all();
}
private static function getHistoricoItems($id)
{
return DispensacaoItem::where('dispensacao_id', $id)->get()->map(function($item) {
return [
'id' => $item->id,
'material' => [
'descricao' => $item->material->descricao
],
'dispensado_em' => Carbon::parse($item->dispensado_em)->format('d/m/Y'),
'usuario_nome' => $item->dispensacao->usuario->nome,
'estornado' => $item->estornado,
'estorno_salvo' => $item->estornado
];
})->values()->all();
}
private static function getPaciente($id)
{
return Paciente::with('unidade')->findOrFail($id);
}
public static function store()
{
self::validate();
$dispensacao = null;
DB::transaction(function() use(&$dispensacao) {
$params = request()->all();
if(count($params['items']) > 0) {
$params['items'] = collect($params['items']);
$dispensacao = Dispensacao::create($params)->fresh();
$dispensacaoItems = collect();
$params['items']->each(function($item) use($dispensacao, &$dispensacaoItems) {
$item['dispensacao_id'] = $dispensacao->id;
$now = Carbon::now();
$dispensadoEm = new Carbon($item['dispensado_em']);
$dispensadoEm->setTime($now->hour, $now->minute, $now->second);
$item['dispensado_em'] = $dispensadoEm;
$dispensacaoItem = DispensacaoItem::create($item)->fresh();
$dispensacaoItems[] = [
'dispensacao_item_id' => $dispensacaoItem->id,
'material_id' => $dispensacaoItem->material_id,
'quantidade' => $dispensacaoItem->quantidade,
'escolheu_entrada_item_manualmente' => false,
];
});
$saidaItens = AlmoxarifadoService::saveSaidaDeDispensacaoDoAlmoxarifado($dispensacaoItems);
$saidaItens->each(function($data) {
DispensacaoItem::findOrFail($data['dispensacao_item_id'])
->update(['saida_item_id' => $data['saida_item_id']]);
});
}
if(count($params['estornados']) > 0) {
self::estornar($params['estornados']);
}
});
return $dispensacao;
}
private static function estornar($estornados)
{
foreach($estornados as $id) {
$item = DispensacaoItem::findOrFail($id);
AlmoxarifadoService::estornarSaidaItens(collect([['id' => $item->saida_item_id]]));
$item->update(['estornado' => true]);
}
}
public static function print($id)
{
$dispensacao = Dispensacao::find($id);
return [
'nome_medico_solicitante' => $dispensacao->usuario->nome,
'itens' => $dispensacao->itens->map(function($item) {
return [
'material' => [
'descricao_completa' => $item->material->descricao
],
'quantidade' => $item->quantidade
];
}),
'dispensado_em' => $dispensacao->data_dispensacao
];
}
private static function validate()
{
$params = request()->all();
$rules = [
'usuario_id' => [
'nullable',
'integer',
Rule::requiredIf(fn() => count($params['items']))
],
'data_dispensacao' => [
'nullable',
'date_format:Y-m-d',
'before_or_equal:now',
Rule::requiredIf(fn() => count($params['items']))
],
'observacao' => [
'nullable',
'string',
'between:3,300'
],
'items' => [
'nullable',
'array'
],
'items.*.dispensacao_id' => [
'nullable',
'integer',
],
'items.*.material_id' => [
'required',
'integer'
],
'dispensado_em' => [
'nullable',
'date_format:Y-m-d H:i',
'before_or_equal:now',
],
'items.*.quantidade' => [
'nullable',
'numeric',
'min:0.01',
],
'items.*.observacao' => [
'nullable',
'string',
'between:3,300'
],
];
$messages = [];
request()->validate($rules, $messages);
}
}

View File

@@ -0,0 +1,235 @@
<?php
namespace App\Services\Almoxarifado;
use App\Models\Cadastro\Fabricante\Fabricante;
use App\Models\Cadastro\Fornecedor\Fornecedor;
use App\Models\Cadastro\Material\Material;
use App\Services\Cadastro\Material\MaterialService;
use App\Services\Service;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
class EntradaInicialService extends Service
{
public static function datatable()
{
$materiais = DB::table('cadastro_material')
->join(
'cadastro_apresentacao',
'cadastro_apresentacao.id',
'cadastro_material.apresentacao_id'
)
->join(
'cadastro_grupo',
'cadastro_grupo.id',
'cadastro_material.grupo_id'
)
->leftJoin(
'cadastro_unidade_medida as apresentacao_unidade_medida',
'apresentacao_unidade_medida.id',
'cadastro_material.apresentacao_unidade_medida_id'
)
->leftJoin(
'cadastro_subgrupo',
'cadastro_subgrupo.id',
'cadastro_material.subgrupo_id'
)
->whereNull('cadastro_material.deleted_at')
->where(function ($query) {
$query->where(function ($query) {
$query
->whereNull('cadastro_material.subgrupo_id')
->whereExists(function ($query) {
$query
->select(DB::raw(1))
->from('almoxarifado_parametrizacao_controle_estoque_grupo')
->whereColumn('almoxarifado_parametrizacao_controle_estoque_grupo.grupo_id', 'cadastro_material.grupo_id')
->where('almoxarifado_parametrizacao_controle_estoque_grupo.centro_custo_id', self::getCurrentCentroCusto()->id);
});
})->orWhere(function ($query) {
$query
->whereNotNull('cadastro_material.subgrupo_id')
->whereExists(function ($query) {
$query
->select(DB::raw(1))
->from('almoxarifado_parametrizacao_controle_estoque_subgrupo')
->join(
'almoxarifado_parametrizacao_controle_estoque_grupo',
'almoxarifado_parametrizacao_controle_estoque_grupo.id',
'almoxarifado_parametrizacao_controle_estoque_subgrupo.parametrizacao_controle_estoque_grupo_id'
)
->whereColumn('almoxarifado_parametrizacao_controle_estoque_subgrupo.subgrupo_id', 'cadastro_material.subgrupo_id')
->where('almoxarifado_parametrizacao_controle_estoque_grupo.centro_custo_id', self::getCurrentCentroCusto()->id);
});
});
})
->whereNotExists(function ($query) {
$query
->select(DB::raw(1))
->from('almoxarifado_entrada_item')
->join(
'almoxarifado_entrada',
'almoxarifado_entrada.id',
'almoxarifado_entrada_item.entrada_id'
)
->whereColumn('almoxarifado_entrada_item.material_id', 'cadastro_material.id')
->where('almoxarifado_entrada.finalizada', true)
->where('almoxarifado_entrada.centro_custo_id', self::getCurrentCentroCusto()->id);
})
->select(
'cadastro_material.id',
'cadastro_material.codigo_material',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
) . " as descricao"),
'cadastro_material.possui_lote',
'cadastro_material.is_ativo',
'cadastro_grupo.nome AS grupo',
'cadastro_subgrupo.nome AS subgrupo',
DB::raw("IF(cadastro_material.material_bnafar_id IS NULL, 0, 1) as has_vinculo_bnafar")
)
->distinct();
return datatables()
->of($materiais)
->filterColumn('descricao', function ($query, $keyword) {
$query->whereRaw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
) . " like ?", ["%{$keyword}%"]);
})
->skipTotalRecords()
->toJson();
}
public static function store()
{
self::validate();
DB::transaction(function () {
AlmoxarifadoService::saveEntradaInicial(self::getParams());
});
}
public static function list()
{
switch (request()->listar) {
case 'integracao-bnafar-medicamentos':
return self::getIntegracaoBnafarMedicamentos(request()->material_id);
break;
}
}
private static function getParams()
{
return collect(request()->entradas)->map(fn ($entrada) => [
'material_id' => request()->material_id,
'integracao_bnafar_medicamento_id' => $entrada['integracao_bnafar_medicamento_id'],
'quantidade' => $entrada['quantidade'],
'lote' => $entrada['lote'] ? Str::upper($entrada['lote']) : null,
'validade_lote' => $entrada['validade_lote']
? Carbon::createFromFormat('d/m/Y', $entrada['validade_lote']) : null,
'valor_unitario' => $entrada['valor_unitario'],
'valor_total' => $entrada['valor_total'],
'codigo_barras' => $entrada['codigo_barras'],
'fabricante_id' => $entrada['fabricante_id'],
'fornecedor_id' => $entrada['fornecedor_id'],
]);
}
private static function validate()
{
$material = is_null(request()->material_id) ? null : Material::find(request()->material_id);
$possuiLote = $material->possui_lote ?? null;
$hasVinculoBnafar = !is_null($material->material_bnafar_id ?? null);
$rules = [
'material_id' => [
'required',
'integer',
Rule::exists(Material::class, 'id'),
],
'entradas' => [
'required',
'array',
],
'entradas.*.quantidade' => [
'required',
'integer',
'between:1,99999999'
],
'entradas.*.lote' => [
'nullable',
Rule::requiredIf(fn () => $possuiLote),
'string',
'max:15',
],
'entradas.*.validade_lote' => [
'nullable',
Rule::requiredIf(fn () => $possuiLote),
'date_format:d/m/Y',
],
'entradas.*.valor_total' => [
'required',
'numeric',
'min:0.000000',
'max:99999999.999999'
],
'entradas.*.valor_unitario' => [
'required',
'numeric',
'min:0.000000',
'max:99999999.999999'
],
'entradas.*.codigo_barras' => [
'nullable',
'digits:13',
],
'entradas.*.fabricante_id' => [
'nullable',
Rule::requiredIf(fn () => $hasVinculoBnafar),
'integer',
Rule::exists(Fabricante::class, 'id'),
],
'entradas.*.fornecedor_id' => [
'nullable',
'integer',
Rule::exists(Fornecedor::class, 'id'),
],
];
$messages = [];
request()->validate($rules, $messages);
}
private static function getIntegracaoBnafarMedicamentos($materialId)
{
return DB::table('integracao_bnafar_medicamento')
->select([
'integracao_bnafar_medicamento.id',
'integracao_bnafar_medicamento.descricao',
])
->whereExists(function ($query) use ($materialId) {
$query->select(DB::raw(1))
->from('cadastro_material_integracao_bnafar_medicamento')
->where('cadastro_material_integracao_bnafar_medicamento.material_id', $materialId)
->whereColumn('cadastro_material_integracao_bnafar_medicamento.medicamento_id', 'integracao_bnafar_medicamento.id');
})
->get();
}
}

View File

@@ -0,0 +1,431 @@
<?php
namespace App\Services\Almoxarifado;
use App\Enums\Almoxarifado\DocumentoTipo as AlmoxarifadoDocumentoTipo;
use App\Enums\Almoxarifado\EntradaTipo;
use App\Models\Almoxarifado\DocumentoTipo;
use App\Models\Almoxarifado\Entrada;
use App\Models\Almoxarifado\EntradaItem;
use App\Models\Cadastro\Fabricante\Fabricante;
use App\Models\Cadastro\Fornecedor\Fornecedor;
use App\Models\Cadastro\Material\Material;
use App\Models\Cadastro\OrigemProgramatica;
use App\Services\Service;
use App\Utils\MaskUtil;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
class EntradaService extends Service
{
public static function datatable()
{
$entradas = DB::table('almoxarifado_entrada')
->join(
'almoxarifado_entrada_documento',
'almoxarifado_entrada_documento.entrada_id',
'almoxarifado_entrada.id'
)
->join(
'almoxarifado_documento_tipo',
'almoxarifado_documento_tipo.id',
'almoxarifado_entrada_documento.tipo_id'
)
->join(
'cadastro_fornecedor',
'cadastro_fornecedor.id',
'almoxarifado_entrada_documento.fornecedor_id'
)
->leftJoin(
'cadastro_origem_programatica',
'cadastro_origem_programatica.id',
'almoxarifado_entrada_documento.origem_programatica_id'
)
->select(
'almoxarifado_entrada.id',
DB::raw("DATE_FORMAT(almoxarifado_entrada_documento.data, '%d/%m/%Y') as data_documento"),
'cadastro_fornecedor.nome_fantasia AS fornecedor_nome_fantasia',
'cadastro_origem_programatica.nome AS origem_programatica_nome',
'almoxarifado_entrada_documento.numero',
'almoxarifado_entrada_documento.numero_pedido',
DB::raw("(
SELECT SUM(item.valor_total)
FROM almoxarifado_entrada_item item
WHERE item.entrada_id = almoxarifado_entrada.id
) AS valor"),
'almoxarifado_documento_tipo.nome AS tipo_nome',
DB::raw("DATE_FORMAT(almoxarifado_entrada.created_at, '%d/%m/%Y') as data_entrada"),
'almoxarifado_entrada.finalizada',
)
->where('almoxarifado_entrada.tipo_id', EntradaTipo::MANUAL)
->where('almoxarifado_entrada.centro_custo_id', self::getCurrentCentroCusto()->id);
return datatables()
->of($entradas)
->filterColumn('almoxarifado_entrada_documento.data', function ($query, $keyword) {
$query->whereRaw("DATE_FORMAT(almoxarifado_entrada_documento.data, '%d/%m/%Y') like ?", ["%{$keyword}%"])
->orWhereRaw(
"CONCAT(
SUBSTR(almoxarifado_entrada_documento.data,9,2),
SUBSTR(almoxarifado_entrada_documento.data,6,2),
SUBSTR(almoxarifado_entrada_documento.data,1,4)
) like ?",
["%{$keyword}%"]
);
})
->filterColumn('almoxarifado_entrada.created_at', function ($query, $keyword) {
$query->whereRaw("DATE_FORMAT(almoxarifado_entrada.created_at, '%d/%m/%Y') like ?", ["%{$keyword}%"])
->orWhereRaw(
"CONCAT(
SUBSTR(almoxarifado_entrada.created_at,9,2),
SUBSTR(almoxarifado_entrada.created_at,6,2),
SUBSTR(almoxarifado_entrada.created_at,1,4)
) like ?",
["%{$keyword}%"]
);
})
->skipTotalRecords()
->toJson();
}
public static function create()
{
return [
'additionals' => self::getAdditionalsData(),
'form' => self::getFormData(),
'model' => [
'finalizada' => false,
'documento' => [
'tipo_id' => null,
'numero_pedido' => null,
'numero' => null,
'data' => null,
'fornecedor' => null,
'origem_programatica' => null,
],
'itens' => [],
]
];
}
public static function store()
{
self::validate();
$entrada = null;
DB::transaction(function () use (&$entrada) {
$entrada = AlmoxarifadoService::saveEntradaManual(self::getParams());
});
return $entrada;
}
public static function edit($id)
{
$entrada = Entrada::findOrFail($id);
return [
'additionals' => self::getAdditionalsData(),
'form' => self::getFormData(),
'model' => [
'finalizada' => $entrada->finalizada,
'documento' => [
'tipo_id' => $entrada->documento->tipo_id,
'numero_pedido' => $entrada->documento->numero_pedido,
'numero' => $entrada->documento->numero,
'data' => $entrada->documento->data->format('d/m/Y'),
'fornecedor' => $entrada->documento->fornecedor,
'origem_programatica' => $entrada->documento->origemProgramatica,
],
'itens' => $entrada->itens->map(function($item) {
$hasMovimentacao = false;
$hasMovimentacao = DB::table('almoxarifado_saida_item_entrada_item')
->where('entrada_item_id', $item->id)
->exists();
if (!$hasMovimentacao) {
$hasMovimentacao = DB::table('almoxarifado_reserva_item_entrada_item')
->where('entrada_item_id', $item->id)
->exists();
}
if (!$hasMovimentacao) {
$hasMovimentacao = DB::table('integracao_bnafar_posicao_estoque_item')
->where('material_id', $item->material->id)
->exists();
}
return [
'id' => $item->id,
'material' => [
'id' => $item->material->id,
'grupo_tipo_id' => $item->material->grupo->grupo_tipo_id ?? null,
'possui_lote' => $item->material->possui_lote,
'codigo_material' => $item->material->codigo_material,
'descricao_completa' => $item->material->descricao_completa,
'material_bnafar_id' => $item->material->materialBnafar->id ?? null,
'material_bnafar_codigo' => $item->material->materialBnafar->codigo ?? null,
'material_bnafar_descricao' => $item->material->materialBnafar->descricao ?? null,
'material_bnafar_tipo' => $item->material->materialBnafar->tipo ?? null,
],
'quantidade' => $item->quantidade,
'lote' => $item->lote,
'validade_lote' => $item->validade_lote ? $item->validade_lote->format('d/m/Y') : null,
'valor_unitario' => $item->valor_unitario_formatted,
'valor_total' => $item->valor_total_formatted,
'numero_empenho' => $item->numero_empenho,
'despesas' => $item->despesas_formatted,
'numero_autorizacao_fornecimento' => MaskUtil::getNumeroAutorizacaoFornecimentoMasked(
$item->numero_autorizacao_fornecimento
),
'fabricante' => $item->fabricante,
'codigo_barras' => $item->codigo_barras,
'estorno_salvo' => $item->estornado,
'estornado' => $item->estornado,
'integracao_bnafar_medicamento' => $item->integracaoBnafarMedicamento ? [
'medicamento_descricao_id' => $item->integracaoBnafarMedicamento->id,
'medicamento_descricao' => $item->integracaoBnafarMedicamento->descricao,
] : null,
'integracao_bnafar_medicamento_id' => $item->integracaoBnafarMedicamento->id ?? null,
'has_movimentacao' => $hasMovimentacao,
];
})
]
];
}
private static function getAdditionalsData()
{
return [
'data_atual' => Carbon::now()->format('d/m/Y'),
];
}
private static function getFormData()
{
return [
'tipos_documento' => DocumentoTipo::orderBy('nome')->get(['id', 'nome']),
];
}
public static function update($id)
{
self::validate();
$entrada = Entrada::findOrFail($id);
DB::transaction(function () use (&$entrada) {
$entrada = AlmoxarifadoService::saveEntradaManual(self::getParams(), $entrada->id);
});
return $entrada;
}
private static function getParams()
{
return [
'finalizada' => request()->finalizada,
'documento' => [
'fornecedor_id' => request()->documento['fornecedor_id'],
'origem_programatica_id' => request()->documento['origem_programatica_id'],
'tipo_id' => request()->documento['tipo_id'],
'numero_pedido' => request()->documento['numero_pedido'],
'numero' => request()->documento['numero'],
'data' => Carbon::createFromFormat('d/m/Y', request()->documento['data']),
],
'itens' => collect(request()->itens)->map(fn ($item) => [
'id' => $item['id'],
'material_id' => $item['material_id'],
'integracao_bnafar_medicamento_id' => $item['integracao_bnafar_medicamento_id'],
'quantidade' => $item['quantidade'],
'lote' => $item['lote'] ? Str::upper($item['lote']) : null,
'validade_lote' => $item['validade_lote']
? Carbon::createFromFormat('d/m/Y', $item['validade_lote']) : null,
'valor_unitario' => $item['valor_unitario'],
'valor_total' => $item['valor_total'],
'numero_empenho' => $item['numero_empenho'],
'despesas' => $item['despesas'],
'numero_autorizacao_fornecimento' => $item['numero_autorizacao_fornecimento'],
'fabricante_id' => $item['fabricante_id'],
'codigo_barras' => $item['codigo_barras'],
'estornado' => $item['estornado'],
])
];
}
public static function validate()
{
$rules = [
'finalizada' => [
'required',
'boolean',
],
'documento.fornecedor_id' => [
'required',
'integer',
Rule::exists(Fornecedor::class, 'id'),
],
'documento.origem_programatica_id' => [
'nullable',
'integer',
Rule::exists(OrigemProgramatica::class, 'id'),
],
'documento.tipo_id' => [
'required',
'integer',
Rule::exists(DocumentoTipo::class, 'id'),
],
'documento.numero_pedido' => [
'required',
'digits_between:1,20',
],
'documento.numero' => [
'required',
'digits_between:1,10',
],
'documento.data' => [
'required',
'date_format:d/m/Y',
'before_or_equal:now',
],
'itens' => [
'required',
'array',
],
];
$isDocumentoDoacao = (request()->documento['tipo_id'] ?? null) == AlmoxarifadoDocumentoTipo::DOACAO;
foreach ((request()->itens ?? []) as $i => $item) {
$material = is_null($item['material_id']) ? null : Material::find($item['material_id']);
$possuiLote = $material->possui_lote ?? null;
$hasVinculoBnafar = !is_null($material->material_bnafar_id ?? null);
$rules["itens.{$i}.id"] = [
'nullable',
'integer',
Rule::exists(EntradaItem::class, 'id'),
];
$rules["itens.{$i}.material_id"] = [
'bail',
'required',
'integer',
Rule::exists(Material::class, 'id'),
];
$rules["itens.{$i}.quantidade"] = [
'required',
'integer',
'between:1,99999999'
];
$rules["itens.{$i}.lote"] = [
'nullable',
Rule::requiredIf(fn () => is_null($item['id']) && $possuiLote),
'string',
'max:15',
];
$rules["itens.{$i}.validade_lote"] = [
'nullable',
Rule::requiredIf(fn () => is_null($item['id']) && $possuiLote),
'date_format:d/m/Y',
'after_or_equal:documento.data',
];
$rules["itens.{$i}.valor_total"] = [
'required',
'numeric',
'min:' . ($isDocumentoDoacao ? '0.000000' : '0.000001'),
'max:99999999.999999'
];
$rules["itens.{$i}.valor_unitario"] = [
'required',
'numeric',
'min:' . ($isDocumentoDoacao ? '0.000000' : '0.000001'),
'max:99999999.999999'
];
$rules["itens.{$i}.numero_empenho"] = [
'nullable',
'digits_between:1,20',
];
$rules["itens.{$i}.despesas"] = [
'nullable',
'numeric',
'max:99999999.999999'
];
$rules["itens.{$i}.numero_autorizacao_fornecimento"] = [
'nullable',
'digits:9',
];
$rules["itens.{$i}.fabricante_id"] = [
'nullable',
Rule::requiredIf(fn () => $hasVinculoBnafar),
'integer',
Rule::exists(Fabricante::class, 'id'),
];
$rules["itens.{$i}.codigo_barras"] = [
'nullable',
'digits:13',
];
$rules["itens.{$i}.estornado"] = [
'required',
'boolean',
];
}
$messages = [];
request()->validate($rules, $messages);
}
public static function destroy($id)
{
Entrada::findOrFail($id)->delete();
return null;
}
public static function list()
{
switch (request()->listar) {
case 'integracao-bnafar-medicamentos':
return self::getIntegracaoBnafarMedicamentos(request()->material_id);
break;
}
}
private static function getIntegracaoBnafarMedicamentos($materialId)
{
return DB::table('integracao_bnafar_medicamento')
->select([
'integracao_bnafar_medicamento.id AS medicamento_id',
'integracao_bnafar_medicamento.codigo AS medicamento_codigo',
'integracao_bnafar_medicamento.descricao AS medicamento_descricao',
])
->whereExists(function ($query) use ($materialId) {
$query->select(DB::raw(1))
->from('cadastro_material_integracao_bnafar_medicamento')
->where('cadastro_material_integracao_bnafar_medicamento.material_id', $materialId)
->whereColumn('cadastro_material_integracao_bnafar_medicamento.medicamento_id', 'integracao_bnafar_medicamento.id');
})
->get();
}
}

View File

@@ -0,0 +1,538 @@
<?php
namespace App\Services\Almoxarifado;
use App\Models\Almoxarifado\Inventario;
use App\Models\Cadastro\Grupo\Grupo;
use App\Models\Cadastro\Material\Material;
use App\Services\Cadastro\Material\MaterialService;
use App\Services\Service;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
class InventarioService extends Service
{
public static function index()
{
$mainFields = [
'cadastro_material.id',
'cadastro_material.codigo_material',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
) . " as descricao"),
'cadastro_grupo.nome AS grupo',
'cadastro_subgrupo.nome AS subgrupo',
'cadastro_material.is_ativo',
'almoxarifado_inventario.contagem',
];
$estoqueSum = "COALESCE(SUM(
COALESCE(almoxarifado_entrada_item.quantidade, 0)
-
COALESCE((
SELECT SUM(almoxarifado_saida_item_entrada_item.quantidade_saida)
FROM almoxarifado_saida_item_entrada_item
JOIN almoxarifado_saida_item
ON almoxarifado_saida_item.id = almoxarifado_saida_item_entrada_item.saida_item_id
JOIN almoxarifado_saida
ON almoxarifado_saida.id = almoxarifado_saida_item.saida_id
WHERE almoxarifado_saida_item_entrada_item.entrada_item_id = almoxarifado_entrada_item.id
AND almoxarifado_saida.finalizada = 1
), 0)
-
COALESCE((
SELECT SUM(almoxarifado_reserva_item_entrada_item.quantidade_saida)
FROM almoxarifado_reserva_item_entrada_item
JOIN almoxarifado_reserva_item
ON almoxarifado_reserva_item.id = almoxarifado_reserva_item_entrada_item.reserva_item_id
WHERE almoxarifado_reserva_item_entrada_item.entrada_item_id = almoxarifado_entrada_item.id
), 0)
), 0)";
$addWherePermissao = fn ($query) => $query
->where(function ($query) {
$query
->whereNull('cadastro_material.subgrupo_id')
->whereExists(function ($query) {
$query
->select(DB::raw(1))
->from('almoxarifado_parametrizacao_controle_estoque_grupo')
->whereColumn('almoxarifado_parametrizacao_controle_estoque_grupo.grupo_id', 'cadastro_material.grupo_id')
->where('almoxarifado_parametrizacao_controle_estoque_grupo.centro_custo_id', self::getCurrentCentroCusto()->id);
});
})
->orWhere(function ($query) {
$query
->whereNotNull('cadastro_material.subgrupo_id')
->whereExists(function ($query) {
$query
->select(DB::raw(1))
->from('almoxarifado_parametrizacao_controle_estoque_subgrupo')
->join(
'almoxarifado_parametrizacao_controle_estoque_grupo',
'almoxarifado_parametrizacao_controle_estoque_grupo.id',
'almoxarifado_parametrizacao_controle_estoque_subgrupo.parametrizacao_controle_estoque_grupo_id'
)
->whereColumn('almoxarifado_parametrizacao_controle_estoque_subgrupo.subgrupo_id', 'cadastro_material.subgrupo_id')
->where('almoxarifado_parametrizacao_controle_estoque_grupo.centro_custo_id', self::getCurrentCentroCusto()->id);
});
});
$selectSemLotes = DB::table('cadastro_material')
->select(array_merge($mainFields, [DB::raw("
NULL AS integracao_bnafar_medicamento_id,
'0' AS is_novo_lote,
NULL AS lote,
NULL AS validade_lote,
'0' AS a_vencer_ou_vencido,
{$estoqueSum} AS estoque
")]))
->join('cadastro_apresentacao', 'cadastro_apresentacao.id', 'cadastro_material.apresentacao_id')
->join('cadastro_grupo', 'cadastro_grupo.id', 'cadastro_material.grupo_id')
->leftJoin(
'cadastro_unidade_medida as apresentacao_unidade_medida',
'apresentacao_unidade_medida.id',
'cadastro_material.apresentacao_unidade_medida_id'
)
->leftJoin('cadastro_subgrupo', 'cadastro_subgrupo.id', 'cadastro_material.subgrupo_id')
->leftJoin('almoxarifado_entrada_item', function ($join) {
$join->on('almoxarifado_entrada_item.material_id', 'cadastro_material.id')
->whereNull('almoxarifado_entrada_item.lote')
->whereExists(function ($query) {
$query
->select(DB::raw('1'))
->from('almoxarifado_entrada')
->whereColumn('almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->where('almoxarifado_entrada.finalizada', true)
->where('almoxarifado_entrada.centro_custo_id', self::getCurrentCentroCusto()->id);
});
})
->leftJoin('almoxarifado_inventario', function ($join) {
$join->on('almoxarifado_inventario.material_id', 'cadastro_material.id')
->where('almoxarifado_inventario.finalizado', false)
->whereNull('almoxarifado_inventario.lote')
->where('almoxarifado_inventario.created_centro_custo_id', self::getCurrentCentroCusto()->id);
})
->whereNull('cadastro_material.deleted_at')
->where(function ($query) {
$query->where('cadastro_material.is_ativo', true)->orWhere(function ($query) {
$query->where('cadastro_material.is_ativo', false)->whereExists(function ($query) {
$query
->select(DB::raw('1'))
->from('almoxarifado_entrada_item')
->join(
'almoxarifado_entrada',
'almoxarifado_entrada.id',
'almoxarifado_entrada_item.entrada_id'
)
->whereColumn('almoxarifado_entrada_item.material_id', 'cadastro_material.id')
->where('almoxarifado_entrada.finalizada', true)
->where('almoxarifado_entrada.centro_custo_id', self::getCurrentCentroCusto()->id);
});
});
})
->where(fn ($query) => $addWherePermissao($query))
->when(request()->query('grupo_id'), fn ($q, $id) => $q->where('cadastro_grupo.id', $id))
->when(request()->query('subgrupo_id'), fn ($q, $id) => $q->where('cadastro_subgrupo.id', $id))
->groupBy(
'cadastro_material.id',
'cadastro_material.codigo_material',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
)),
'cadastro_grupo.nome',
'cadastro_subgrupo.nome',
'cadastro_material.is_ativo',
'almoxarifado_inventario.contagem',
DB::raw("NULL"),
DB::raw("'0'"),
DB::raw("NULL"),
DB::raw("NULL"),
DB::raw("'0'")
);
$selectComLotes = DB::table('cadastro_material')
->select(array_merge($mainFields, [DB::raw("
NULL AS integracao_bnafar_medicamento_id,
'0' AS is_novo_lote,
almoxarifado_entrada_item.lote,
DATE_FORMAT(almoxarifado_entrada_item.validade_lote, '%d/%m/%Y') AS validade_lote,
IF(DATEDIFF(almoxarifado_entrada_item.validade_lote, CURRENT_DATE) < 90, '1', '0') AS a_vencer_ou_vencido,
{$estoqueSum} AS estoque
")]))
->join('cadastro_apresentacao', 'cadastro_apresentacao.id', 'cadastro_material.apresentacao_id')
->join('cadastro_grupo', 'cadastro_grupo.id', 'cadastro_material.grupo_id')
->join('almoxarifado_entrada_item', function ($join) {
$join->on('almoxarifado_entrada_item.material_id', 'cadastro_material.id')
->whereExists(function ($query) {
$query
->select(DB::raw('1'))
->from('almoxarifado_entrada')
->whereColumn('almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->where('almoxarifado_entrada.finalizada', true)
->where('almoxarifado_entrada.centro_custo_id', self::getCurrentCentroCusto()->id);
});
})
->leftJoin(
'cadastro_unidade_medida as apresentacao_unidade_medida',
'apresentacao_unidade_medida.id',
'cadastro_material.apresentacao_unidade_medida_id'
)
->leftJoin('cadastro_subgrupo', 'cadastro_subgrupo.id', 'cadastro_material.subgrupo_id')
->leftJoin('almoxarifado_inventario', function ($join) {
$join->on('almoxarifado_inventario.material_id', 'cadastro_material.id')
->where('almoxarifado_inventario.finalizado', false)
->where('almoxarifado_inventario.is_novo_lote', false)
->whereNotNull('almoxarifado_inventario.lote')
->whereColumn('almoxarifado_inventario.lote', 'almoxarifado_entrada_item.lote')
->whereColumn('almoxarifado_inventario.validade_lote', 'almoxarifado_entrada_item.validade_lote')
->where('almoxarifado_inventario.created_centro_custo_id', self::getCurrentCentroCusto()->id);
})
->whereNull('cadastro_material.deleted_at')
->whereNotNull('almoxarifado_entrada_item.lote')
->where(fn ($query) => $addWherePermissao($query))
->when(request()->query('grupo_id'), fn ($q, $id) => $q->where('cadastro_grupo.id', $id))
->when(request()->query('subgrupo_id'), fn ($q, $id) => $q->where('cadastro_subgrupo.id', $id))
->groupBy(
'cadastro_material.id',
'cadastro_material.codigo_material',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
)),
'cadastro_grupo.nome',
'cadastro_subgrupo.nome',
'cadastro_material.is_ativo',
'almoxarifado_inventario.contagem',
DB::raw("NULL"),
DB::raw("'0'"),
'almoxarifado_entrada_item.lote',
DB::raw("DATE_FORMAT(almoxarifado_entrada_item.validade_lote, '%d/%m/%Y')"),
DB::raw("IF(DATEDIFF(almoxarifado_entrada_item.validade_lote, CURRENT_DATE) < 90, 1, 0)")
)
->havingRaw("estoque > 0");
$selectNovosLotes = DB::table('cadastro_material')
->select(array_merge($mainFields, [DB::raw("
almoxarifado_inventario.integracao_bnafar_medicamento_id,
'1' AS is_novo_lote,
almoxarifado_inventario.lote,
DATE_FORMAT(almoxarifado_inventario.validade_lote, '%d/%m/%Y') AS validade_lote,
IF(DATEDIFF(almoxarifado_inventario.validade_lote, CURRENT_DATE) < 90, '1', '0') AS a_vencer_ou_vencido,
0 AS estoque
")]))
->join('cadastro_apresentacao', 'cadastro_apresentacao.id', 'cadastro_material.apresentacao_id')
->join('cadastro_grupo', 'cadastro_grupo.id', 'cadastro_material.grupo_id')
->join('almoxarifado_inventario', 'almoxarifado_inventario.material_id', 'cadastro_material.id')
->leftJoin('cadastro_subgrupo', 'cadastro_subgrupo.id', 'cadastro_material.subgrupo_id')
->leftJoin(
'cadastro_unidade_medida as apresentacao_unidade_medida',
'apresentacao_unidade_medida.id',
'cadastro_material.apresentacao_unidade_medida_id'
)
->whereNull('cadastro_material.deleted_at')
->where('almoxarifado_inventario.finalizado', false)
->where('almoxarifado_inventario.is_novo_lote', true)
->where('almoxarifado_inventario.created_centro_custo_id', self::getCurrentCentroCusto()->id)
->when(request()->query('grupo_id'), fn ($q, $id) => $q->where('cadastro_grupo.id', $id))
->when(request()->query('subgrupo_id'), fn ($q, $id) => $q->where('cadastro_subgrupo.id', $id))
->where(fn ($query) => $addWherePermissao($query));
return$selectSemLotes
->unionAll($selectComLotes)
->unionAll($selectNovosLotes)
->orderBy('descricao')
->get()
->each(function ($material) {
$material->is_novo_lote = $material->is_novo_lote === '1';
$material->a_vencer_ou_vencido = $material->a_vencer_ou_vencido === '1';
});
}
public static function list()
{
return [
'additionals' => [
'data_atual' => Carbon::now()->format('d/m/Y'),
],
'form' => [
'has_inventario_nao_finalizado' => self::getInventariosNaoFinalizadosBuilder()->get()->isNotEmpty(),
'grupos' => Grupo::whereHas('almoxarifadoParametrizacoesControleEstoqueGrupo', function ($query) {
$query->where('centro_custo_id', self::getCurrentCentroCusto()->id);
})
->orderBy('nome')
->get()
->map(fn ($grupo) => [
'id' => $grupo->id,
'nome' => $grupo->nome,
'subgrupos' => $grupo->subgrupos()
->whereHas('almoxarifadoParametrizacoesControleEstoqueSubgrupo')
->orderBy('nome')
->get()
->map(fn ($subgrupo) => [
'id' => $subgrupo->id,
'nome' => $subgrupo->nome,
])
]),
'grupo_id' => null,
'subgrupo_id' => null,
]
];
}
public static function store()
{
self::validate();
DB::transaction(function () {
$itensData = collect(self::getItensData());
self::deleteContagensExcluidas($itensData);
$contagens = self::saveContagens($itensData);
if (request()->finalizar) {
self::ajustarEstoque($contagens);
}
});
}
private static function getInventariosNaoFinalizadosBuilder()
{
return Inventario::where('finalizado', false)
->where('created_centro_custo_id', self::getCurrentCentroCusto()->id)
->whereHas('material', function ($query) {
$query->where(function ($query) {
$query
->whereNull('subgrupo_id')
->whereHas('grupo', function ($query) {
$query->whereHas('almoxarifadoParametrizacoesControleEstoqueGrupo', function ($query) {
$query->where('centro_custo_id', self::getCurrentCentroCusto()->id);
});
});
})->orWhere(function ($query) {
$query
->whereNotNull('subgrupo_id')
->whereHas('grupo', function ($query) {
$query->whereHas('almoxarifadoParametrizacoesControleEstoqueGrupo', function ($query) {
$query->where('centro_custo_id', self::getCurrentCentroCusto()->id);
});
})
->whereHas('subgrupo', function ($query) {
$query->whereHas('almoxarifadoParametrizacoesControleEstoqueSubgrupo');
});
});
});
}
private static function getItensData()
{
$itens = request()->itens;
foreach ($itens as &$item) {
if (!is_null($item['validade_lote'])) {
$item['validade_lote'] = Carbon::createFromFormat('d/m/Y', $item['validade_lote']);
}
}
unset($item);
return $itens;
}
private static function deleteContagensExcluidas(&$itensData)
{
$itensData
->filter(fn ($i) => is_null($i['contagem']) && !$i['is_novo_lote'])
->each(function ($itemData) {
$itemComContagemExcluida = self::getInventariosNaoFinalizadosBuilder()
->where('material_id', $itemData['material_id'])
->where('is_novo_lote', false)
->where('lote', $itemData['lote'])
->when($itemData['validade_lote'], fn ($q, $v) => $q->whereDate('validade_lote', $v))
->first();
if (!is_null($itemComContagemExcluida)) {
$itemComContagemExcluida->delete();
}
});
}
private static function saveContagens($itensData)
{
$contagens = collect();
$finalizado = request()->finalizar;
$finalizadoEm = $finalizado ? Carbon::now() : null;
$itensData
->filter(fn ($i) => !is_null($i['contagem']) || $i['is_novo_lote'])
->each(function ($itemData) use ($contagens, $finalizado, $finalizadoEm) {
$inventario = self::getInventariosNaoFinalizadosBuilder()
->where('material_id', $itemData['material_id'])
->where('is_novo_lote', $itemData['is_novo_lote'])
->where('lote', $itemData['lote'])
->when($itemData['validade_lote'], fn ($q, $v) => $q->whereDate('validade_lote', $v))
->first();
if ($itemData['is_novo_lote'] && $itemData['deleted']) {
if (!is_null($inventario)) {
$inventario->delete();
}
}
else {
if (is_null($inventario)) {
$inventario = new Inventario([
'material_id' => $itemData['material_id'],
'lote' => $itemData['lote'],
'validade_lote' => $itemData['validade_lote'],
]);
}
$inventario->integracao_bnafar_medicamento_id = $itemData['integracao_bnafar_medicamento_id'];
$inventario->finalizado = $finalizado;
$inventario->finalizado_em = $finalizadoEm;
$inventario->contagem = $itemData['contagem'];
$inventario->is_novo_lote = $itemData['is_novo_lote'];
$inventario->save();
$contagens->push($inventario);
}
});
return $contagens;
}
public static function ajustarEstoque($contagens)
{
$itens = collect();
$contagens->each(function ($contagem) use ($itens) {
$item = $itens
->where('material_id', $contagem->material_id)
->where('lote', $contagem->lote)
->first();
if (!is_null($item)
&& $item['validade_lote']->format('d/m/Y') === $contagem->validade_lote->format('d/m/Y')
) {
$item['contagem'] += (int)$contagem->contagem;
}
else {
$itens->push(collect([
'material_id' => $contagem->material_id,
'integracao_bnafar_medicamento_id' => $contagem->integracao_bnafar_medicamento_id,
'lote' => $contagem->lote,
'validade_lote' => $contagem->validade_lote,
'contagem' => (int)$contagem->contagem,
]));
}
});
AlmoxarifadoService::saveAjusteDeEstoqueDeInventario($itens);
}
public static function validate()
{
$rules = [
'finalizar' => [
'required',
'boolean',
],
'itens' => [
'present',
'array',
],
'itens.*.material_id' => [
'required',
'integer',
Rule::exists(Material::class, 'id'),
],
'itens.*.lote' => [
'nullable',
'string',
'max:15',
],
'itens.*.validade_lote' => [
'nullable',
'date_format:d/m/Y',
],
'itens.*.contagem' => [
'nullable',
'integer',
'between:0,99999999',
],
'itens.*.is_novo_lote' => [
'required',
'boolean',
],
'itens.*.deleted' => [
'required',
'boolean',
]
];
$messages = [];
request()->validate($rules, $messages);
}
public static function getIntegracaoBnafarMedicamentos()
{
return DB::table('integracao_bnafar_medicamento')
->select([
'integracao_bnafar_medicamento.id AS medicamento_id',
'integracao_bnafar_medicamento.codigo AS medicamento_codigo',
'integracao_bnafar_medicamento.descricao AS medicamento_descricao',
])
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('cadastro_material_integracao_bnafar_medicamento')
->where('cadastro_material_integracao_bnafar_medicamento.material_id', request()->material_id)
->whereColumn('cadastro_material_integracao_bnafar_medicamento.medicamento_id', 'integracao_bnafar_medicamento.id');
})
->get();
}
}

View File

@@ -0,0 +1,101 @@
<?php
namespace App\Services\Almoxarifado;
use App\Models\Almoxarifado\MotivoBaixa;
use App\Models\Almoxarifado\MotivoBaixaTipo;
use App\Services\Service;
use DB;
class MotivoBaixaService extends Service
{
public static function datatable()
{
$motivosBaixa = DB::table('almoxarifado_motivo_baixa')
->leftJoin(
'almoxarifado_motivo_baixa_tipo',
'almoxarifado_motivo_baixa_tipo.id',
'almoxarifado_motivo_baixa.tipo_id'
)
->select(
'almoxarifado_motivo_baixa.id',
DB::raw('almoxarifado_motivo_baixa_tipo.nome as tipo'),
'almoxarifado_motivo_baixa.descricao',
DB::raw('DECODE_ORACLE(almoxarifado_motivo_baixa.justificar, 1, "Sim", "Não") AS justificar')
)
->whereNull('almoxarifado_motivo_baixa.deleted_at');
return $motivosBaixa;
}
public static function create()
{
$motivoBaixa = new MotivoBaixa;
$motivoBaixa->fill(array_fill_keys($motivoBaixa->getFillable(), null));
return [
'form' => [
'tipos' => MotivoBaixaTipo::orderBy('nome')->get(['id', 'nome'])
],
'model' => $motivoBaixa->makeHidden(['id'])
];
}
public static function store()
{
self::validate();
return MotivoBaixa::create(request()->all())->fresh();
}
public static function edit($id)
{
$motivoBaixa = MotivoBaixa::findOrFail($id);
return [
'form' => [
'tipos' => MotivoBaixaTipo::orderBy('nome')->get(['id', 'nome'])
],
'model' => $motivoBaixa->makeHidden(['id'])
];
}
public static function update($id)
{
self::validate();
$motivoBaixa = tap(MotivoBaixa::findOrFail($id))->update(request()->all());
return $motivoBaixa->fresh();
}
public static function validate()
{
$rule = [
'tipo_id' => [
'nullable',
'integer',
],
'descricao' => [
'string',
'required',
'between:3,100',
'unique:\App\Models\Almoxarifado\MotivoBaixa,descricao,'
. (request()->route('motivo_baixa') ?? 'NULL') . ',id,deleted_at,NULL',
]
];
$messages = [
'descricao.unique' => 'A descrição do Motivo de baixa já foi inserido anteriormente.',
];
request()->validate($rule, $messages);
}
public static function destroy($id)
{
MotivoBaixa::findOrFail($id)->delete();
return null;
}
}

View File

@@ -0,0 +1,702 @@
<?php
namespace App\Services\Almoxarifado;
use App\Enums\Cadastro\Grupo\GrupoTipo;
use App\Models\Almoxarifado\ParametrizacaoControleEstoqueGrupo;
use App\Models\Almoxarifado\ParametrizacaoDispensacaoMateriais;
use App\Models\Almoxarifado\ParametrizacaoDispensacaoUnidade;
use App\Models\Almoxarifado\ParametrizacaoEstoque;
use App\Models\Almoxarifado\ParametrizacaoRequisicao;
use App\Models\Almoxarifado\RequisicaoPermissao;
use App\Models\Almoxarifado\ParametrizacaoPortalDivulgacaoGrupo;
use App\Models\Cadastro\Estabelecimento\CentroCusto;
use App\Models\Cadastro\Estabelecimento\Infraestrutura;
use App\Models\Cadastro\Estabelecimento\Unidade;
use App\Models\Cadastro\Grupo\Grupo;
use App\Models\Cadastro\Material\Material;
use App\Models\Cadastro\Subgrupo\Subgrupo;
use App\Services\Service;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
class ParametrizacaoService extends Service
{
public static function getParametrizacaoRequisicao()
{
$parametrizacaoRequisicao = ParametrizacaoRequisicao::first();
return [
'numero_requisicao_automatico' => $parametrizacaoRequisicao
->numero_requisicao_automatico ?? false,
'permite_requisitar_materiais_sem_estoque' => $parametrizacaoRequisicao
->permite_requisitar_materiais_sem_estoque ?? false,
'prazo_validade' => $parametrizacaoRequisicao->prazo_validade
];
}
public static function getNovoNumeroRequisicao()
{
return Carbon::now()->format('ymdHis');
}
public static function controlaEstoque($materialId, $centroCustoId = null)
{
$material = Material::findOrFail($materialId);
if (is_null($centroCustoId)) {
$centroCustoId = self::getCurrentCentroCusto()->id;
}
return ParametrizacaoControleEstoqueGrupo::where('centro_custo_id', $centroCustoId)
->where('grupo_id', $material->grupo_id)
->when($material->subgrupo_id, function ($query, $subgrupoId) {
$query->whereHas('subgrupos', fn ($query) => $query->where('subgrupo_id', $subgrupoId));
})
->exists();
}
public static function list()
{
switch (request()->origem) {
case 'portal-divulgacao': {
switch (request()->listar) {
case 'infraestruturas': {
return Infraestrutura::setEagerLoads([])
->where('unidade_id', request()->unidade_id)
->whereHas('centrosCusto')
->get(['id', 'nome', 'principal', 'unidade_id'])
->map(fn ($infraestrutura) => [
'id' => $infraestrutura->id,
'nome' => $infraestrutura->nome
])
->sortBy('nome')
->values();
}
case 'centros-custo': {
return CentroCusto::where('infraestrutura_id', request()->infraestrutura_id)
->get(['id', 'setor_id'])
->map(fn ($centroCusto) => [
'id' => $centroCusto->id,
'setor_nome' => $centroCusto->setor->nome
])
->sortBy('setor_nome')
->values();
}
case 'grupos': {
return Grupo::whereIn('grupo_tipo_id', [GrupoTipo::MEDICAMENTO, GrupoTipo::MATERIAL])->get(['id', 'nome'])->map(function ($grupo) {
$parametrizacao = $grupo->almoxarifadoParametrizacoesPortalDivulgacaoGrupo()
->where('centro_custo_id', request()->centro_custo_id)
->first();
$permiteControlar = false;
if (!is_null($parametrizacao)) {
$permiteControlar = true;
}
return [
'id' => $grupo->id,
'centro_custo_id' => request()->centro_custo_id,
'nome' => $grupo->nome,
'permite_controlar' => $permiteControlar,
'subgrupos' => $grupo->subgrupos()
->whereHas('materiais', fn ($q) => $q->where('is_ativo', true))
->get(['id', 'nome'])->map(function ($subgrupo) {
$parametrizacao = $subgrupo->almoxarifadoParametrizacoesPortalDivulgacaoSubgrupo()
->whereHas('parametrizacaoPortalDivulgacaoGrupo', fn ($q) => $q
->where('centro_custo_id', request()->centro_custo_id)
)
->first();
$permiteControlar = false;
if (!is_null($parametrizacao)) {
$permiteControlar = true;
}
return [
'id' => $subgrupo->id,
'nome' => $subgrupo->nome,
'permite_controlar' => $permiteControlar,
];
}),
];
});
}
case 'item-grupos': {
$grupo = Grupo::where('id', request()->grupo_id)
->first(['id', 'nome']);
$parametrizacao = $grupo->almoxarifadoParametrizacoesPortalDivulgacaoGrupo()
->where('centro_custo_id', request()->centro_custo_id)
->first();
return [
'id' => $grupo->id,
'nome' => $grupo->nome,
'permite_controlar' => !is_null($parametrizacao),
'materiais' => $grupo->materiais()
->where('is_ativo', true)
->when(
request()->filled('subgrupo_ids'),
fn ($query) => $query->whereIn('subgrupo_id', request()->subgrupo_ids)
)
->get(['id', 'descricao as nome'])
->map(function ($material) use ($parametrizacao){
if (!is_null($parametrizacao)) {
$permiteControlar = $material->parametrizacaoPortalDivulgacaoMaterialgrupo()
->where('parametrizacao_portal_divulgacao_grupo_id', $parametrizacao->id)
->exists();
}
else {
$permiteControlar = !request()->filled('subgrupo_ids');
}
return [
'id' => $material->id,
'nome' => $material->nome,
'permite_controlar' => $permiteControlar
];
})
->values()
->toArray(),
];
}
}
}
case 'controle-estoque': {
switch (request()->listar) {
case 'infraestruturas': {
return Infraestrutura::setEagerLoads([])
->where('unidade_id', request()->unidade_id)
->whereHas('centrosCusto')
->get(['id', 'nome', 'principal', 'unidade_id'])
->map(fn ($infraestrutura) => [
'id' => $infraestrutura->id,
'nome' => $infraestrutura->nome
])
->sortBy('nome')
->values();
}
case 'centros-custo': {
return CentroCusto::where('infraestrutura_id', request()->infraestrutura_id)
->get(['id', 'setor_id'])
->map(fn ($centroCusto) => [
'id' => $centroCusto->id,
'setor_nome' => $centroCusto->setor->nome
])
->sortBy('setor_nome')
->values();
}
case 'grupos': {
return Grupo::get(['id', 'nome'])->map(function ($grupo) {
$parametrizacao = $grupo->almoxarifadoParametrizacoesControleEstoqueGrupo()
->where('centro_custo_id', request()->centro_custo_id)
->first();
$permiteControlar = false;
$hasPermissaoRequisicao = false;
if (!is_null($parametrizacao)) {
$permiteControlar = true;
$hasPermissaoRequisicao = RequisicaoPermissao::where(
'created_centro_custo_id',
request()->centro_custo_id
)
->whereHas('material', fn ($q) => $q->where('grupo_id', $grupo->id))
->exists();
}
return [
'id' => $grupo->id,
'nome' => $grupo->nome,
'permite_controlar' => $permiteControlar,
'has_permissao_requisicao' => $hasPermissaoRequisicao,
'subgrupos' => $grupo->subgrupos()->get(['id', 'nome'])->map(function ($subgrupo) {
$parametrizacao = $subgrupo->almoxarifadoParametrizacoesControleEstoqueSubgrupo()
->whereHas('parametrizacaoControleEstoqueGrupo', fn ($q) => $q
->where('centro_custo_id', request()->centro_custo_id)
)
->first();
$permiteControlar = false;
$hasPermissaoRequisicao = false;
if (!is_null($parametrizacao)) {
$permiteControlar = true;
$hasPermissaoRequisicao = RequisicaoPermissao::where(
'created_centro_custo_id',
request()->centro_custo_id
)
->whereHas('material', fn ($q) => $q->where('subgrupo_id', $subgrupo->id))
->exists();
}
return [
'id' => $subgrupo->id,
'nome' => $subgrupo->nome,
'permite_controlar' => $permiteControlar,
'has_permissao_requisicao' => $hasPermissaoRequisicao,
];
}),
];
});
}
}
}
case 'estoque-minimo-maximo': {
switch (request()->listar) {
case 'infraestruturas': {
return Infraestrutura::setEagerLoads([])
->where('unidade_id', request()->unidade_id)
->whereHas('centrosCusto', fn ($q) => $q
->whereHas('almoxarifadoParametrizacoesControleEstoqueGrupo')
)
->get(['id', 'nome', 'principal', 'unidade_id'])
->map(fn ($infraestrutura) => [
'id' => $infraestrutura->id,
'nome' => $infraestrutura->nome
])
->sortBy('nome')
->values();
}
case 'centros-custo': {
return CentroCusto::whereHas('almoxarifadoParametrizacoesControleEstoqueGrupo')
->where('infraestrutura_id', request()->infraestrutura_id)
->get(['id', 'setor_id'])
->map(fn ($centroCusto) => [
'id' => $centroCusto->id,
'setor_nome' => $centroCusto->setor->nome
])
->sortBy('setor_nome')
->values();
}
case 'grupos': {
return Grupo::whereHas(
'almoxarifadoParametrizacoesControleEstoqueGrupo',
fn ($query) => $query->where('centro_custo_id', request()->centro_custo_id)
)
->get()
->map(fn ($grupo) => [
'id' => $grupo->id,
'nome' => $grupo->nome,
'materiais' => $grupo->materiais()
->where('is_ativo', true)
->where(fn ($query) => $query
->whereNull('subgrupo_id')
->orWhereHas('subgrupo', fn ($query) => $query
->whereHas(
'almoxarifadoParametrizacoesControleEstoqueSubgrupo',
fn ($query) => $query->whereHas(
'parametrizacaoControleEstoqueGrupo',
fn ($query) => $query
->where('centro_custo_id', request()->centro_custo_id)
)
)
)
)
->get()
->map(function ($material) {
$parametrizacao = ParametrizacaoEstoque::where(
'centro_custo_id',
request()->centro_custo_id
)
->where('material_id', $material->id)
->first();
return [
'id' => $material->id,
'codigo' => $material->codigo_material,
'descricao' => $material->descricao_completa,
'subgrupo_id' => $material->subgrupo_id,
'subgrupo_nome' => $material->subgrupo->nome ?? null,
'estoque_minimo' => $parametrizacao->estoque_minimo ?? null,
'estoque_maximo' => $parametrizacao->estoque_maximo ?? null,
];
}),
]);
}
}
}
}
}
public static function create()
{
$parametrizacaoRequisicao = ParametrizacaoRequisicao::first();
return [
'requisicao' => [
'model' => [
'numero_requisicao_automatico' => $parametrizacaoRequisicao
->numero_requisicao_automatico ?? false,
'permite_requisitar_materiais_sem_estoque' => $parametrizacaoRequisicao
->permite_requisitar_materiais_sem_estoque ?? false,
'prazo_validade' => $parametrizacaoRequisicao->prazo_validade ?? null,
'motivo_obrigatorio' => $parametrizacaoRequisicao->motivo_obrigatorio ?? false,
],
],
'controle_estoque' => [
'form' => [
'unidades' => Unidade::whereHas('infraestruturas', fn ($q) => $q->whereHas('centrosCusto'))
->orderBy('nome_fantasia')
->get(['id', 'nome_fantasia']),
'infraestruturas' => [],
'centrosCusto' => [],
],
'model' => [
'centros_custo' => CentroCusto::whereHas('almoxarifadoParametrizacoesControleEstoqueGrupo')
->get()
->map(fn ($centroCusto) => [
'id' => $centroCusto->id,
'setor_nome' => $centroCusto->setor->nome,
'local_atendimento_nome' => $centroCusto->infraestrutura->nome,
'unidade_nome_fantasia' => $centroCusto->infraestrutura->unidade->nome_fantasia,
'grupos' => [],
'is_saved' => true,
])
]
],
'portal_divulgacao' => [
'form' => [
'unidades' => Unidade::whereHas('infraestruturas', fn ($q) => $q->whereHas('centrosCusto'))
->orderBy('nome_fantasia')
->get(['id', 'nome_fantasia']),
'infraestruturas' => [],
'centrosCusto' => [],
],
'model' => [
'portal_centros_custo' => CentroCusto::whereHas('almoxarifadoParametrizacoesPortalDivulgacaoGrupo')
->get()
->map(fn ($centroCusto) => [
'id' => $centroCusto->id,
'setor_nome' => $centroCusto->setor->nome,
'local_atendimento_nome' => $centroCusto->infraestrutura->nome,
'unidade_nome_fantasia' => $centroCusto->infraestrutura->unidade->nome_fantasia,
'grupos' => [],
'is_saved' => true,
])
]
],
'dispensacao_materiais' => [
'form' => [
'unidades' => Unidade::whereHas('infraestruturas', fn ($q) => $q->whereHas('centrosCusto'))
->orderBy('nome_fantasia')
->get(['id', 'nome_fantasia']),
'infraestruturas' => [],
'centrosCusto' => [],
],
'model' => [
'centros_custo' => CentroCusto::has('almoxarifadoParametrizacaoDispensacaoUnidades')
->get()->map(fn($centroCusto) => [
'id' => $centroCusto->id,
'setor_nome' => $centroCusto->setor->nome,
'local_atendimento_nome' => $centroCusto->infraestrutura->nome,
'unidade_nome_fantasia' => $centroCusto->infraestrutura->unidade->nome_fantasia,
]
),
'grupos' => Grupo::with('materiais')->where('grupo_tipo_id', GrupoTipo::MATERIAL)->get()->map(fn($grupo) => [
'id' => $grupo->id,
'dispensar' => $grupo->almoxarifadoParametrizacoesDispensarMateriais->isNotEmpty(),
'nome' => $grupo->nome,
'materiais' => $grupo->materiais->map(fn($material) => [
'id' => $material->id,
'descricao' => $material->descricao,
'grupo_id' => $material->grupo_id,
'dispensar' => $material->almoxarifadoParametrizacaoDispensacao->isNotEmpty() || $material->grupo->almoxarifadoParametrizacoesDispensarMateriais->isNotEmpty()
])
]),
]
],
'estoque' => [
'form' => [
'unidades' => Unidade::whereHas('infraestruturas', fn ($q) => $q->whereHas(
'centrosCusto',
fn ($q) => $q->whereHas('almoxarifadoParametrizacoesControleEstoqueGrupo')
))
->orderBy('nome_fantasia')
->get(['id', 'nome_fantasia']),
'infraestruturas' => [],
'centrosCusto' => [],
],
'model' => [
'centros_custo' => CentroCusto::whereHas('almoxarifadoParametrizacoesEstoque')
->get()
->map(fn ($centroCusto) => [
'id' => $centroCusto->id,
'setor_nome' => $centroCusto->setor->nome,
'local_atendimento_nome' => $centroCusto->infraestrutura->nome,
'unidade_nome_fantasia' => $centroCusto->infraestrutura->unidade->nome_fantasia,
'grupos' => [],
'is_saved' => true,
])
],
],
];
}
public static function store()
{
self::validate();
DB::transaction(function () {
self::saveParametrizacaoRequisicao(request()->requisicao);
self::saveParametrizacaoControleEstoque(request()->controle_estoque);
self::saveParametrizacaoDispensacaoMateriais(request()->dispensacao_materiais);
self::saveParametrizacaoEstoque(request()->estoque);
self::saveParametrizacaoPortalDivulgacao(request()->portal_divulgacao);
});
}
private static function saveParametrizacaoRequisicao($data)
{
ParametrizacaoRequisicao::updateOrCreate(
['id' => ParametrizacaoRequisicao::first()->id ?? null],
$data
);
}
private static function saveParametrizacaoControleEstoque($data)
{
collect($data['centros_custo'])->each(function ($centroCustoData) {
$centroCusto = CentroCusto::findOrFail($centroCustoData['id']);
$centroCusto->almoxarifadoParametrizacoesControleEstoqueGrupo()
->whereNotIn('grupo_id', collect($centroCustoData['grupos'])->pluck('id'))
->delete();
foreach ($centroCustoData['grupos'] as $grupo) {
$parametrizacaoGrupo = $centroCusto->almoxarifadoParametrizacoesControleEstoqueGrupo()
->updateOrCreate([
'centro_custo_id' => $centroCusto->id,
'grupo_id' => $grupo['id'],
]);
$parametrizacaoGrupo->subgrupos()
->whereNotIn('subgrupo_id', $grupo['subgrupos'])
->delete();
$parametrizacaoGrupo->subgrupos()
->createMany(collect($grupo['subgrupos'])->map(fn ($sg) => ['subgrupo_id' => $sg]));
}
});
}
private static function saveParametrizacaoPortalDivulgacao($data)
{
collect($data['portal_centros_custo'])->each(function ($centroCustoData) {
$centroCusto = CentroCusto::findOrFail($centroCustoData['id']);
$centroCusto->almoxarifadoParametrizacoesPortalDivulgacaoGrupo()
->whereNotIn('grupo_id', collect($centroCustoData['grupos'])->pluck('id'))
->delete();
foreach ($centroCustoData['grupos'] as $grupo) {
$parametrizacaoGrupo = $centroCusto->almoxarifadoParametrizacoesPortalDivulgacaoGrupo()
->updateOrCreate([
'centro_custo_id' => $centroCusto->id,
'grupo_id' => $grupo['id'],
]);
$materiaisIds = collect($grupo['materiais'])
->map(fn($sg) => is_array($sg) ? $sg['id'] ?? null : $sg)
->filter()
->unique()
->toArray();
if (!empty($materiaisIds)) {
$parametrizacaoGrupo->material()
->whereNotIn('material_id', $materiaisIds)
->delete();
}
foreach ($materiaisIds as $materialId) {
$parametrizacaoGrupo->material()->firstOrCreate([
'material_id' => $materialId
]);
}
$subgrupoIds = collect($grupo['subgrupos'])
->map(fn($sg) => is_array($sg) ? $sg['id'] ?? null : $sg)
->filter()
->unique()
->toArray();
$parametrizacaoGrupo->subgrupos()
->whereNotIn('subgrupo_id', $subgrupoIds)
->delete();
foreach ($subgrupoIds as $subgrupoId) {
$parametrizacaoGrupo->subgrupos()->firstOrCreate([
'subgrupo_id' => $subgrupoId
]);
}
}
});
}
private static function saveParametrizacaoDispensacaoMateriais($data)
{
ParametrizacaoDispensacaoUnidade::truncate();
collect($data['centros_custo'])->each(function($centroCusto) {
ParametrizacaoDispensacaoUnidade::create(
['centro_custo_id' => $centroCusto['id']]
);
});
ParametrizacaoDispensacaoMateriais::truncate();
collect($data['grupos'])->each(function($grupo) {
if($grupo['dispensar']) {
ParametrizacaoDispensacaoMateriais::create([
'grupo_id' => $grupo['id']
]);
} else {
collect($grupo['materiais'])->each(function($material) {
if($material['dispensar']) {
ParametrizacaoDispensacaoMateriais::create([
'material_id' => $material['id']
]);
}
});
}
});
}
private static function saveParametrizacaoEstoque($data)
{
$centrosCusto = collect($data['centros_custo']);
$centrosCusto->each(function ($centroCustoData) {
foreach ($centroCustoData['materiais'] as $material) {
if (!is_null($material['estoque_minimo']) || !is_null($material['estoque_maximo'])) {
ParametrizacaoEstoque::updateOrCreate(
[
'centro_custo_id' => $centroCustoData['id'],
'material_id' => $material['id'],
],
[
'estoque_minimo' => $material['estoque_minimo'],
'estoque_maximo' => $material['estoque_maximo'],
]
);
}
else {
ParametrizacaoEstoque::where('centro_custo_id', $centroCustoData['id'])
->where('material_id', $material['id'])
->delete();
}
}
});
}
public static function validate()
{
$rules = [
'requisicao.numero_requisicao_automatico' => [
'required',
'boolean'
],
'requisicao.permite_requisitar_materiais_sem_estoque' => [
'required',
'boolean'
],
'controle_estoque.centros_custo' => [
'present',
'array',
],
'controle_estoque.centros_custo.*.id' => [
'required',
'integer',
Rule::exists(CentroCusto::class, 'id'),
],
'controle_estoque.centros_custo.*.grupos' => [
'array',
],
'controle_estoque.centros_custo.*.grupos.*.id' => [
'integer',
Rule::exists(Grupo::class, 'id'),
],
'controle_estoque.centros_custo.*.grupos.*.subgrupos' => [
'array',
],
'controle_estoque.centros_custo.*.grupos.*.subgrupos.*' => [
'integer',
Rule::exists(Subgrupo::class, 'id'),
],
'estoque.centros_custo' => [
'present',
'array',
],
'estoque.centros_custo.*.id' => [
'required',
'integer',
Rule::exists(CentroCusto::class, 'id'),
],
'estoque.centros_custo.*.materiais' => [
'array',
],
'estoque.centros_custo.*.materiais.*.id' => [
'integer',
Rule::exists(Material::class, 'id'),
],
'estoque.centros_custo.*.materiais.*.estoque_minimo' => [
'nullable',
'integer',
],
'estoque.centros_custo.*.materiais.*.estoque_maximo' => [
'nullable',
'integer',
],
];
$messages = [];
request()->validate($rules, $messages);
}
}

View File

@@ -0,0 +1,240 @@
<?php
namespace App\Services\Almoxarifado\Relatorios;
use App\Models\Almoxarifado\DocumentoTipo;
use App\Models\Cadastro\Estabelecimento\CentroCusto;
use App\Models\Cadastro\Estabelecimento\Infraestrutura;
use App\Models\Cadastro\Estabelecimento\Unidade;
use App\Models\Cadastro\Grupo\Grupo;
use App\Models\Cadastro\Material\Material;
use App\Models\Cadastro\Subgrupo\Subgrupo;
use App\Services\Cadastro\Material\MaterialService;
use App\Services\Service;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
class ConsumoFinanceiroService extends Service
{
public static function index()
{
$totalizadores = (object) ['quantidade' => 0];
$consulta = $query = DB::table('almoxarifado_saida_item')
->join(
'cadastro_material',
'almoxarifado_saida_item.material_id',
'cadastro_material.id'
)
->join(
'cadastro_apresentacao',
'cadastro_apresentacao.id',
'cadastro_material.apresentacao_id'
)
->join(
'almoxarifado_saida_item_entrada_item',
'almoxarifado_saida_item.id',
'almoxarifado_saida_item_entrada_item.saida_item_id'
)
->join(
'almoxarifado_saida',
'almoxarifado_saida_item.saida_id',
'almoxarifado_saida.id'
)
->join(
'almoxarifado_entrada_item',
'almoxarifado_saida_item_entrada_item.entrada_item_id',
'almoxarifado_entrada_item.id'
)
->leftJoin(
'almoxarifado_saida_requisicao',
'almoxarifado_saida.id',
'almoxarifado_saida_requisicao.saida_id'
)
->join(
'cadastro_centro_custo',
'cadastro_centro_custo.id',
'almoxarifado_saida.centro_custo_id'
)
->join(
'cadastro_setor',
'cadastro_setor.id',
'cadastro_centro_custo.setor_id'
)
->join(
'cadastro_infraestrutura',
'cadastro_infraestrutura.id',
'cadastro_centro_custo.infraestrutura_id'
)
->join(
'cadastro_unidade',
'cadastro_unidade.id',
'cadastro_infraestrutura.unidade_id'
)
->join(
'cadastro_grupo',
'cadastro_grupo.id',
'cadastro_material.grupo_id'
)
->leftJoin(
'cadastro_unidade_medida as apresentacao_unidade_medida',
'apresentacao_unidade_medida.id',
'cadastro_material.apresentacao_unidade_medida_id'
)
->leftJoin(
'cadastro_subgrupo',
'cadastro_material.subgrupo_id',
'cadastro_subgrupo.id'
)
->select(
DB::raw("DATE_FORMAT(almoxarifado_saida_item.created_at, '%d/%m/%Y') as data"),
'cadastro_material.codigo_material',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
) . " AS descricao"),
'almoxarifado_entrada_item.valor_unitario AS valor_unitario',
'almoxarifado_saida_item_entrada_item.quantidade_saida AS quantidade',
DB::raw('almoxarifado_entrada_item.valor_unitario * almoxarifado_saida_item_entrada_item.quantidade_saida AS valor_total'),
'cadastro_grupo.nome AS grupo',
'cadastro_subgrupo.nome AS subgrupo',
'cadastro_unidade.nome_fantasia AS unidade',
DB::raw('COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) AS infraestrutura')
)
->whereNull('almoxarifado_saida_item.estornado_em')
->when(request()->periodo['start'], fn ($q, $data) => $q
->where('almoxarifado_saida_item.created_at', '>=', Carbon::createFromFormat('d/m/Y', $data)
->setTime(0, 0, 0))
)
->when(request()->periodo['end'], fn ($q, $data) => $q
->where('almoxarifado_saida_item.created_at', '<=', Carbon::createFromFormat('d/m/Y', $data)
->setTime(23, 59, 59))
)
->when(request()->query('unidade_id'), fn ($q, $id) => $q->where('cadastro_infraestrutura.unidade_id', $id))
->when(request()->query('infraestrutura_id'), fn ($q, $id) => $q->where('cadastro_infraestrutura.id', $id))
->when(request()->query('centro_custo_id'), fn ($q, $id) => $q->where('cadastro_centro_custo.id', $id))
->when(request()->query('grupo_id'), fn ($q, $id) => $q->where('cadastro_grupo.id', $id))
->when(request()->query('subgrupo_id'), fn ($q, $id) => $q->where('cadastro_subgrupo.id', $id))
->when(request()->query('material_id'), fn ($q, $id) => $q->where('cadastro_material.id', $id))
->select(
DB::raw("DATE_FORMAT(almoxarifado_saida_item.created_at, '%d/%m/%Y') as data"),
'cadastro_material.codigo_material',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
) . " AS descricao"),
'almoxarifado_entrada_item.valor_unitario AS valor_unitario',
'almoxarifado_saida_item_entrada_item.quantidade_saida as quantidade',
DB::raw('almoxarifado_entrada_item.valor_unitario * almoxarifado_saida_item_entrada_item.quantidade_saida AS valor_total'),
'cadastro_grupo.nome AS grupo',
'cadastro_subgrupo.nome AS subgrupo',
'cadastro_unidade.nome_fantasia AS unidade',
DB::raw("COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) AS infraestrutura"),
)
->get();
$totalizadores = [
'total' => number_format($consulta->sum('valor_total'), 2, ',', '.'),
];
$consulta = $consulta->map(function ($item) use ($totalizadores) {
$item->valor_total = number_format($item->valor_total, 2, ',', '.');
$item->valor_unitario = number_format($item->valor_unitario, 2, ',', '.');
return $item;
});
return ['consulta' => $consulta, 'totalizadores' => $totalizadores];
}
public static function list()
{
$centroCustoLogado = self::getCurrentCentroCusto();
return [
'additionals' => [],
'form' => [
'tipos_documento' => DocumentoTipo::orderBy('nome')->get(['id', 'nome']),
'unidades' => Unidade::orderBy('nome_fantasia')
->whereHas('infraestruturas', function ($query) {
$query->whereHas('centrosCusto');
})
->get()
->map(fn ($unidade) => [
'id' => $unidade->id,
'nome_fantasia' => $unidade->nome_fantasia,
'infraestruturas' => $unidade->infraestruturas()
->whereHas('centrosCusto')
->get()
->sortBy('nome')
->map(fn ($infraestrutura) => [
'id' => $infraestrutura->id,
'nome' => $infraestrutura->nome,
'centros_custo' => $infraestrutura->centrosCusto()
->get()
->map(fn ($centroCusto) => [
'id' => $centroCusto->id,
'setor_nome' => $centroCusto->setor->nome,
])
->sortBy('setor_nome')
->values()
])
->values()
]),
'grupos' => Grupo::orderBy('nome')
->get()
->map(fn ($grupo) => [
'id' => $grupo->id,
'nome' => $grupo->nome,
'subgrupos' => $grupo->subgrupos()->orderBy('nome')->get(['id', 'nome'])
]),
],
'model' => [
'periodo' => [
'start' => null,
'end' => null,
],
'unidade_id' => null,
'infraestrutura_id' => null,
'centro_custo_id' => null,
'grupo_id' => null,
'subgrupo_id' => null,
'tipo_documento_id' => null,
'material_id' => null,
],
];
}
public static function getPrintExportData()
{
$resultado = self::index();
$itens = $resultado['consulta'];
$unidade = Unidade::find(request()->unidade_id);
$infraestrutura = Infraestrutura::find(request()->infraestrutura_id);
$centroCusto = CentroCusto::find(request()->centro_custo_id);
$grupo = Grupo::find(request()->grupo_id);
$subgrupo = Subgrupo::find(request()->subgrupo_id);
$material = Material::find(request()->material_id['id'] ?? null);
$tipo_documento = DocumentoTipo::find(request()->tipo_documento_id);
return [
'inicio' => request()->periodo['start'],
'fim' => request()->periodo['end'],
'unidade' => $unidade->nome_fantasia ?? 'Todas',
'infraestrutura' => $infraestrutura->nome ?? 'Todas',
'setor' => $centroCusto->setor->nome ?? 'Todos',
'grupo' => $grupo->nome ?? 'Todos',
'subgrupo' => $subgrupo->nome ?? 'Todos',
'colunas' => collect(request()->selectedCols),
'itens' => $itens,
'totalizadores' => $resultado['totalizadores'],
'tipo_documento' => $tipo_documento->nome ?? 'Todos',
'material' => $material->descricao_completa ?? 'Todos',
];
}
}

View File

@@ -0,0 +1,869 @@
<?php
namespace App\Services\Almoxarifado\Relatorios;
use App\Enums\Almoxarifado\MotivoBaixaTipo;
use App\Enums\Almoxarifado\RequisicaoRespostaStatus;
use App\Enums\Almoxarifado\SaidaTipo;
use App\Models\Cadastro\Estabelecimento\CentroCusto;
use App\Models\Cadastro\Estabelecimento\Infraestrutura;
use App\Models\Cadastro\Estabelecimento\Unidade;
use App\Models\Cadastro\Grupo\Grupo;
use App\Models\Cadastro\Material\Material;
use App\Models\Cadastro\Subgrupo\Subgrupo;
use App\Services\Cadastro\Material\MaterialService;
use App\Services\Service;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
class ConsumoMedioMensalService extends Service
{
public static function index()
{
$totalizadores = (object) [
'total' => 0,
'saldo_atual' => 0,
];
$periodo = is_null(request()->periodo) ? null : [
'start' => Carbon::createFromFormat('d/m/Y', request()->periodo['start'])->setTime(0, 0, 0),
'end' => Carbon::createFromFormat('d/m/Y', request()->periodo['end'])->setTime(23, 59, 59)
];
$intervaloMeses = $periodo['end']->copy()->floorMonth()
->diffInMonths($periodo['start']->copy()->floorMonth()) + 1;
$isCalculoEspecifico = request()->tipo_calculo === 'especifico';
$whereSaida = function ($query) use ($periodo) {
$query->where('saida.finalizada', true)
->whereBetween('saida.created_at', $periodo)
->when(request()->unidade_id, fn ($q, $id) => $q->where('infraestrutura_saida_almoxarifado.unidade_id', $id))
->when(request()->infraestrutura_id, fn ($q, $id) => $q->where('infraestrutura_saida_almoxarifado.id', $id))
->when(request()->centro_custo_id, fn ($q, $id) => $q->where('centro_custo_saida_almoxarifado.id', $id))
->where(fn ($q) => $q
->when(is_null(request()->unidade_requisitante_id)
&& is_null(request()->infraestrutura_requisitante_id)
&& is_null(request()->centro_custo_requisitante_id),
fn ($q) => $q
->where('saida.tipo_id', SaidaTipo::DISPENSACAO_FARMACIA)
->orWhere(function ($query) {
$query->where('saida.tipo_id', SaidaTipo::BAIXA)
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('almoxarifado_saida_baixa as baixa')
->join(
'almoxarifado_motivo_baixa as motivo',
'motivo.id',
'baixa.motivo_id'
)
->whereColumn('baixa.saida_id', 'saida.id')
->where('motivo.tipo_id', MotivoBaixaTipo::CONSUMO_INTERNO);
});
})
)
->orWhere(function ($query) {
$query->where('saida.tipo_id', SaidaTipo::MANUAL)
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('almoxarifado_saida_requisicao as requisicao')
->join(
'cadastro_centro_custo as centro_custo',
'centro_custo.id',
'requisicao.centro_custo_id'
)
->join(
'cadastro_infraestrutura as infraestrutura',
'infraestrutura.id',
'centro_custo.infraestrutura_id'
)
->whereColumn('requisicao.saida_id', 'saida.id')
->when(request()->unidade_requisitante_id, fn ($q, $id) => $q
->where('infraestrutura.unidade_id', $id))
->when(request()->infraestrutura_requisitante_id, fn ($q, $id) => $q
->where('infraestrutura.id', $id))
->when(request()->centro_custo_requisitante_id, fn ($q, $id) => $q
->where('centro_custo.id', $id));
});
})
->orWhere(function ($query) {
$query->where('saida.tipo_id', SaidaTipo::REQUISICAO)
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('almoxarifado_requisicao_resposta_item as resposta_item')
->join(
'almoxarifado_requisicao_resposta as resposta',
'resposta.id',
'resposta_item.requisicao_resposta_id'
)
->join(
'almoxarifado_requisicao as requisicao',
'requisicao.id',
'resposta.requisicao_id'
)
->join(
'cadastro_centro_custo as centro_custo',
'centro_custo.id',
'requisicao.created_centro_custo_id'
)
->join(
'cadastro_infraestrutura as infraestrutura',
'infraestrutura.id',
'centro_custo.infraestrutura_id'
)
->whereColumn('resposta_item.saida_item_id', 'saida_item.id')
->where('resposta.status_id', RequisicaoRespostaStatus::RECEBIDA)
->when(request()->unidade_requisitante_id, fn ($q, $id) => $q
->where('infraestrutura.unidade_id', $id))
->when(request()->infraestrutura_requisitante_id, fn ($q, $id) => $q
->where('infraestrutura.id', $id))
->when(request()->centro_custo_requisitante_id, fn ($q, $id) => $q
->where('centro_custo.id', $id))
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('almoxarifado_requisicao_resposta_item_recebimento as recebimento')
->whereColumn('recebimento.requisicao_resposta_item_id', 'resposta_item.id')
->where(fn ($q) => $q
->where(fn ($q) => $q
->whereNull('controlava_estoque')
->orWhere('controlava_estoque', false)
)
->where('quantidade', '>', 0)
);
});
});
})
);
};
$materiais = DB::table('cadastro_material as material')
->join(
'cadastro_grupo as grupo',
'grupo.id',
'material.grupo_id'
)
->join(
'cadastro_apresentacao as apresentacao',
'apresentacao.id',
'material.apresentacao_id'
)
->leftJoin(
'cadastro_subgrupo as subgrupo',
'subgrupo.id',
'material.subgrupo_id'
)
->leftJoin(
'cadastro_unidade_medida as apresentacao_unidade_medida',
'apresentacao_unidade_medida.id',
'material.apresentacao_unidade_medida_id'
)
->whereExists(function ($query) use ($whereSaida) {
$query->select(DB::raw(1))
->from('almoxarifado_saida_item as saida_item')
->join(
'almoxarifado_saida as saida',
'saida.id',
'saida_item.saida_id'
)
->join(
'cadastro_centro_custo as centro_custo_saida_almoxarifado',
'centro_custo_saida_almoxarifado.id',
'saida.centro_custo_id'
)
->join(
'cadastro_infraestrutura as infraestrutura_saida_almoxarifado',
'infraestrutura_saida_almoxarifado.id',
'centro_custo_saida_almoxarifado.infraestrutura_id'
)
->whereColumn('saida_item.material_id', 'material.id')
->whereNull('saida_item.estornado_em')
->where($whereSaida);
})
->when(request()->grupo_id, fn ($q, $id) => $q->where('grupo.id', $id))
->when(request()->subgrupo_id, fn ($q, $id) => $q->where('subgrupo.id', $id))
->when(request()->material_id, fn ($q, $id) => $q->where('material.id', $id))
->select(DB::raw("
material.codigo_material,
" . MaterialService::getDescricaoCompletaRaw(
'material',
'apresentacao',
'apresentacao_unidade_medida'
) . " as material,
grupo.nome as grupo,
subgrupo.nome as subgrupo
"))
->when($isCalculoEspecifico, function ($query) use ($whereSaida) {
$query->addSelect([
'meses_consumo' => function ($query) use ($whereSaida) {
$query->select(DB::raw("COUNT(DISTINCT CONCAT(
EXTRACT(YEAR FROM saida.created_at),
EXTRACT(MONTH FROM saida.created_at)
))"))
->from('almoxarifado_saida_item as saida_item')
->join(
'almoxarifado_saida as saida',
'saida.id',
'saida_item.saida_id'
)
->join(
'cadastro_centro_custo as centro_custo_saida_almoxarifado',
'centro_custo_saida_almoxarifado.id',
'saida.centro_custo_id'
)
->join(
'cadastro_infraestrutura as infraestrutura_saida_almoxarifado',
'infraestrutura_saida_almoxarifado.id',
'centro_custo_saida_almoxarifado.infraestrutura_id'
)
->whereColumn('saida_item.material_id', 'material.id')
->whereNull('saida_item.estornado_em')
->where($whereSaida);
},
]);
})
->addSelect([
'total' => function ($query) use ($whereSaida) {
$query->select(DB::raw("COALESCE(SUM(
IF(saida.tipo_id = " . SaidaTipo::REQUISICAO . ",
(
SELECT COALESCE(SUM(recebimento.quantidade), 0)
FROM almoxarifado_requisicao_resposta_item_recebimento as recebimento
JOIN almoxarifado_requisicao_resposta_item as resposta_item
ON resposta_item.id = recebimento.requisicao_resposta_item_id
WHERE resposta_item.saida_item_id = saida_item.id
),
(
SELECT COALESCE(SUM(saida_item_entrada_item.quantidade_saida), 0)
FROM almoxarifado_saida_item_entrada_item as saida_item_entrada_item
WHERE saida_item_entrada_item.saida_item_id = saida_item.id
)
)
), 0)"))
->from('almoxarifado_saida_item as saida_item')
->join(
'almoxarifado_saida as saida',
'saida.id',
'saida_item.saida_id'
)
->join(
'cadastro_centro_custo as centro_custo_saida_almoxarifado',
'centro_custo_saida_almoxarifado.id',
'saida.centro_custo_id'
)
->join(
'cadastro_infraestrutura as infraestrutura_saida_almoxarifado',
'infraestrutura_saida_almoxarifado.id',
'centro_custo_saida_almoxarifado.infraestrutura_id'
)
->whereColumn('saida_item.material_id', 'material.id')
->whereNull('saida_item.estornado_em')
->where($whereSaida);
},
'saldo_atual' => function ($query) {
$query->select(DB::raw("
COALESCE(SUM(
COALESCE(entrada_item.quantidade, 0)
-
COALESCE((
SELECT SUM(almoxarifado_saida_item_entrada_item.quantidade_saida)
FROM almoxarifado_saida_item_entrada_item
JOIN almoxarifado_saida_item
ON almoxarifado_saida_item.id = almoxarifado_saida_item_entrada_item.saida_item_id
JOIN almoxarifado_saida
ON almoxarifado_saida.id = almoxarifado_saida_item.saida_id
WHERE almoxarifado_saida_item_entrada_item.entrada_item_id = entrada_item.id
AND almoxarifado_saida.finalizada = 1
), 0)
), 0)
"))
->from('almoxarifado_entrada_item as entrada_item')
->join(
'almoxarifado_entrada as entrada',
'entrada.id',
'entrada_item.entrada_id'
)
->join(
'cadastro_centro_custo as centro_custo',
'centro_custo.id',
'entrada.centro_custo_id'
)
->join(
'cadastro_infraestrutura as infraestrutura',
'infraestrutura.id',
'centro_custo.infraestrutura_id'
)
->whereColumn('entrada_item.material_id', 'material.id')
->where('entrada.finalizada', true)
->when(request()->unidade_id, fn ($q, $id) => $q->where('infraestrutura.unidade_id', $id))
->when(request()->infraestrutura_id, fn ($q, $id) => $q->where('infraestrutura.id', $id))
->when(request()->centro_custo_id, fn ($q, $id) => $q->where('centro_custo.id', $id));
}
])
->orderByRaw(MaterialService::getDescricaoCompletaRaw(
'material',
'apresentacao',
'apresentacao_unidade_medida'
))
->get();
$materiais->each(function ($material) use ($totalizadores, $intervaloMeses, $isCalculoEspecifico) {
$media = $material->total / ($isCalculoEspecifico ? $material->meses_consumo : $intervaloMeses);
$material->media = number_format($media, 2, ',', '.');
$totalizadores->total += $material->total;
$totalizadores->saldo_atual += $material->saldo_atual;
});
return compact('materiais', 'totalizadores');
}
public static function list()
{
$data = (object) [
'additionals' => [],
'form' => [],
'model' => [],
];
$params = self::getParams();
$sets = [
'periodo' => function () use ($data) {
$data->model['periodo'] = ['start' => null, 'end' => null];
},
'unidade' => function () use ($data, $params) {
$unidadesData = self::getUnidadesData($params);
$data->form['unidades'] = $unidadesData['form'];
$data->model['unidade_id'] = $params->unidade_id = $unidadesData['model'];
},
'infraestrutura' => function () use ($data, $params) {
$infraestruturasData = self::getInfraestruturasData($params);
$data->form['infraestruturas'] = $infraestruturasData['form'];
$data->model['infraestrutura_id'] = $params->infraestrutura_id = $infraestruturasData['model'];
},
'centro_custo' => function () use ($data, $params) {
$centrosDeCustoData = self::getCentrosDeCustoData($params);
$data->form['centros_custo'] = $centrosDeCustoData['form'];
$data->model['centro_custo_id'] = $params->centro_custo_id = $centrosDeCustoData['model'];
},
'unidade_requisitante' => function () use ($data, $params) {
$unidadesRequisitantesData = self::getUnidadesRequisitantesData($params);
$data->form['unidades_requisitantes'] = $unidadesRequisitantesData['form'];
$data->model['unidade_requisitante_id'] = $params->unidade_requisitante_id = $unidadesRequisitantesData['model'];
},
'infraestrutura_requisitante' => function () use ($data, $params) {
$infraestruturasRequisitantesData = self::getInfraestruturasRequisitantesData($params);
$data->form['infraestruturas_requisitantes'] = $infraestruturasRequisitantesData['form'];
$data->model['infraestrutura_requisitante_id'] = $params->infraestrutura_requisitante_id = $infraestruturasRequisitantesData['model'];
},
'centro_custo_requisitante' => function () use ($data, $params) {
$centrosDeCustoRequisitantesData = self::getCentrosDeCustoRequisitantesData($params);
$data->form['centros_custo_requisitantes'] = $centrosDeCustoRequisitantesData['form'];
$data->model['centro_custo_requisitante_id'] = $params->centro_custo_requisitante_id = $centrosDeCustoRequisitantesData['model'];
},
'grupo' => function () use ($data, $params) {
$gruposData = self::getGruposData($params);
$data->form['grupos'] = $gruposData['form'];
$data->model['grupo_id'] = $params->grupo_id = $gruposData['model'];
},
'subgrupo' => function () use ($data, $params) {
$subgruposData = self::getSubgruposData($params);
$data->form['subgrupos'] = $subgruposData['form'];
$data->model['subgrupo_id'] = $params->subgrupo_id = $subgruposData['model'];
},
'material' => function () use ($data, $params) {
$data->model['material'] = $params->material_id = null;
},
'tipo_calculo' => function () use ($data, $params) {
$tiposCalculoData = self::getTiposCalculoData();
$data->form['tipos_calculo'] = $tiposCalculoData['form'];
$data->model['tipo_calculo'] = $params->tipo_calculo ?? $tiposCalculoData['model'];
},
];
$load = is_null(request()->load_from);
if ($load) {
$data->additionals = [
'data_atual' => Carbon::now()->format('d/m/Y'),
];
}
foreach ($sets as $field => $set) {
if ($load) {
$set();
}
else if ($field === request()->load_from) {
$load = true;
}
}
foreach ($data as $property => $itens) {
if (empty($itens)) {
unset($data->{$property});
}
}
return $data;
}
private static function getParams()
{
$params = (object) request()->only([
'periodo',
'unidade_id',
'infraestrutura_id',
'centro_custo_id',
'unidade_requisitante_id',
'infraestrutura_requisitante_id',
'centro_custo_requisitante_id',
'grupo_id',
'subgrupo_id',
'tipo_calculo',
]);
if (isset($params->periodo)
&& !is_null($params->periodo['start'])
&& !is_null($params->periodo['end'])
) {
$start = Carbon::createFromFormat('d/m/Y', $params->periodo['start'])->setTime(0, 0, 0);
$end = Carbon::createFromFormat('d/m/Y', $params->periodo['end'])->setTime(23, 59, 59);
$params->periodo['start'] = $start;
$params->periodo['end'] = $end;
}
else {
$params->periodo = null;
}
return $params;
}
private static function getUnidadesData($params)
{
$unidades = collect();
$id = null;
if (!is_null($params->periodo)) {
$unidades = Unidade::setEagerLoads([])
->whereHas('infraestruturas', fn ($q) => $q
->whereHas('centrosCusto', fn ($q) => self::setWhereForFilterCentroCustoAlmoxarifado($q, $params))
)
->orderBy('nome_fantasia')
->get(['id', 'nome_fantasia']);
}
return ['form' => $unidades, 'model' => $id];
}
private static function getInfraestruturasData($params)
{
$infraestruturas = collect();
$id = null;
if (!is_null($params->periodo) && !is_null($params->unidade_id)) {
$infraestruturas = Infraestrutura::setEagerLoads([])
->where('unidade_id', $params->unidade_id)
->whereHas('centrosCusto', fn ($q) => self::setWhereForFilterCentroCustoAlmoxarifado($q, $params))
->get(['id', 'nome', 'principal', 'unidade_id'])
->map(fn ($i) => ['id' => $i->id, 'nome' => $i->nome])
->sortBy('nome')
->values();
}
return ['form' => $infraestruturas, 'model' => $id];
}
private static function getCentrosDeCustoData($params)
{
$centrosCusto = collect();
$id = null;
if (!is_null($params->periodo) && !is_null($params->infraestrutura_id)) {
$centrosCusto = CentroCusto::setEagerLoads([])
->where('infraestrutura_id', $params->infraestrutura_id)
->where(fn ($q) => self::setWhereForFilterCentroCustoAlmoxarifado($q, $params))
->get(['id', 'setor_id'])
->map(fn ($cc) => [
'id' => $cc->id,
'setor_nome' => $cc->setor()->setEagerLoads([])->first(['nome'])->nome
])
->sortBy('setor_nome')
->values();
}
return ['form' => $centrosCusto, 'model' => $id];
}
private static function setWhereForFilterCentroCustoAlmoxarifado($query, $params)
{
return $query->whereHas('almoxarifadoSaidas', fn ($q) => $q
->where('finalizada', true)
->whereBetween('created_at', $params->periodo)
->whereHas('itens', fn ($q) => $q->whereNull('estornado_em'))
->where(fn ($q) => $q
->whereIn('tipo_id', [SaidaTipo::MANUAL, SaidaTipo::DISPENSACAO_FARMACIA])
->orWhere(fn ($q) => $q
->where('tipo_id', SaidaTipo::BAIXA)
->whereHas('baixa', fn ($q) => $q
->whereHas('motivo', fn ($q) => $q
->where('tipo_id', MotivoBaixaTipo::CONSUMO_INTERNO)
)
)
)
->orWhere(fn ($q) => $q
->where('tipo_id', SaidaTipo::REQUISICAO)
->whereHas('requisicaoResposta', fn ($q) => $q
->where('status_id', RequisicaoRespostaStatus::RECEBIDA)
->whereHas('itens', fn ($q) => $q
->whereHas('recebimentos', fn ($q) => $q
->where(fn ($q) => $q
->whereNull('controlava_estoque')
->orWhere('controlava_estoque', false)
)
->where('quantidade', '>', 0)
)
)
)
)
)
);
}
private static function getUnidadesRequisitantesData($params)
{
$unidades = collect();
$id = null;
if (!is_null($params->periodo)) {
$unidades = Unidade::setEagerLoads([])
->whereHas('infraestruturas', fn ($q) => $q
->whereHas('centrosCusto', fn ($q) => self::setWhereForFilterCentroCustoRequisitante($q, $params))
)
->orderBy('nome_fantasia')
->get(['id', 'nome_fantasia']);
}
return ['form' => $unidades, 'model' => $id];
}
private static function getInfraestruturasRequisitantesData($params)
{
$infraestruturas = collect();
$id = null;
if (!is_null($params->periodo) && !is_null($params->unidade_requisitante_id)) {
$infraestruturas = Infraestrutura::setEagerLoads([])
->where('unidade_id', $params->unidade_requisitante_id)
->whereHas('centrosCusto', fn ($q) => self::setWhereForFilterCentroCustoRequisitante($q, $params))
->get(['id', 'nome', 'principal', 'unidade_id'])
->map(fn ($i) => ['id' => $i->id, 'nome' => $i->nome])
->sortBy('nome')
->values();
}
return ['form' => $infraestruturas, 'model' => $id];
}
private static function getCentrosDeCustoRequisitantesData($params)
{
$centrosCusto = collect();
$id = null;
if (!is_null($params->periodo) && !is_null($params->infraestrutura_requisitante_id)) {
$centrosCusto = CentroCusto::setEagerLoads([])
->where('infraestrutura_id', $params->infraestrutura_requisitante_id)
->where(fn ($q) => self::setWhereForFilterCentroCustoRequisitante($q, $params))
->get(['id', 'setor_id'])
->map(fn ($cc) => [
'id' => $cc->id,
'setor_nome' => $cc->setor()->setEagerLoads([])->first(['nome'])->nome
])
->sortBy('setor_nome')
->values();
}
return ['form' => $centrosCusto, 'model' => $id];
}
private static function setWhereForFilterCentroCustoRequisitante($query, $params)
{
return $query->whereHas('almoxarifadoSaidaRequisicoes', fn ($q) => $q
->whereHas('saida', fn ($q) =>
self::setWhereForSelectedCentroCustoAlmoxarifado($q, $params)
->where('finalizada', true)
->whereBetween('created_at', $params->periodo)
->whereHas('itens', fn ($q) => $q->whereNull('estornado_em'))
)
)
->orWhereHas('almoxarifadoRequisicoesRequisitante', fn ($q) => $q
->whereHas('respostas', fn ($q) => $q
->where('status_id', RequisicaoRespostaStatus::RECEBIDA)
->whereHas('saida', fn ($q) =>
self::setWhereForSelectedCentroCustoAlmoxarifado($q, $params)
->where('finalizada', true)
->whereBetween('created_at', $params->periodo)
->whereHas('itens', fn ($q) => $q->whereNull('estornado_em'))
)
->whereHas('itens', fn ($q) => $q
->whereHas('recebimentos', fn ($q) => $q
->where(fn ($q) => $q
->whereNull('controlava_estoque')
->orWhere('controlava_estoque', false)
)
->where('quantidade', '>', 0)
)
)
)
);
}
private static function getGruposData($params)
{
$grupos = collect();
$id = null;
if (!is_null($params->periodo)) {
$grupos = Grupo::setEagerLoads([])
->whereHas('materiais', fn ($q) => self::setWhereForFilterMaterial($q, $params))
->orderBy('nome')
->get(['id', 'nome']);
}
return ['form' => $grupos, 'model' => $id];
}
private static function getSubgruposData($params)
{
$subgrupos = collect();
$id = null;
if (!is_null($params->periodo) && !is_null($params->grupo_id)) {
$subgrupos = Subgrupo::setEagerLoads([])
->where('grupo_id', $params->grupo_id)
->whereHas('materiais', fn ($q) => self::setWhereForFilterMaterial($q, $params))
->orderBy('nome')
->get(['id', 'nome']);
}
return ['form' => $subgrupos, 'model' => $id];
}
public static function autocompleteMaterial()
{
$params = self::getParams();
$materiais = Material::setEagerLoads([])
->when($params->grupo_id, fn ($q, $grupoId) => $q->where('grupo_id', $grupoId))
->when($params->subgrupo_id, fn ($q, $subgrupoId) => $q->where('subgrupo_id', $subgrupoId))
->where(fn ($q) => self::setWhereForFilterMaterial($q, $params))
->getQuery()
->join(
'cadastro_apresentacao',
'cadastro_apresentacao.id',
'cadastro_material.apresentacao_id'
)
->leftJoin(
'cadastro_unidade_medida as apresentacao_unidade_medida',
'apresentacao_unidade_medida.id',
'cadastro_material.apresentacao_unidade_medida_id'
)
->select(
'cadastro_material.id',
'cadastro_material.codigo_material',
'cadastro_material.descricao',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
) . " as descricao"),
);
return $materiais;
}
public static function setWhereForFilterMaterial($query, $params)
{
return $query->whereHas('almoxarifadoSaidaItens', fn ($q) => $q
->whereNull('estornado_em')
->whereHas('saida', fn ($q) =>
self::setWhereForSelectedCentroCustoAlmoxarifado($q, $params)
->where('finalizada', true)
->whereBetween('created_at', $params->periodo)
->where(fn ($q) => $q
->when(is_null($params->unidade_requisitante_id)
&& is_null($params->infraestrutura_requisitante_id)
&& is_null($params->centro_custo_requisitante_id),
fn ($q) => $q
->where('tipo_id', SaidaTipo::DISPENSACAO_FARMACIA)
->orWhere(fn ($q) => $q
->where('tipo_id', SaidaTipo::BAIXA)
->whereHas('baixa', fn ($q) => $q
->whereHas('motivo', fn ($q) => $q
->where('tipo_id', MotivoBaixaTipo::CONSUMO_INTERNO)
)
)
)
)
->orWhere(fn ($q) => $q
->where('tipo_id', SaidaTipo::MANUAL)
->whereHas('requisicao', fn ($q) =>
self::setWhereForSelectedCentroCustoRequisitante($q, $params, 'centro_custo_id')
)
)
->orWhere(fn ($q) => $q
->where('tipo_id', SaidaTipo::REQUISICAO)
->whereHas('requisicaoResposta', fn ($q) => $q
->where('status_id', RequisicaoRespostaStatus::RECEBIDA)
->whereHas('requisicao', fn ($q) =>
self::setWhereForSelectedCentroCustoRequisitante($q, $params, 'created_centro_custo_id')
)
)
)
)
)
->where(fn ($q) => $q
->doesntHave('requisicaoRespostaItem')
->orWhereHas('requisicaoRespostaItem', fn ($q) => $q
->whereHas('recebimentos', fn ($q) => $q
->where(fn ($q) => $q
->whereNull('controlava_estoque')
->orWhere('controlava_estoque', false)
)
->where('quantidade', '>', 0)
)
)
)
);
}
private static function setWhereForSelectedCentroCustoAlmoxarifado($query, $params)
{
return $query->when($params->centro_custo_id,
fn ($q, $centroCustoId) => $q->where('centro_custo_id', $centroCustoId),
fn ($q) => $q->when(!is_null($params->infraestrutura_id) || !is_null($params->unidade_id),
fn ($q) => $q->whereHas('centroCusto', fn ($q) => $q
->when($params->infraestrutura_id,
fn ($q, $infraestruturaId) => $q->where('infraestrutura_id', $infraestruturaId),
fn ($q) => $q->whereHas('infraestrutura', fn ($q) => $q
->where('unidade_id', $params->unidade_id))
)
)
)
);
}
private static function setWhereForSelectedCentroCustoRequisitante($query, $params, $centroCustoField)
{
return $query->when($params->centro_custo_requisitante_id,
fn ($q, $centroCustoId) => $q->where($centroCustoField, $centroCustoId),
fn ($q) => $q->when(!is_null($params->infraestrutura_requisitante_id) || !is_null($params->unidade_requisitante_id),
fn ($q) => $q->whereHas('centroCusto', fn ($q) => $q
->when($params->infraestrutura_requisitante_id,
fn ($q, $infraestruturaId) => $q->where('infraestrutura_id', $infraestruturaId),
fn ($q) => $q->whereHas('infraestrutura', fn ($q) => $q
->where('unidade_id', $params->unidade_requisitante_id))
)
)
)
);
}
private static function getTiposCalculoData()
{
return ['form' => self::getTiposCalculo(), 'model' => 'simples'];
}
private static function getTiposCalculo()
{
return collect([
(object) ['value' => 'especifico', 'text' => 'ESPECÍFICO'],
(object) ['value' => 'simples', 'text' => 'SIMPLES'],
]);
}
public static function getPrintExportData()
{
$resultado = self::index();
$itens = $resultado['materiais'];
$unidade = Unidade::find(request()->unidade_id);
$infraestrutura = Infraestrutura::find(request()->infraestrutura_id);
$centroCusto = CentroCusto::find(request()->centro_custo_id);
$unidadeRequisitante = Unidade::find(request()->unidade_requisitante_id);
$infraestruturaRequisitante = Infraestrutura::find(request()->infraestrutura_requisitante_id);
$centroCustoRequisitante = CentroCusto::find(request()->centro_custo_requisitante_id);
$grupo = Grupo::find(request()->grupo_id);
$subgrupo = Subgrupo::find(request()->subgrupo_id);
$material = Material::find(request()->material_id);
$tipoCalculo = self::getTiposCalculo()->where('value', request()->tipo_calculo)->first();
return [
'inicio' => request()->periodo['start'],
'fim' => request()->periodo['end'],
'unidade' => $unidade->nome_fantasia ?? 'Todas',
'infraestrutura' => $infraestrutura->nome ?? 'Todos',
'setor' => $centroCusto->setor->nome ?? 'Todos',
'unidadeRequisitante' => $unidadeRequisitante->nome_fantasia ?? 'Todas',
'infraestruturaRequisitante' => $infraestruturaRequisitante->nome ?? 'Todos',
'setorRequisitante' => $centroCustoRequisitante->setor->nome ?? 'Todos',
'grupo' => $grupo->nome ?? 'Todos',
'subgrupo' => $subgrupo->nome ?? 'Todos',
'material' => $material->descricao_completa ?? 'Todos',
'tipoCalculo' => $tipoCalculo->text,
'colunas' => collect(request()->selectedCols),
'itens' => $itens,
'totalizadores' => $resultado['totalizadores'],
];
}
}

View File

@@ -0,0 +1,306 @@
<?php
namespace App\Services\Almoxarifado\Relatorios;
use App\Enums\Almoxarifado\EntradaTipo as EntradaTipoEnum;
use App\Enums\Cadastro\Estabelecimento\SetorTipo;
use App\Enums\Cadastro\Grupo\GrupoTipo;
use App\Models\Almoxarifado\DocumentoTipo;
use App\Models\Almoxarifado\Entrada;
use App\Models\Almoxarifado\EntradaTipo;
use App\Models\Cadastro\Estabelecimento\CentroCusto;
use App\Models\Cadastro\Estabelecimento\Infraestrutura;
use App\Models\Cadastro\Estabelecimento\Unidade;
use App\Models\Cadastro\Fornecedor\Fornecedor;
use App\Models\Cadastro\Grupo\Grupo;
use App\Models\Cadastro\Material\Material;
use App\Models\Cadastro\Subgrupo\Subgrupo;
use App\Services\Cadastro\Material\MaterialService;
use App\Services\Service;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
class EntradaService extends Service
{
public static function index()
{
$totalizadores = (object) ['quantidade' => 0];
if(request()->tipo_data == 'entrada') {
$tipo_data = 'almoxarifado_entrada.finalizada_em';
} else {
$tipo_data = 'almoxarifado_entrada_documento.data';
}
$consulta = DB::table('almoxarifado_entrada')
->join(
'almoxarifado_entrada_item',
'almoxarifado_entrada_item.entrada_id',
'almoxarifado_entrada.id'
)
->join(
'cadastro_material',
'cadastro_material.id',
'almoxarifado_entrada_item.material_id'
)
->join(
'cadastro_apresentacao',
'cadastro_apresentacao.id',
'cadastro_material.apresentacao_id'
)
->join(
'almoxarifado_entrada_tipo',
'almoxarifado_entrada_tipo.id',
'almoxarifado_entrada.tipo_id'
)
->join(
'cadastro_grupo',
'cadastro_grupo.id',
'cadastro_material.grupo_id'
)
->join(
'cadastro_centro_custo',
'cadastro_centro_custo.id',
'almoxarifado_entrada.centro_custo_id'
)
->join(
'cadastro_infraestrutura',
'cadastro_infraestrutura.id',
'cadastro_centro_custo.infraestrutura_id'
)
->join(
'cadastro_unidade',
'cadastro_unidade.id',
'cadastro_infraestrutura.unidade_id'
)
->leftJoin(
'almoxarifado_entrada_documento',
'almoxarifado_entrada_documento.entrada_id',
'almoxarifado_entrada.id'
)
->leftJoin(
'almoxarifado_documento_tipo',
'almoxarifado_documento_tipo.id',
'almoxarifado_entrada_documento.tipo_id'
)
->leftJoin(
'cadastro_fornecedor',
'cadastro_fornecedor.id',
'almoxarifado_entrada_documento.fornecedor_id'
)
->leftJoin(
'cadastro_subgrupo',
'cadastro_subgrupo.id',
'cadastro_material.subgrupo_id'
)
->leftJoin(
'cadastro_unidade_medida as apresentacao_unidade_medida',
'apresentacao_unidade_medida.id',
'cadastro_material.apresentacao_unidade_medida_id'
)
->when(request()->periodo['start'], fn ($q, $data) => $q
->where($tipo_data, '>=', Carbon::createFromFormat('d/m/Y', $data)
->setTime(0, 0, 0))
)
->when(request()->periodo['end'], fn ($q, $data) => $q
->where($tipo_data, '<=', Carbon::createFromFormat('d/m/Y', $data)
->setTime(23, 59, 59))
)
->when(
request()->unidade_id,
fn ($q, $id) => $q->where('cadastro_infraestrutura.unidade_id', $id)
)
->when(
request()->infraestrutura_id,
fn ($q, $id) => $q->where('cadastro_centro_custo.infraestrutura_id', $id)
)
->when(
request()->centro_custo_id,
fn ($q, $id) => $q->where('almoxarifado_entrada.centro_custo_id', $id)
)
->when(
request()->grupo_id,
fn ($q, $id) => $q->where('cadastro_material.grupo_id', $id)
)
->when(
request()->grupo_id,
fn ($q, $id) => $q->where('cadastro_material.grupo_id', $id)
)
->when(
request()->subgrupo_id,
fn ($q, $id) => $q->where('cadastro_material.subgrupo_id', $id)
)
->when(
request()->fornecedor_id,
fn ($q, $id) => $q->where('almoxarifado_entrada_documento.fornecedor_id', $id)
)
->when(
request()->tipo_documento_id,
fn ($q, $id) => $q->where('almoxarifado_entrada_documento.tipo_id', $id)
)
->when(
request()->numero_pedido,
fn ($q, $id) => $q->where('almoxarifado_entrada_documento.numero_pedido', $id)
)
->when(
request()->material_id,
fn ($q, $id) => $q->where('almoxarifado_entrada_item.material_id', $id)
)
->when(
request()->tipo_entrada_id,
fn ($q, $id) => $q->where('almoxarifado_entrada.tipo_id', $id)
)
->when(
request()->sort_field,
fn ($q, $campo) => $q->orderBy($campo, request()->sort_direction ?? 'asc')
)
->whereNull('almoxarifado_entrada_item.estornado_em')
->select(
'almoxarifado_entrada_documento.data',
'almoxarifado_entrada.finalizada_em',
'almoxarifado_entrada_tipo.nome as entrada',
'almoxarifado_documento_tipo.nome as documento',
'almoxarifado_entrada_documento.numero_pedido',
'almoxarifado_entrada_documento.numero',
'cadastro_fornecedor.nome_fantasia',
'cadastro_grupo.nome as grupo',
'cadastro_subgrupo.nome as subgrupo',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
) . " as material"),
'cadastro_material.codigo_material' ,
'almoxarifado_entrada_item.lote',
'almoxarifado_entrada_item.validade_lote',
'almoxarifado_entrada_item.quantidade' ,
'almoxarifado_entrada_item.valor_unitario' ,
DB::raw("almoxarifado_entrada_item.quantidade * almoxarifado_entrada_item.valor_unitario as valor_total"),
'cadastro_unidade.nome_fantasia AS unidade',
DB::raw("COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) AS infraestrutura")
)
->get();
$totalizadores = [
'valor_unitario' => $consulta->sum('valor_unitario'),
'total' => $consulta->sum('valor_total'),
];
return ['consulta' => $consulta, 'totalizadores' => $totalizadores];
}
public static function list()
{
return [
'additionals' => [],
'form' => [
'fornecedores' => Fornecedor::orderBy('nome_fantasia')->get(['id', 'nome_fantasia']),
'unidades' => Unidade::orderBy('nome_fantasia')
->whereHas('infraestruturas', function ($query) {
$query->whereHas('centrosCusto');
})
->get()
->map(fn ($unidade) => [
'id' => $unidade->id,
'nome_fantasia' => $unidade->nome_fantasia,
'infraestruturas' => $unidade->infraestruturas()
->whereHas('centrosCusto')
->get()
->sortBy('nome')
->map(fn ($infraestrutura) => [
'id' => $infraestrutura->id,
'nome' => $infraestrutura->nome,
'centros_custo' => $infraestrutura->centrosCusto()
->get()
->map(fn ($centroCusto) => [
'id' => $centroCusto->id,
'setor_nome' => $centroCusto->setor->nome,
])
->sortBy('setor_nome')
->values()
])
->values()
]),
'grupos' => Grupo::
whereNull('grupo_tipo_id')
->orWhere('grupo_tipo_id', '<>', GrupoTipo::EXAME)
->orderBy('nome')
->get()
->map(fn ($grupo) => [
'id' => $grupo->id,
'nome' => $grupo->nome,
'subgrupos' => $grupo->subgrupos()->orderBy('nome')->get(['id', 'nome'])
]),
'tipos_documento' => DocumentoTipo::orderBy('nome')->get(['id', 'nome']),
'tipos' => EntradaTipo::orderBy('nome')->get(['id', 'nome']),
'tipo_data' => ['documento' => 'Documento', 'entrada' => 'Entrada'],
],
'model' => [
'periodo' => [
'start' => null,
'end' => null,
],
'tipo_data' => null,
'unidade_id' => null,
'infraestrutura_id' => null,
'centro_custo_id' => null,
'grupo_id' => null,
'subgrupo_id' => null,
'numero' => null,
'data' => null,
'data_documento' => null,
'tipo_entrada_id' => null,
'tipo_documento_id' => null,
'numero_documento' => null,
'fornecedor_id' => null,
'material_id' => null,
],
];
}
public static function getPrintExportData()
{
$resultado = self::index();
$itens = $resultado['consulta'];
$itens->each(function ($item) {
$item->finalizada_em = (new Carbon($item->finalizada_em))->format('d/m/Y');
$item->data = (new Carbon($item->data))->format('d/m/Y');
$item->validade_lote = (new Carbon($item->validade_lote))->format('d/m/Y');
$item->valor_unitario = number_format($item->valor_unitario, 2, ',', '.');
$item->valor_total = number_format($item->valor_total, 2, ',', '.');
$item->quantidade = number_format($item->quantidade, 2, ',', '.');
});
$unidade = Unidade::find(request()->unidade_id);
$infraestrutura = Infraestrutura::find(request()->infraestrutura_id);
$centroCusto = CentroCusto::find(request()->centro_custo_id);
$grupo = Grupo::find(request()->grupo_id);
$subgrupo = Subgrupo::find(request()->subgrupo_id);
$fornecedor = Fornecedor::find(request()->fornecedor_id);
$numero_documento = request()->numero_documento;
$tipo_documento = DocumentoTipo::find(request()->tipo_documento_id);
$tipo_entrada = EntradaTipo::find(request()->tipo_entrada_id);
$material = Material::find(request()->material_id['id'] ?? null);
return [
'inicio' => request()->periodo['start'],
'fim' => request()->periodo['end'],
'unidade' => $unidade->nome_fantasia ?? 'Todas',
'infraestrutura' => $infraestrutura->nome ?? 'Todas',
'setor' => $centroCusto->setor->nome ?? 'Todos',
'grupo' => $grupo->nome ?? 'Todos',
'subgrupo' => $subgrupo->nome ?? 'Todos',
'colunas' => collect(request()->selectedCols),
'itens' => $itens,
'totalizadores' => $resultado['totalizadores'],
'fornecedor' => $fornecedor->nome_fantasia ?? 'Todos',
'tipo_documento' => $tipo_documento->nome ?? 'Todos',
'tipo_entrada' => $tipo_entrada->nome ?? 'Todos',
'material' => $material->descricao_completa ?? 'Todos',
'numero_documento' => $numero_documento ?? 'Todos',
];
}
}

View File

@@ -0,0 +1,272 @@
<?php
namespace App\Services\Almoxarifado\Relatorios;
use App\Enums\Cadastro\Estabelecimento\SetorTipo;
use App\Models\Cadastro\Estabelecimento\CentroCusto;
use App\Models\Cadastro\Estabelecimento\Infraestrutura;
use App\Models\Cadastro\Estabelecimento\Unidade;
use App\Models\Cadastro\Fornecedor\Fornecedor;
use App\Models\Cadastro\Grupo\Grupo;
use App\Models\Cadastro\Material\Material;
use App\Models\Cadastro\Subgrupo\Subgrupo;
use App\Services\Cadastro\Material\MaterialService;
use App\Services\Service;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
class EstornoEntradaService extends Service
{
public static function index()
{
$totalizadores = (object) ['quantidade' => 0];
$periodo = [
'start' => Carbon::createFromFormat('d/m/Y', request()->periodo['start'])->setTime(0, 0, 0),
'end' => Carbon::createFromFormat('d/m/Y', request()->periodo['end'])->setTime(23, 59, 59)
];
$estornos = DB::table('almoxarifado_entrada_item as entrada_item')
->join(
'almoxarifado_entrada as entrada',
'entrada.id',
'entrada_item.entrada_id'
)
->join(
'cadastro_centro_custo as entrada_centro_custo',
'entrada_centro_custo.id',
'entrada.created_centro_custo_id'
)
->join(
'cadastro_infraestrutura as entrada_infraestrutura',
'entrada_infraestrutura.id',
'entrada_centro_custo.infraestrutura_id'
)
->join(
'almoxarifado_entrada_documento as entrada_documento',
'entrada_documento.entrada_id',
'entrada.id'
)
->join(
'almoxarifado_documento_tipo as documento_tipo',
'documento_tipo.id',
'entrada_documento.tipo_id'
)
->join(
'cadastro_fornecedor as fornecedor',
'fornecedor.id',
'entrada_documento.fornecedor_id'
)
->join(
'cadastro_material as material',
'material.id',
'entrada_item.material_id'
)
->join(
'cadastro_apresentacao as apresentacao',
'apresentacao.id',
'material.apresentacao_id'
)
->join(
'cadastro_grupo as grupo',
'grupo.id',
'material.grupo_id'
)
->leftJoin(
'cadastro_subgrupo as subgrupo',
'subgrupo.id',
'material.subgrupo_id'
)
->join(
'almoxarifado_saida_item as saida_item',
'saida_item.id',
'entrada_item.saida_item_estornado_id'
)
->join(
'cadastro_lotacao as saida_item_lotacao',
'saida_item_lotacao.id',
'saida_item.created_lotacao_id'
)
->join(
'cadastro_usuario as saida_item_usuario',
'saida_item_usuario.id',
'saida_item_lotacao.usuario_id'
)
->join(
'cadastro_cidadao as saida_item_cidadao',
'saida_item_cidadao.id',
'saida_item_usuario.cidadao_id'
)
->join(
'almoxarifado_saida_item_entrada_item as saida_item_entrada_item',
fn ($join) => $join->on('saida_item_entrada_item.entrada_item_id', 'entrada_item.id')
->whereColumn('saida_item_entrada_item.saida_item_id', 'entrada_item.saida_item_estornado_id')
)
->leftJoin(
'cadastro_unidade_medida as apresentacao_unidade_medida',
'apresentacao_unidade_medida.id',
'material.apresentacao_unidade_medida_id'
)
->where('entrada.finalizada', true)
->whereNotNull('entrada_item.estornado_em')
->whereBetween('entrada_item.estornado_em', $periodo)
->when(
request()->unidade_id,
fn ($q, $id) => $q->where('entrada_infraestrutura.unidade_id', $id)
)
->when(
request()->infraestrutura_id,
fn ($q, $id) => $q->where('entrada_centro_custo.infraestrutura_id', $id)
)
->when(
request()->centro_custo_id,
fn ($q, $id) => $q->where('entrada.created_centro_custo_id', $id)
)
->when(
request()->fornecedor_id,
fn ($q, $id) => $q->where('entrada_documento.fornecedor_id', $id)
)
->when(
request()->grupo_id,
fn ($q, $id) => $q->where('material.grupo_id', $id)
)
->when(
request()->subgrupo_id,
fn ($q, $id) => $q->where('material.subgrupo_id', $id)
)
->when(
request()->material_id,
fn ($q, $id) => $q->where('entrada_item.material_id', $id)
)
->select(
'entrada_item.estornado_em as data_hora_estorno',
'material.codigo_material',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'material',
'apresentacao',
'apresentacao_unidade_medida'
) . " as material"),
'entrada_item.lote as lote',
'entrada_item.validade_lote as validade',
'grupo.nome as grupo',
'subgrupo.nome as subgrupo',
'entrada_documento.data as data_documento',
'entrada_documento.numero as numero_documento',
'documento_tipo.nome as tipo_documento',
'fornecedor.nome_fantasia as fornecedor',
'saida_item_cidadao.nome as usuario_estorno',
'saida_item_entrada_item.quantidade_saida as quantidade'
)
->get();
$estornos->each(fn ($e) => $totalizadores->quantidade += $e->quantidade);
return compact('estornos', 'totalizadores');
}
public static function list()
{
return [
'additionals' => [
'data_atual' => Carbon::now()->format('d/m/Y')
],
'form' => [
'unidades' => Unidade::orderBy('nome_fantasia')
->whereHas('infraestruturas', function ($query) {
$query->whereHas('centrosCusto', function ($query) {
$query->whereHas('setor', fn ($q) => $q->where('tipo_id', SetorTipo::ALMOXARIFADO));
});
})
->get()
->map(fn ($unidade) => [
'id' => $unidade->id,
'nome_fantasia' => $unidade->nome_fantasia,
'infraestruturas' => $unidade->infraestruturas()
->whereHas('centrosCusto', function ($query) {
$query->whereHas('setor', fn ($q) => $q->where('tipo_id', SetorTipo::ALMOXARIFADO));
})
->get()
->sortBy('nome')
->map(fn ($infraestrutura) => [
'id' => $infraestrutura->id,
'nome' => $infraestrutura->nome,
'centros_custo' => $infraestrutura->centrosCusto()
->whereHas('setor', fn ($q) => $q->where('tipo_id', SetorTipo::ALMOXARIFADO))
->get()
->map(fn ($centroCusto) => [
'id' => $centroCusto->id,
'setor_nome' => $centroCusto->setor->nome,
])
->sortBy('setor_nome')
->values()
])
->values()
]),
'fornecedores' => Fornecedor::orderBy('nome_fantasia')->get(['id', 'nome_fantasia']),
'grupos' => Grupo::orderBy('nome')
->get()
->map(fn ($grupo) => [
'id' => $grupo->id,
'nome' => $grupo->nome,
'subgrupos' => $grupo->subgrupos()->orderBy('nome')->get(['id', 'nome'])
])
],
'model' => [
'periodo' => [
'start' => null,
'end' => null,
],
'unidade_id' => null,
'infraestrutura_id' => null,
'centro_custo_id' => null,
'fornecedor_id' => null,
'grupo_id' => null,
'subgrupo_id' => null,
'material' => null,
],
];
}
public static function getPrintExportData()
{
$resultado = self::index();
$itens = $resultado['estornos'];
$itens->each(function ($item) {
$item->data_hora_estorno = (new Carbon($item->data_hora_estorno))->format('d/m/Y H:i');
$item->data_documento = (new Carbon($item->data_documento))->format('d/m/Y');
if (!is_null($item->validade)) {
$item->validade = (new Carbon($item->validade))->format('d/m/Y');
}
});
$unidade = Unidade::find(request()->unidade_id);
$infraestrutura = Infraestrutura::find(request()->infraestrutura_id);
$centroCusto = CentroCusto::find(request()->centro_custo_id);
$fornecedor = Fornecedor::find(request()->fornecedor_id);
$grupo = Grupo::find(request()->grupo_id);
$subgrupo = Subgrupo::find(request()->subgrupo_id);
$material = Material::find(request()->material_id);
return [
'inicio' => request()->periodo['start'],
'fim' => request()->periodo['end'],
'unidade' => $unidade->nome_fantasia ?? 'Todas',
'infraestrutura' => $infraestrutura->nome ?? 'Todas',
'setor' => $centroCusto->setor->nome ?? 'Todos',
'fornecedor' => $fornecedor->nome_fantasia ?? 'Todos',
'grupo' => $grupo->nome ?? 'Todos',
'subgrupo' => $subgrupo->nome ?? 'Todos',
'material' => $material->descricao_completa ?? 'Todos',
'colunas' => collect(request()->selectedCols),
'itens' => $itens,
'totalizadores' => $resultado['totalizadores'],
];
}
}

View File

@@ -0,0 +1,394 @@
<?php
namespace App\Services\Almoxarifado\Relatorios;
use App\Enums\Almoxarifado\SaidaTipo as SaidaTipoEnum;
use App\Enums\Cadastro\Estabelecimento\SetorTipo;
use App\Models\Almoxarifado\SaidaTipo;
use App\Models\Cadastro\Estabelecimento\CentroCusto;
use App\Models\Cadastro\Estabelecimento\Infraestrutura;
use App\Models\Cadastro\Estabelecimento\Unidade;
use App\Models\Cadastro\Grupo\Grupo;
use App\Models\Cadastro\Material\Material;
use App\Models\Cadastro\Subgrupo\Subgrupo;
use App\Models\Cadastro\SujeitoAtencao\Usuario;
use App\Services\Cadastro\Material\MaterialService;
use App\Services\Service;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
class EstornoSaidaService extends Service
{
public static function index()
{
$totalizadores = (object) ['quantidade' => 0];
$periodo = [
'start' => Carbon::createFromFormat('d/m/Y', request()->periodo['start'])->setTime(0, 0, 0),
'end' => Carbon::createFromFormat('d/m/Y', request()->periodo['end'])->setTime(23, 59, 59)
];
$estornos = DB::table('almoxarifado_saida_item_entrada_item as saida_item_entrada_item')
->join(
'almoxarifado_saida_item as saida_item',
'saida_item.id',
'saida_item_entrada_item.saida_item_id'
)
->join(
'almoxarifado_saida as saida',
'saida.id',
'saida_item.saida_id'
)
->join(
'cadastro_centro_custo as saida_centro_custo',
'saida_centro_custo.id',
'saida.created_centro_custo_id'
)
->join(
'cadastro_infraestrutura as saida_infraestrutura',
'saida_infraestrutura.id',
'saida_centro_custo.infraestrutura_id'
)
->join(
'almoxarifado_saida_tipo as saida_tipo',
'saida_tipo.id',
'saida.tipo_id'
)
->join(
'cadastro_material as material',
'material.id',
'saida_item.material_id'
)
->join(
'cadastro_apresentacao as apresentacao',
'apresentacao.id',
'material.apresentacao_id'
)
->join(
'cadastro_grupo as grupo',
'grupo.id',
'material.grupo_id'
)
->join(
'cadastro_lotacao as saida_item_lotacao',
'saida_item_lotacao.id',
'saida_item.created_lotacao_id'
)
->join(
'cadastro_usuario as saida_item_usuario',
'saida_item_usuario.id',
'saida_item_lotacao.usuario_id'
)
->join(
'cadastro_cidadao as saida_item_cidadao',
'saida_item_cidadao.id',
'saida_item_usuario.cidadao_id'
)
->leftJoin(
'cadastro_unidade_medida as apresentacao_unidade_medida',
'apresentacao_unidade_medida.id',
'material.apresentacao_unidade_medida_id'
)
->leftJoin(
'almoxarifado_entrada_item as entrada_item_estorno',
'entrada_item_estorno.id',
'saida_item_entrada_item.entrada_item_estornado_id'
)
->leftJoin(
'cadastro_lotacao as entrada_item_estorno_lotacao',
'entrada_item_estorno_lotacao.id',
'entrada_item_estorno.created_lotacao_id'
)
->leftJoin(
'cadastro_usuario as entrada_item_estorno_usuario',
'entrada_item_estorno_usuario.id',
'entrada_item_estorno_lotacao.usuario_id'
)
->leftJoin(
'cadastro_cidadao as entrada_item_estorno_cidadao',
'entrada_item_estorno_cidadao.id',
'entrada_item_estorno_usuario.cidadao_id'
)
->leftJoin(
'almoxarifado_saida_baixa as saida_baixa',
'saida_baixa.saida_id',
'saida.id'
)
->leftJoin(
'cadastro_lotacao as saida_baixa_lotacao',
'saida_baixa_lotacao.id',
'saida_baixa.usuario_solicitante_id'
)
->leftJoin(
'cadastro_usuario as saida_baixa_usuario',
'saida_baixa_usuario.id',
'saida_baixa_lotacao.usuario_id'
)
->leftJoin(
'cadastro_cidadao as saida_baixa_cidadao',
'saida_baixa_cidadao.id',
'saida_baixa_usuario.cidadao_id'
)
->leftJoin(
'almoxarifado_motivo_baixa as saida_baixa_motivo',
'saida_baixa_motivo.id',
'saida_baixa.motivo_id'
)
->leftJoin(
'almoxarifado_saida_requisicao as saida_requisicao',
'saida_requisicao.saida_id',
'saida.id'
)
->leftJoin(
'cadastro_lotacao as saida_requisicao_lotacao',
'saida_requisicao_lotacao.id',
'saida_requisicao.usuario_id'
)
->leftJoin(
'cadastro_usuario as saida_requisicao_usuario',
'saida_requisicao_usuario.id',
'saida_requisicao_lotacao.usuario_id'
)
->leftJoin(
'cadastro_cidadao as saida_requisicao_cidadao',
'saida_requisicao_cidadao.id',
'saida_requisicao_usuario.cidadao_id'
)
->leftJoin(
'almoxarifado_saida_transferencia as saida_transferencia',
'saida_transferencia.saida_id',
'saida.id'
)
->leftJoin(
'cadastro_lotacao as saida_transferencia_lotacao',
'saida_transferencia_lotacao.id',
'saida_transferencia.usuario_id'
)
->leftJoin(
'cadastro_usuario as saida_transferencia_usuario',
'saida_transferencia_usuario.id',
'saida_transferencia_lotacao.usuario_id'
)
->leftJoin(
'cadastro_cidadao as saida_transferencia_cidadao',
'saida_transferencia_cidadao.id',
'saida_transferencia_usuario.cidadao_id'
)
->leftJoin(
'cadastro_subgrupo as subgrupo',
'subgrupo.id',
'material.subgrupo_id'
)
->where('saida.finalizada', true)
->whereNotNull('saida_item.estornado_em')
->whereBetween('saida_item.estornado_em', $periodo)
->when(
request()->unidade_id,
fn ($q, $id) => $q->where('saida_infraestrutura.unidade_id', $id)
)
->when(
request()->infraestrutura_id,
fn ($q, $id) => $q->where('saida_centro_custo.infraestrutura_id', $id)
)
->when(
request()->centro_custo_id,
fn ($q, $id) => $q->where('saida.created_centro_custo_id', $id)
)
->when(
request()->tipo_saida_id,
fn ($q, $id) => $q->where('saida.tipo_id', $id)
)
->when(
request()->usuario_requisitante_id,
fn ($q, $id) => $q->where(function ($query) use ($id) {
$query->where('saida_requisicao.usuario_id', $id)
->orWhere('saida_transferencia.usuario_id', $id)
->orWhere('saida_baixa.usuario_solicitante_id', $id);
})
)
->when(
request()->grupo_id,
fn ($q, $id) => $q->where('material.grupo_id', $id)
)
->when(
request()->subgrupo_id,
fn ($q, $id) => $q->where('material.subgrupo_id', $id)
)
->when(
request()->material_id,
fn ($q, $id) => $q->where('saida_item.material_id', $id)
)
->select(
'saida_item.estornado_em as data_hora_estorno',
'saida_item.created_at as data_saida',
DB::raw("CONCAT(
saida_tipo.nome,
IF(saida.tipo_id = " . SaidaTipoEnum::BAIXA . ",
CONCAT(' (', saida_baixa_motivo.descricao, ')'),
''
)
) as tipo_saida"),
'material.codigo_material',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'material',
'apresentacao',
'apresentacao_unidade_medida'
) . " as material"),
'entrada_item_estorno.lote as lote',
'entrada_item_estorno.validade_lote as validade',
'grupo.nome as grupo',
'subgrupo.nome as subgrupo',
'saida_requisicao.numero as numero_requisicao',
DB::raw("(
CASE
WHEN saida.tipo_id = " . SaidaTipoEnum::MANUAL . "
THEN saida_requisicao_cidadao.nome
WHEN saida.tipo_id = " . SaidaTipoEnum::TRANSFERENCIA . "
THEN saida_transferencia_cidadao.nome
WHEN saida.tipo_id = " . SaidaTipoEnum::BAIXA . "
THEN saida_baixa_cidadao.nome
END
) as usuario_requisitante"),
'entrada_item_estorno_cidadao.nome as usuario_estorno',
'saida_item_cidadao.nome as usuario_saida',
'saida_item_entrada_item.quantidade_saida as quantidade'
)
->get();
$estornos->each(fn ($e) => $totalizadores->quantidade += $e->quantidade);
return compact('estornos', 'totalizadores');
}
public static function list()
{
$centroCustoLogado = self::getCurrentCentroCusto();
$unidadeLogadaId = $centroCustoLogado->infraestrutura->unidade_id;
$infraestruturaLogadaId = $centroCustoLogado->infraestrutura_id;
$centroCustoLogadoId = $centroCustoLogado->id;
$isAlmoxarifado = $centroCustoLogado->setor->tipo_id === SetorTipo::ALMOXARIFADO;
$data = [
'additionals' => [
'data_atual' => Carbon::now()->format('d/m/Y'),
'is_almoxarifado' => $isAlmoxarifado,
],
'form' => [
'unidades' => Unidade::orderBy('nome_fantasia')
->when($isAlmoxarifado,
fn ($query) => $query->whereHas('infraestruturas', fn ($q) => $q->whereHas('centrosCusto')),
fn ($query) => $query->where('id', $unidadeLogadaId)
)
->get()
->map(fn ($unidade) => (object) [
'id' => $unidade->id,
'nome_fantasia' => $unidade->nome_fantasia,
'infraestruturas' => $unidade->infraestruturas()
->when($isAlmoxarifado,
fn ($q) => $q->whereHas('centrosCusto'),
fn ($q) => $q->where('id', $infraestruturaLogadaId)
)
->get()
->sortBy('nome')
->map(fn ($infraestrutura) => (object) [
'id' => $infraestrutura->id,
'nome' => $infraestrutura->nome,
'centros_custo' => $infraestrutura->centrosCusto()
->when(!$isAlmoxarifado, fn ($q) => $q->where('id', $centroCustoLogadoId))
->get()
->map(fn ($centroCusto) => (object) [
'id' => $centroCusto->id,
'setor_nome' => $centroCusto->setor->nome,
])
->sortBy('setor_nome')
->values()
])
->values()
]),
'tipos_saida' => SaidaTipo::query()
->when($isAlmoxarifado,
fn ($q) => $q->whereIn('id', [
SaidaTipoEnum::MANUAL,
SaidaTipoEnum::BAIXA,
SaidaTipoEnum::TRANSFERENCIA,
]),
fn ($q) => $q->where('id', SaidaTipoEnum::BAIXA)
)
->orderBy('nome')
->get(['id', 'nome']),
'grupos' => Grupo::orderBy('nome')
->get()
->map(fn ($grupo) => (object) [
'id' => $grupo->id,
'nome' => $grupo->nome,
'subgrupos' => $grupo->subgrupos()->orderBy('nome')->get(['id', 'nome'])
])
],
];
$unidade = $isAlmoxarifado ? null : $data['form']['unidades']->first();
$infraestrutura = $isAlmoxarifado ? null : $unidade->infraestruturas->first();
$centroCusto = $isAlmoxarifado ? null : $infraestrutura->centros_custo->first();
$tipoSaida = $isAlmoxarifado ? null : $data['form']['tipos_saida']->first();
$data['model'] = [
'periodo' => [
'start' => null,
'end' => null,
],
'unidade_id' => $unidade->id ?? null,
'infraestrutura_id' => $infraestrutura->id ?? null,
'centro_custo_id' => $centroCusto->id ?? null,
'tipo_saida_id' => $tipoSaida->id ?? null,
'usuario_requisitante' => null,
'grupo_id' => null,
'subgrupo_id' => null,
'material' => null,
];
return $data;
}
public static function getPrintExportData()
{
$resultado = self::index();
$itens = $resultado['estornos'];
$itens->each(function ($item) {
$item->data_hora_estorno = (new Carbon($item->data_hora_estorno))->format('d/m/Y H:i');
$item->data_saida = (new Carbon($item->data_saida))->format('d/m/Y');
if (!is_null($item->validade)) {
$item->validade = (new Carbon($item->validade))->format('d/m/Y');
}
});
$unidade = Unidade::find(request()->unidade_id);
$infraestrutura = Infraestrutura::find(request()->infraestrutura_id);
$centroCusto = CentroCusto::find(request()->centro_custo_id);
$tipoSaida = SaidaTipo::find(request()->tipo_saida_id);
$usuarioRequisitante = Usuario::find(request()->usuario_requisitante_id);
$grupo = Grupo::find(request()->grupo_id);
$subgrupo = Subgrupo::find(request()->subgrupo_id);
$material = Material::find(request()->material_id);
return [
'inicio' => request()->periodo['start'],
'fim' => request()->periodo['end'],
'unidade' => $unidade->nome_fantasia ?? 'Todas',
'infraestrutura' => $infraestrutura->nome ?? 'Todas',
'setor' => $centroCusto->setor->nome ?? 'Todos',
'tipoSaida' => $tipoSaida->nome ?? 'Todos',
'usuarioRequisitante' => $usuarioRequisitante->cidadao->nome ?? 'Todos',
'grupo' => $grupo->nome ?? 'Todos',
'subgrupo' => $subgrupo->nome ?? 'Todos',
'material' => $material->descricao_completa ?? 'Todos',
'colunas' => collect(request()->selectedCols),
'itens' => $itens,
'totalizadores' => $resultado['totalizadores'],
];
}
}

View File

@@ -0,0 +1,921 @@
<?php
namespace App\Services\Almoxarifado\Relatorios;
use App\Enums\Almoxarifado\EntradaTipo;
use App\Enums\Almoxarifado\SaidaTipo;
use App\Services\Cadastro\Material\MaterialService;
use App\Services\Service;
use App\Utils\DataUtil;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
class MovimentacaoGeralService extends Service
{
public static function index()
{
$params = self::getParams();
$itens = collect();
if ($params->movimentacao_tipo === 'entrada') {
$itens = DB::table('almoxarifado_entrada_item')
->select([
'almoxarifado_entrada_item.id AS entrada_item_id',
DB::raw("DATE_FORMAT(almoxarifado_entrada.created_at, '%d/%m/%Y') AS data_movimentacao"),
'almoxarifado_entrada_tipo.id AS movimentacao_subtipo_id',
'almoxarifado_entrada_tipo.nome AS movimentacao_subtipo_nome',
'cadastro_unidade.nome_fantasia AS unidade_nome_fantasia',
DB::raw("COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) AS infraestrutura_nome"),
'cadastro_setor.nome AS setor_nome',
'cadastro_cidadao.nome AS usuario_nome',
'cadastro_material.codigo_material AS material_codigo',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'cadastro_unidade_medida'
) . ' AS material_descricao'),
'cadastro_grupo.nome AS grupo_nome',
'almoxarifado_entrada_item.quantidade',
'almoxarifado_entrada_item.valor_unitario',
'almoxarifado_entrada_item.valor_total',
'almoxarifado_entrada_item.lote',
DB::raw("DATE_FORMAT(almoxarifado_entrada_item.validade_lote, '%d/%m/%Y') AS validade_lote"),
'almoxarifado_entrada_documento.numero AS documento_numero',
'cadastro_fornecedor.nome_fantasia AS fornecedor_nome_fantasia',
'cadastro_origem_programatica.nome AS origem_programatica_nome',
])
->join('cadastro_material', 'cadastro_material.id', 'almoxarifado_entrada_item.material_id')
->join('cadastro_apresentacao', 'cadastro_apresentacao.id', 'cadastro_material.apresentacao_id')
->join('cadastro_unidade_medida', 'cadastro_unidade_medida.id', 'cadastro_material.apresentacao_unidade_medida_id')
->join('cadastro_grupo', 'cadastro_grupo.id', 'cadastro_material.grupo_id')
->join('almoxarifado_entrada', 'almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->join('almoxarifado_entrada_tipo', 'almoxarifado_entrada_tipo.id', 'almoxarifado_entrada.tipo_id')
->join('cadastro_centro_custo', 'cadastro_centro_custo.id', 'almoxarifado_entrada.centro_custo_id')
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->join('cadastro_unidade', 'cadastro_unidade.id', 'cadastro_infraestrutura.unidade_id')
->join('cadastro_setor', 'cadastro_setor.id', 'cadastro_centro_custo.setor_id')
->join('cadastro_lotacao', 'cadastro_lotacao.id', 'almoxarifado_entrada.created_lotacao_id')
->join('cadastro_usuario', 'cadastro_usuario.id', 'cadastro_lotacao.usuario_id')
->join('cadastro_cidadao', 'cadastro_cidadao.id', 'cadastro_usuario.cidadao_id')
->leftJoin('almoxarifado_entrada_documento', 'almoxarifado_entrada_documento.entrada_id', 'almoxarifado_entrada.id')
->leftJoin('cadastro_fornecedor', 'cadastro_fornecedor.id', 'almoxarifado_entrada_documento.fornecedor_id')
->leftJoin('cadastro_origem_programatica', 'cadastro_origem_programatica.id', 'almoxarifado_entrada_documento.origem_programatica_id')
->whereBetween('almoxarifado_entrada.created_at', $params->periodo)
->where('almoxarifado_entrada.finalizada', true)
->when($params->movimentacao_subtipo_id, fn ($q) => $q->where('almoxarifado_entrada.tipo_id', $params->movimentacao_subtipo_id))
->when($params->unidade_id, fn ($q) => $q->where('cadastro_infraestrutura.unidade_id', $params->unidade_id))
->when($params->infraestrutura_id, fn ($q) => $q->where('cadastro_infraestrutura.id', $params->infraestrutura_id))
->when($params->setor_id, fn ($q) => $q->where('cadastro_centro_custo.setor_id', $params->setor_id))
->when($params->usuario_id, fn ($q) => $q->where('cadastro_lotacao.usuario_id', $params->usuario_id))
->when($params->origem_programatica_id, fn ($q) => $q->where('almoxarifado_entrada_documento.origem_programatica_id', $params->origem_programatica_id))
->when($params->material_id, fn ($q) => $q->where('almoxarifado_entrada_item.material_id', $params->material_id));
} else {
$itens = DB::table('almoxarifado_saida_item_entrada_item')
->select([
'almoxarifado_saida.id AS saida_id',
'almoxarifado_saida_item.id AS saida_item_id',
DB::raw("DATE_FORMAT(almoxarifado_saida.created_at, '%d/%m/%Y') AS data_movimentacao"),
'almoxarifado_saida_tipo.id AS movimentacao_subtipo_id',
'almoxarifado_saida_tipo.nome AS movimentacao_subtipo_nome',
'cadastro_unidade.nome_fantasia AS unidade_nome_fantasia',
DB::raw("COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) AS infraestrutura_nome"),
'cadastro_setor.nome AS setor_nome',
'cadastro_cidadao.nome AS usuario_nome',
'cadastro_material.codigo_material AS material_codigo',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'cadastro_unidade_medida'
) . ' AS material_descricao'),
'cadastro_grupo.nome AS grupo_nome',
'almoxarifado_saida_item_entrada_item.quantidade_saida AS quantidade',
'almoxarifado_entrada_item.valor_unitario',
DB::raw("(almoxarifado_saida_item_entrada_item.quantidade_saida * almoxarifado_entrada_item.valor_unitario) AS valor_total"),
'almoxarifado_entrada_item.lote',
DB::raw("DATE_FORMAT(almoxarifado_entrada_item.validade_lote, '%d/%m/%Y') AS validade_lote"),
'almoxarifado_entrada_documento.numero AS documento_numero',
'cadastro_fornecedor.nome_fantasia AS fornecedor_nome_fantasia',
'cadastro_origem_programatica.nome AS origem_programatica_nome',
])
->join('almoxarifado_saida_item', 'almoxarifado_saida_item.id', 'almoxarifado_saida_item_entrada_item.saida_item_id')
->join('cadastro_material', 'cadastro_material.id', 'almoxarifado_saida_item.material_id')
->join('cadastro_apresentacao', 'cadastro_apresentacao.id', 'cadastro_material.apresentacao_id')
->join('cadastro_unidade_medida', 'cadastro_unidade_medida.id', 'cadastro_material.apresentacao_unidade_medida_id')
->join('cadastro_grupo', 'cadastro_grupo.id', 'cadastro_material.grupo_id')
->join('almoxarifado_saida', 'almoxarifado_saida.id', 'almoxarifado_saida_item.saida_id')
->join('almoxarifado_saida_tipo', 'almoxarifado_saida_tipo.id', 'almoxarifado_saida.tipo_id')
->join('cadastro_centro_custo', 'cadastro_centro_custo.id', 'almoxarifado_saida.centro_custo_id')
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->join('cadastro_unidade', 'cadastro_unidade.id', 'cadastro_infraestrutura.unidade_id')
->join('cadastro_setor', 'cadastro_setor.id', 'cadastro_centro_custo.setor_id')
->join('cadastro_lotacao', 'cadastro_lotacao.id', 'almoxarifado_saida.created_lotacao_id')
->join('cadastro_usuario', 'cadastro_usuario.id', 'cadastro_lotacao.usuario_id')
->join('cadastro_cidadao', 'cadastro_cidadao.id', 'cadastro_usuario.cidadao_id')
->join('almoxarifado_entrada_item', 'almoxarifado_entrada_item.id', 'almoxarifado_saida_item_entrada_item.entrada_item_id')
->join('almoxarifado_entrada', 'almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->leftJoin('almoxarifado_entrada_documento', 'almoxarifado_entrada_documento.entrada_id', 'almoxarifado_entrada.id')
->leftJoin('cadastro_fornecedor', 'cadastro_fornecedor.id', 'almoxarifado_entrada_documento.fornecedor_id')
->leftJoin('cadastro_origem_programatica', 'cadastro_origem_programatica.id', 'almoxarifado_entrada_documento.origem_programatica_id')
->whereBetween('almoxarifado_saida.created_at', $params->periodo)
->where('almoxarifado_saida.finalizada', true)
->when($params->movimentacao_subtipo_id, fn ($q) => $q->where('almoxarifado_saida.tipo_id', $params->movimentacao_subtipo_id))
->when($params->unidade_id, fn ($q) => $q->where('cadastro_infraestrutura.unidade_id', $params->unidade_id))
->when($params->infraestrutura_id, fn ($q) => $q->where('cadastro_infraestrutura.id', $params->infraestrutura_id))
->when($params->setor_id, fn ($q) => $q->where('cadastro_centro_custo.setor_id', $params->setor_id))
->when($params->usuario_id, fn ($q) => $q->where('cadastro_lotacao.usuario_id', $params->usuario_id))
->when($params->origem_programatica_id, fn ($q) => $q->where('almoxarifado_entrada_documento.origem_programatica_id', $params->origem_programatica_id))
->when($params->material_id, fn ($q) => $q->where('almoxarifado_saida_item.material_id', $params->material_id));
}
$camposOrigem = collect([
'unidade_origem_nome_fantasia',
'infraestrutura_origem_nome',
'usuario_solicitante_nome',
]);
$camposDestino = collect([
'unidade_destino_nome_fantasia',
'infraestrutura_destino_nome',
'usuario_destino_nome',
]);
if (is_null(request()->sort_by)
|| (!$camposOrigem->contains(request()->sort_by) && !$camposDestino->contains(request()->sort_by))
) {
self::setOrderBy($itens);
}
if ($params->movimentacao_tipo === 'entrada') {
$itens = $itens->get()
->map(function($query) {
if ($query->movimentacao_subtipo_id === EntradaTipo::REQUISICAO) {
$centroCustoOrigem = DB::table('cadastro_centro_custo')
->select([
'cadastro_unidade.nome_fantasia AS unidade_nome_fantasia',
DB::raw("COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) AS infraestrutura_nome"),
])
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->join('cadastro_unidade', 'cadastro_unidade.id', 'cadastro_infraestrutura.unidade_id')
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_requisicao_resposta_item_entrada_item')
->join('almoxarifado_requisicao_resposta_item', 'almoxarifado_requisicao_resposta_item.id', 'almoxarifado_requisicao_resposta_item_entrada_item.requisicao_resposta_item_id')
->join('almoxarifado_requisicao_resposta', 'almoxarifado_requisicao_resposta.id', 'almoxarifado_requisicao_resposta_item.requisicao_resposta_id')
->join('almoxarifado_saida', 'almoxarifado_saida.id', 'almoxarifado_requisicao_resposta.saida_id')
->where('almoxarifado_requisicao_resposta_item_entrada_item.entrada_item_id', $query->entrada_item_id)
->whereColumn('almoxarifado_saida.centro_custo_id', 'cadastro_centro_custo.id')
)
->first();
$query->unidade_origem_nome_fantasia = $centroCustoOrigem->unidade_nome_fantasia ?? '-';
$query->infraestrutura_origem_nome = $centroCustoOrigem->infraestrutura_nome ?? '-';
$lotacaoSolicitante = DB::table('cadastro_usuario')
->select(['cadastro_cidadao.nome AS usuario_nome'])
->join('cadastro_cidadao', 'cadastro_cidadao.id', 'cadastro_usuario.cidadao_id')
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_requisicao_resposta_item_entrada_item')
->join('almoxarifado_requisicao_resposta_item', 'almoxarifado_requisicao_resposta_item.id', 'almoxarifado_requisicao_resposta_item_entrada_item.requisicao_resposta_item_id')
->join('almoxarifado_requisicao_resposta', 'almoxarifado_requisicao_resposta.id', 'almoxarifado_requisicao_resposta_item.requisicao_resposta_id')
->join('almoxarifado_requisicao', 'almoxarifado_requisicao.id', 'almoxarifado_requisicao_resposta.requisicao_id')
->join('cadastro_lotacao', 'cadastro_lotacao.id', 'almoxarifado_requisicao.created_lotacao_id')
->where('almoxarifado_requisicao_resposta_item_entrada_item.entrada_item_id', $query->entrada_item_id)
->whereColumn('cadastro_lotacao.usuario_id', 'cadastro_usuario.id')
)
->first();
$query->usuario_solicitante_nome = $lotacaoSolicitante->usuario_nome ?? '-';
}
else if ($query->movimentacao_subtipo_id === EntradaTipo::TRANSFERENCIA) {
$centroCustoOrigem = DB::table('cadastro_centro_custo')
->select([
'cadastro_unidade.nome_fantasia AS unidade_nome_fantasia',
DB::raw("COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) AS infraestrutura_nome"),
])
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->join('cadastro_unidade', 'cadastro_unidade.id', 'cadastro_infraestrutura.unidade_id')
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_saida_item_entrada_item_transferencia')
->join('almoxarifado_saida_item', 'almoxarifado_saida_item.id', 'almoxarifado_saida_item_entrada_item_transferencia.saida_item_origem_id')
->join('almoxarifado_saida', 'almoxarifado_saida.id', 'almoxarifado_saida_item.saida_id')
->where('almoxarifado_saida_item_entrada_item_transferencia.entrada_item_destino_id', $query->entrada_item_id)
->whereColumn('almoxarifado_saida.centro_custo_id', 'cadastro_centro_custo.id')
)
->first();
$query->unidade_origem_nome_fantasia = $centroCustoOrigem->unidade_nome_fantasia ?? '-';
$query->infraestrutura_origem_nome = $centroCustoOrigem->infraestrutura_nome ?? '-';
} else {
$query->unidade_origem_nome_fantasia = '-';
$query->infraestrutura_origem_nome = '-';
$query->usuario_solicitante_nome = '-';
}
return $query;
});
if ($camposOrigem->contains(request()->sort_by)) {
$itens = $itens->sortBy([
[request()->sort_by, DataUtil::getBooleanValueFromStringBoolean(request()->sort_desc) ? 'desc' : 'asc'],
['entrada_item_id', 'asc']
]);
}
} else {
$itens = $itens->get()
->map(function($query) {
if ($query->movimentacao_subtipo_id === SaidaTipo::MANUAL) {
$centroCustoDestino = DB::table('cadastro_centro_custo')
->select([
'cadastro_unidade.nome_fantasia AS unidade_nome_fantasia',
DB::raw("COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) AS infraestrutura_nome"),
])
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->join('cadastro_unidade', 'cadastro_unidade.id', 'cadastro_infraestrutura.unidade_id')
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_saida_requisicao')
->where('almoxarifado_saida_requisicao.saida_id', $query->saida_id)
->whereColumn('almoxarifado_saida_requisicao.centro_custo_id', 'cadastro_centro_custo.id')
)
->first();
$query->unidade_destino_nome_fantasia = $centroCustoDestino->unidade_nome_fantasia ?? null;
$query->infraestrutura_destino_nome = $centroCustoDestino->infraestrutura_nome ?? null;
$usuarioDestino = DB::table('cadastro_usuario')
->select(['cadastro_cidadao.nome AS usuario_nome'])
->join('cadastro_cidadao', 'cadastro_cidadao.id', 'cadastro_usuario.cidadao_id')
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_saida_requisicao')
->where('almoxarifado_saida_requisicao.saida_id', $query->saida_id)
->whereColumn('almoxarifado_saida_requisicao.usuario_id', 'cadastro_usuario.id')
)
->first();
$query->usuario_destino_nome = $usuarioDestino->usuario_nome ?? null;
}
else if ($query->movimentacao_subtipo_id === SaidaTipo::REQUISICAO) {
$centroCustoDestino = DB::table('cadastro_centro_custo')
->select([
'cadastro_unidade.nome_fantasia AS unidade_origem_nome_fantasia',
DB::raw("COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) AS infraestrutura_origem_nome"),
])
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->join('cadastro_unidade', 'cadastro_unidade.id', 'cadastro_infraestrutura.unidade_id')
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_requisicao_resposta')
->join('almoxarifado_requisicao', 'almoxarifado_requisicao.id', 'almoxarifado_requisicao_resposta.requisicao_id')
->where('almoxarifado_requisicao_resposta.saida_id', $query->saida_id)
->whereColumn('almoxarifado_requisicao.created_centro_custo_id', 'cadastro_centro_custo.id')
)
->first();
$query->unidade_destino_nome_fantasia = $centroCustoDestino->unidade_nome_fantasia ?? '-';
$query->infraestrutura_destino_nome = $centroCustoDestino->infraestrutura_nome ?? '-';
$lotacaoDestino = DB::table('cadastro_usuario')
->select(['cadastro_cidadao.nome AS usuario_nome'])
->join('cadastro_cidadao', 'cadastro_cidadao.id', 'cadastro_usuario.cidadao_id')
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_requisicao_resposta')
->join('almoxarifado_requisicao', 'almoxarifado_requisicao.id', 'almoxarifado_requisicao_resposta.requisicao_id')
->join('cadastro_lotacao', 'cadastro_lotacao.id', 'almoxarifado_requisicao.created_lotacao_id')
->where('almoxarifado_requisicao_resposta.saida_id', $query->saida_id)
->whereColumn('cadastro_lotacao.usuario_id', 'cadastro_usuario.id')
)
->first();
$query->usuario_destino_nome = $lotacaoDestino->usuario_nome ?? '-';
}
else if ($query->movimentacao_subtipo_id === SaidaTipo::TRANSFERENCIA) {
$centroCustoDestino = DB::table('cadastro_centro_custo')
->select([
'cadastro_unidade.nome_fantasia AS unidade_nome_fantasia',
DB::raw("COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) AS infraestrutura_nome"),
])
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->join('cadastro_unidade', 'cadastro_unidade.id', 'cadastro_infraestrutura.unidade_id')
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_saida_transferencia')
->where('almoxarifado_saida_transferencia.saida_id', $query->saida_id)
->whereColumn('almoxarifado_saida_transferencia.centro_custo_id', 'cadastro_centro_custo.id')
)
->first();
$query->unidade_destino_nome_fantasia = $centroCustoDestino->unidade_nome_fantasia ?? '-';
$query->infraestrutura_destino_nome = $centroCustoDestino->infraestrutura_nome ?? '-';
} else {
$query->unidade_destino_nome_fantasia = '-';
$query->infraestrutura_destino_nome = '-';
$query->usuario_destino_nome = '-';
}
return $query;
});
if ($camposDestino->contains(request()->sort_by)) {
$itens = $itens->sortBy([
[request()->sort_by, DataUtil::getBooleanValueFromStringBoolean(request()->sort_desc) ? 'desc' : 'asc'],
['saida_item_id', 'asc']
]);
}
}
return $itens;
}
public static function create()
{
return [
'additionals' => [
'data_atual' => Carbon::now()->format('d/m/Y'),
],
'form' => [
'movimentacao_tipos' => [],
'movimentacao_subtipos' => [],
'unidades' => [],
'infraestruturas' => [],
'setores' => [],
'usuarios' => [],
'origens_programaticas' => [],
],
'model' => [
'periodo' => ['start' => null, 'end' => null],
'movimentacao_tipo' => null,
'movimentacao_subtipo_id' => null,
'unidade_id' => null,
'infraestrutura_id' => null,
'setor_id' => null,
'usuario_id' => null,
'origem_programatica_id' => null,
'material' => null,
],
];
}
public static function list()
{
$params = self::getParams();
switch (request()->listar) {
case 'movimentacao-tipos': {
return [
'movimentacao-tipos' => self::getMovimentacaoTipos($params),
'usuarios' => self::getUsuarios($params),
'origens_programaticas' => self::getOrigensProgramaticas($params),
];
}
case 'movimentacao-subtipos': {
return [
'movimentacao-subtipos' => self::getMovimentacaoSubtipos($params),
'unidades' => self::getUnidades($params),
'usuarios' => self::getUsuarios($params),
'origens_programaticas' => self::getOrigensProgramaticas($params),
];
}
case 'unidades': {
return [
'unidades' => self::getUnidades($params),
'usuarios' => self::getUsuarios($params),
'origens_programaticas' => self::getOrigensProgramaticas($params),
];
}
case 'infraestruturas': {
return [
'infraestruturas' => self::getInfraestruturas($params),
'usuarios' => self::getUsuarios($params),
'origens_programaticas' => self::getOrigensProgramaticas($params),
];
}
case 'setores': {
return [
'setores' => self::getSetores($params),
'usuarios' => self::getUsuarios($params),
'origens_programaticas' => self::getOrigensProgramaticas($params),
];
}
case 'usuarios': {
return [
'usuarios' => self::getUsuarios($params),
'origens_programaticas' => self::getOrigensProgramaticas($params),
];
}
}
}
public static function autocomplete()
{
$params = self::getParams();
$materiais = null;
if ($params->movimentacao_tipo === 'entrada') {
$materiais = DB::table('cadastro_material')
->select([
'cadastro_material.id',
'cadastro_material.codigo_material',
'cadastro_material.descricao',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'cadastro_unidade_medida'
) . ' AS material_descricao'),
])
->join('cadastro_apresentacao', 'cadastro_apresentacao.id', 'cadastro_material.apresentacao_id')
->join('cadastro_unidade_medida', 'cadastro_unidade_medida.id', 'cadastro_material.apresentacao_unidade_medida_id')
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_entrada_item')
->join('almoxarifado_entrada', 'almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->join('cadastro_centro_custo', 'cadastro_centro_custo.id', 'almoxarifado_entrada.centro_custo_id')
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->join('cadastro_lotacao', 'cadastro_lotacao.id', 'almoxarifado_entrada.created_lotacao_id')
->leftJoin('almoxarifado_entrada_documento', 'almoxarifado_entrada_documento.entrada_id', 'almoxarifado_entrada.id')
->whereBetween('almoxarifado_entrada.created_at', $params->periodo)
->where('almoxarifado_entrada.finalizada', true)
->when($params->movimentacao_subtipo_id, fn ($q) => $q->where('almoxarifado_entrada.tipo_id', $params->movimentacao_subtipo_id))
->when($params->unidade_id, fn ($q) => $q->where('cadastro_infraestrutura.unidade_id', $params->unidade_id))
->when($params->infraestrutura_id, fn ($q) => $q->where('cadastro_infraestrutura.id', $params->infraestrutura_id))
->when($params->setor_id, fn ($q) => $q->where('cadastro_centro_custo.setor_id', $params->setor_id))
->when($params->usuario_id, fn ($q) => $q->where('cadastro_lotacao.usuario_id', $params->usuario_id))
->when($params->origem_programatica_id, fn ($q) => $q->where('almoxarifado_entrada_documento.origem_programatica_id', $params->origem_programatica_id))
->whereColumn('almoxarifado_entrada_item.material_id', 'cadastro_material.id')
)
->orderBy('cadastro_material.descricao');
} else {
$materiais = DB::table('cadastro_material')
->select([
'cadastro_material.id',
'cadastro_material.codigo_material',
'cadastro_material.descricao',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'cadastro_unidade_medida'
) . ' AS material_descricao'),
])
->join('cadastro_apresentacao', 'cadastro_apresentacao.id', 'cadastro_material.apresentacao_id')
->join('cadastro_unidade_medida', 'cadastro_unidade_medida.id', 'cadastro_material.apresentacao_unidade_medida_id')
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_saida_item_entrada_item')
->join('almoxarifado_saida_item', 'almoxarifado_saida_item.id', 'almoxarifado_saida_item_entrada_item.saida_item_id')
->join('almoxarifado_saida', 'almoxarifado_saida.id', 'almoxarifado_saida_item.saida_id')
->join('cadastro_centro_custo', 'cadastro_centro_custo.id', 'almoxarifado_saida.centro_custo_id')
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->join('cadastro_lotacao', 'cadastro_lotacao.id', 'almoxarifado_saida.created_lotacao_id')
->join('almoxarifado_entrada_item', 'almoxarifado_entrada_item.id', 'almoxarifado_saida_item_entrada_item.entrada_item_id')
->join('almoxarifado_entrada', 'almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->leftJoin('almoxarifado_entrada_documento', 'almoxarifado_entrada_documento.entrada_id', 'almoxarifado_entrada.id')
->whereBetween('almoxarifado_saida.created_at', $params->periodo)
->where('almoxarifado_saida.finalizada', true)
->when($params->movimentacao_subtipo_id, fn ($q) => $q->where('almoxarifado_saida.tipo_id', $params->movimentacao_subtipo_id))
->when($params->unidade_id, fn ($q) => $q->where('cadastro_infraestrutura.unidade_id', $params->unidade_id))
->when($params->infraestrutura_id, fn ($q) => $q->where('cadastro_infraestrutura.id', $params->infraestrutura_id))
->when($params->setor_id, fn ($q) => $q->where('cadastro_centro_custo.setor_id', $params->setor_id))
->when($params->usuario_id, fn ($q) => $q->where('cadastro_lotacao.usuario_id', $params->usuario_id))
->when($params->origem_programatica_id, fn ($q) => $q->where('almoxarifado_entrada_documento.origem_programatica_id', $params->origem_programatica_id))
->whereColumn('almoxarifado_saida_item.material_id', 'cadastro_material.id')
)
->orderBy('cadastro_material.descricao');
}
return $materiais;
}
private static function getParams()
{
return (object) [
'periodo' => [
'start' => Carbon::createFromFormat('d/m/Y', request()->get('periodo')['start'])->setTime(0, 0, 0),
'end' => Carbon::createFromFormat('d/m/Y', request()->get('periodo')['end'])->setTime(23, 59, 59)
],
'movimentacao_tipo' => request()->get('movimentacao_tipo'),
'movimentacao_subtipo_id' => request()->get('movimentacao_subtipo_id'),
'unidade_id' => request()->get('unidade_id'),
'infraestrutura_id' => request()->get('infraestrutura_id'),
'setor_id' => request()->get('setor_id'),
'usuario_id' => request()->get('usuario_id'),
'origem_programatica_id' => request()->get('origem_programatica_id'),
'material_id' => request()->get('material_id'),
];
}
private static function getMovimentacaoTipos($params)
{
$movimentacaoTipos = collect();
$hasEntrada = DB::table('almoxarifado_entrada_item')
->join('almoxarifado_entrada', 'almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->whereBetween('almoxarifado_entrada.created_at', $params->periodo)
->where('almoxarifado_entrada.finalizada', true)
->exists();
$hasSaida = DB::table('almoxarifado_saida_item')
->join('almoxarifado_saida', 'almoxarifado_saida.id', 'almoxarifado_saida_item.saida_id')
->whereBetween('almoxarifado_saida.created_at', $params->periodo)
->where('almoxarifado_saida.finalizada', true)
->exists();
if ($hasEntrada) {
$movimentacaoTipos->push([
'value' => 'entrada',
'text' => 'ENTRADA',
]);
}
if ($hasSaida) {
$movimentacaoTipos->push([
'value' => 'saida',
'text' => 'SAÍDA',
]);
}
return $movimentacaoTipos->sortBy('text')->values();
}
private static function getMovimentacaoSubtipos($params)
{
$subtipos = collect();
if ($params->movimentacao_tipo === 'entrada') {
$subtipos = DB::table('almoxarifado_entrada_tipo')
->select([
'almoxarifado_entrada_tipo.id',
'almoxarifado_entrada_tipo.nome',
])
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_entrada')
->whereBetween('almoxarifado_entrada.created_at', $params->periodo)
->where('almoxarifado_entrada.finalizada', true)
->whereColumn('almoxarifado_entrada.tipo_id', 'almoxarifado_entrada_tipo.id')
)
->orderBy('almoxarifado_entrada_tipo.nome')
->get();
} else {
$subtipos = DB::table('almoxarifado_saida_tipo')
->select([
'almoxarifado_saida_tipo.id',
'almoxarifado_saida_tipo.nome',
])
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_saida')
->whereBetween('almoxarifado_saida.created_at', $params->periodo)
->where('almoxarifado_saida.finalizada', true)
->whereColumn('almoxarifado_saida.tipo_id', 'almoxarifado_saida_tipo.id')
)
->orderBy('almoxarifado_saida_tipo.nome')
->get();
}
return $subtipos;
}
private static function getUnidades($params)
{
$unidades = collect();
if ($params->movimentacao_tipo === 'entrada') {
$unidades = DB::table('cadastro_unidade')
->select([
'cadastro_unidade.id',
'cadastro_unidade.nome_fantasia',
])
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_entrada_item')
->join('almoxarifado_entrada', 'almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->join('cadastro_centro_custo', 'cadastro_centro_custo.id', 'almoxarifado_entrada.centro_custo_id')
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->whereBetween('almoxarifado_entrada.created_at', $params->periodo)
->where('almoxarifado_entrada.finalizada', true)
->when($params->movimentacao_subtipo_id, fn ($q) => $q->where('almoxarifado_entrada.tipo_id', $params->movimentacao_subtipo_id))
->whereColumn('cadastro_infraestrutura.unidade_id', 'cadastro_unidade.id')
)
->orderBy('cadastro_unidade.nome_fantasia')
->get();
} else {
$unidades = DB::table('cadastro_unidade')
->select([
'cadastro_unidade.id',
'cadastro_unidade.nome_fantasia',
])
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_saida_item')
->join('almoxarifado_saida', 'almoxarifado_saida.id', 'almoxarifado_saida_item.saida_id')
->join('cadastro_centro_custo', 'cadastro_centro_custo.id', 'almoxarifado_saida.centro_custo_id')
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->whereBetween('almoxarifado_saida.created_at', $params->periodo)
->where('almoxarifado_saida.finalizada', true)
->when($params->movimentacao_subtipo_id, fn ($q) => $q->where('almoxarifado_saida.tipo_id', $params->movimentacao_subtipo_id))
->whereColumn('cadastro_infraestrutura.unidade_id', 'cadastro_unidade.id')
)
->orderBy('cadastro_unidade.nome_fantasia')
->get();
}
return $unidades;
}
private static function getInfraestruturas($params)
{
$infraestruturas = collect();
if ($params->movimentacao_tipo === 'entrada') {
$infraestruturas = DB::table('cadastro_infraestrutura')
->select([
'cadastro_infraestrutura.id',
DB::raw("COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) AS nome"),
])
->join('cadastro_unidade', 'cadastro_unidade.id', 'cadastro_infraestrutura.unidade_id')
->where('cadastro_infraestrutura.unidade_id', $params->unidade_id)
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_entrada_item')
->join('almoxarifado_entrada', 'almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->join('cadastro_centro_custo', 'cadastro_centro_custo.id', 'almoxarifado_entrada.centro_custo_id')
->whereBetween('almoxarifado_entrada.created_at', $params->periodo)
->where('almoxarifado_entrada.finalizada', true)
->when($params->movimentacao_subtipo_id, fn ($q) => $q->where('almoxarifado_entrada.tipo_id', $params->movimentacao_subtipo_id))
->whereColumn('cadastro_centro_custo.infraestrutura_id', 'cadastro_infraestrutura.id')
)
->orderByRaw('COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia)')
->get();
} else {
$infraestruturas = DB::table('cadastro_infraestrutura')
->select([
'cadastro_infraestrutura.id',
DB::raw("COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) AS nome"),
])
->join('cadastro_unidade', 'cadastro_unidade.id', 'cadastro_infraestrutura.unidade_id')
->where('cadastro_infraestrutura.unidade_id', $params->unidade_id)
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_saida_item')
->join('almoxarifado_saida', 'almoxarifado_saida.id', 'almoxarifado_saida_item.saida_id')
->join('cadastro_centro_custo', 'cadastro_centro_custo.id', 'almoxarifado_saida.centro_custo_id')
->whereBetween('almoxarifado_saida.created_at', $params->periodo)
->where('almoxarifado_saida.finalizada', true)
->when($params->movimentacao_subtipo_id, fn ($q) => $q->where('almoxarifado_saida.tipo_id', $params->movimentacao_subtipo_id))
->whereColumn('cadastro_centro_custo.infraestrutura_id', 'cadastro_infraestrutura.id')
)
->orderByRaw('COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia)')
->get();
}
return $infraestruturas;
}
private static function getSetores($params)
{
$setores = collect();
if ($params->movimentacao_tipo === 'entrada') {
$setores = DB::table('cadastro_setor')
->select([
'cadastro_setor.id',
'cadastro_setor.nome',
])
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_entrada_item')
->join('almoxarifado_entrada', 'almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->join('cadastro_centro_custo', 'cadastro_centro_custo.id', 'almoxarifado_entrada.centro_custo_id')
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->whereBetween('almoxarifado_entrada.created_at', $params->periodo)
->where('almoxarifado_entrada.finalizada', true)
->when($params->movimentacao_subtipo_id, fn ($q) => $q->where('almoxarifado_entrada.tipo_id', $params->movimentacao_subtipo_id))
->where('cadastro_infraestrutura.unidade_id', $params->unidade_id)
->where('cadastro_infraestrutura.id', $params->infraestrutura_id)
->whereColumn('cadastro_centro_custo.setor_id', 'cadastro_setor.id')
)
->orderBy('cadastro_setor.nome')
->get();
} else {
$setores = DB::table('cadastro_setor')
->select([
'cadastro_setor.id',
'cadastro_setor.nome',
])
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_saida_item')
->join('almoxarifado_saida', 'almoxarifado_saida.id', 'almoxarifado_saida_item.saida_id')
->join('cadastro_centro_custo', 'cadastro_centro_custo.id', 'almoxarifado_saida.centro_custo_id')
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->whereBetween('almoxarifado_saida.created_at', $params->periodo)
->where('almoxarifado_saida.finalizada', true)
->when($params->movimentacao_subtipo_id, fn ($q) => $q->where('almoxarifado_saida.tipo_id', $params->movimentacao_subtipo_id))
->where('cadastro_infraestrutura.unidade_id', $params->unidade_id)
->where('cadastro_infraestrutura.id', $params->infraestrutura_id)
->whereColumn('cadastro_centro_custo.setor_id', 'cadastro_setor.id')
)
->orderBy('cadastro_setor.nome')
->get();
}
return $setores;
}
private static function getUsuarios($params)
{
$usuarios = collect();
if ($params->movimentacao_tipo === 'entrada') {
$usuarios = DB::table('cadastro_usuario')
->select([
'cadastro_usuario.id',
'cadastro_cidadao.nome',
])
->join('cadastro_cidadao', 'cadastro_cidadao.id', 'cadastro_usuario.cidadao_id')
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_entrada_item')
->join('almoxarifado_entrada', 'almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->join('cadastro_centro_custo', 'cadastro_centro_custo.id', 'almoxarifado_entrada.centro_custo_id')
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->join('cadastro_lotacao', 'cadastro_lotacao.id', 'almoxarifado_entrada.created_lotacao_id')
->whereBetween('almoxarifado_entrada.created_at', $params->periodo)
->where('almoxarifado_entrada.finalizada', true)
->when($params->movimentacao_subtipo_id, fn ($q) => $q->where('almoxarifado_entrada.tipo_id', $params->movimentacao_subtipo_id))
->when($params->unidade_id, fn ($q) => $q->where('cadastro_infraestrutura.unidade_id', $params->unidade_id))
->when($params->infraestrutura_id, fn ($q) => $q->where('cadastro_infraestrutura.id', $params->infraestrutura_id))
->when($params->setor_id, fn ($q) => $q->where('cadastro_centro_custo.setor_id', $params->setor_id))
->whereColumn('cadastro_lotacao.usuario_id', 'cadastro_usuario.id')
)
->orderBy('cadastro_cidadao.nome')
->get();
} else {
$usuarios = DB::table('cadastro_usuario')
->select([
'cadastro_usuario.id',
'cadastro_cidadao.nome',
])
->join('cadastro_cidadao', 'cadastro_cidadao.id', 'cadastro_usuario.cidadao_id')
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_saida_item')
->join('almoxarifado_saida', 'almoxarifado_saida.id', 'almoxarifado_saida_item.saida_id')
->join('cadastro_centro_custo', 'cadastro_centro_custo.id', 'almoxarifado_saida.centro_custo_id')
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->join('cadastro_lotacao', 'cadastro_lotacao.id', 'almoxarifado_saida.created_lotacao_id')
->whereBetween('almoxarifado_saida.created_at', $params->periodo)
->where('almoxarifado_saida.finalizada', true)
->when($params->movimentacao_subtipo_id, fn ($q) => $q->where('almoxarifado_saida.tipo_id', $params->movimentacao_subtipo_id))
->when($params->unidade_id, fn ($q) => $q->where('cadastro_infraestrutura.unidade_id', $params->unidade_id))
->when($params->infraestrutura_id, fn ($q) => $q->where('cadastro_infraestrutura.id', $params->infraestrutura_id))
->when($params->setor_id, fn ($q) => $q->where('cadastro_centro_custo.setor_id', $params->setor_id))
->whereColumn('cadastro_lotacao.usuario_id', 'cadastro_usuario.id')
)
->orderBy('cadastro_cidadao.nome')
->get();
}
return $usuarios;
}
private static function getOrigensProgramaticas($params)
{
$origens = collect();
if ($params->movimentacao_tipo === 'entrada') {
$origens = DB::table('cadastro_origem_programatica')
->select([
'cadastro_origem_programatica.id',
'cadastro_origem_programatica.nome',
])
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_entrada_item')
->join('almoxarifado_entrada', 'almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->join('almoxarifado_entrada_documento', 'almoxarifado_entrada_documento.entrada_id', 'almoxarifado_entrada.id')
->join('cadastro_centro_custo', 'cadastro_centro_custo.id', 'almoxarifado_entrada.centro_custo_id')
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->join('cadastro_lotacao', 'cadastro_lotacao.id', 'almoxarifado_entrada.created_lotacao_id')
->whereBetween('almoxarifado_entrada.created_at', $params->periodo)
->where('almoxarifado_entrada.finalizada', true)
->when($params->movimentacao_subtipo_id, fn ($q) => $q->where('almoxarifado_entrada.tipo_id', $params->movimentacao_subtipo_id))
->when($params->unidade_id, fn ($q) => $q->where('cadastro_infraestrutura.unidade_id', $params->unidade_id))
->when($params->infraestrutura_id, fn ($q) => $q->where('cadastro_infraestrutura.id', $params->infraestrutura_id))
->when($params->setor_id, fn ($q) => $q->where('cadastro_centro_custo.setor_id', $params->setor_id))
->when($params->usuario_id, fn ($q) => $q->where('cadastro_lotacao.usuario_id', $params->usuario_id))
->whereColumn('almoxarifado_entrada_documento.origem_programatica_id', 'cadastro_origem_programatica.id')
)
->orderBy('cadastro_origem_programatica.nome')
->get();
} else {
$origens = DB::table('cadastro_origem_programatica')
->select([
'cadastro_origem_programatica.id',
'cadastro_origem_programatica.nome',
])
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('almoxarifado_saida_item_entrada_item')
->join('almoxarifado_saida_item', 'almoxarifado_saida_item.id', 'almoxarifado_saida_item_entrada_item.saida_item_id')
->join('almoxarifado_saida', 'almoxarifado_saida.id', 'almoxarifado_saida_item.saida_id')
->join('cadastro_centro_custo', 'cadastro_centro_custo.id', 'almoxarifado_saida.centro_custo_id')
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->join('cadastro_lotacao', 'cadastro_lotacao.id', 'almoxarifado_saida.created_lotacao_id')
->join('almoxarifado_entrada_item', 'almoxarifado_entrada_item.id', 'almoxarifado_saida_item_entrada_item.entrada_item_id')
->join('almoxarifado_entrada', 'almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->join('almoxarifado_entrada_documento', 'almoxarifado_entrada_documento.entrada_id', 'almoxarifado_entrada.id')
->whereBetween('almoxarifado_saida.created_at', $params->periodo)
->where('almoxarifado_saida.finalizada', true)
->when($params->movimentacao_subtipo_id, fn ($q) => $q->where('almoxarifado_saida.tipo_id', $params->movimentacao_subtipo_id))
->when($params->unidade_id, fn ($q) => $q->where('cadastro_infraestrutura.unidade_id', $params->unidade_id))
->when($params->infraestrutura_id, fn ($q) => $q->where('cadastro_infraestrutura.id', $params->infraestrutura_id))
->when($params->setor_id, fn ($q) => $q->where('cadastro_centro_custo.setor_id', $params->setor_id))
->when($params->usuario_id, fn ($q) => $q->where('cadastro_lotacao.usuario_id', $params->usuario_id))
->whereColumn('almoxarifado_entrada_documento.origem_programatica_id', 'cadastro_origem_programatica.id')
)
->orderBy('cadastro_origem_programatica.nome')
->get();
}
return $origens;
}
private static function setOrderBy($builder)
{
if (is_null(request()->sort_by)) {
if (request()->movimentacao_tipo === 'entrada') {
$builder->orderBy('entrada_item_id');
} else {
$builder->orderBy('saida_item_id');
}
return;
}
if (request()->movimentacao_tipo === 'entrada') {
$columns = [
'data_movimentacao' => "DATE_FORMAT(almoxarifado_entrada.created_at, '%d/%m/%Y')",
'movimentacao_subtipo_nome' => 'almoxarifado_entrada_tipo.nome',
'unidade_nome_fantasia' => 'cadastro_unidade.nome_fantasia',
'infraestrutura_nome' => "COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia)",
'setor_nome' => 'cadastro_setor.nome',
'usuario_nome' => 'cadastro_cidadao.nome',
'material_descricao' => MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'cadastro_unidade_medida'
),
'grupo_nome' => 'cadastro_grupo.nome',
'quantidade' => 'almoxarifado_entrada_item.quantidade',
'valor_unitario' => 'almoxarifado_entrada_item.valor_unitario',
'valor_total' => 'almoxarifado_entrada_item.valor_total',
'lote' => 'almoxarifado_entrada_item.lote',
'validade_lote' => "DATE_FORMAT(almoxarifado_entrada_item.validade_lote, '%d/%m/%Y')",
'documento_numero' => 'CAST(almoxarifado_entrada_documento.numero AS INT)',
'fornecedor_nome_fantasia' => 'cadastro_fornecedor.nome_fantasia',
'origem_programatica_nome' => 'cadastro_origem_programatica.nome',
];
} else {
$columns = [
'data_movimentacao' => "DATE_FORMAT(almoxarifado_saida.created_at, '%d%m%Y')",
'movimentacao_subtipo_nome' => 'almoxarifado_saida_tipo.nome',
'unidade_nome_fantasia' => 'cadastro_unidade.nome_fantasia',
'infraestrutura_nome' => "COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia)",
'setor_nome' => 'cadastro_setor.nome',
'usuario_nome' => 'cadastro_cidadao.nome',
'material_descricao' => MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'cadastro_unidade_medida'
),
'grupo_nome' => 'cadastro_grupo.nome',
'quantidade' => 'almoxarifado_saida_item_entrada_item.quantidade_saida',
'valor_unitario' => 'almoxarifado_entrada_item.valor_unitario',
'valor_total' => "(almoxarifado_saida_item_entrada_item.quantidade_saida * almoxarifado_entrada_item.valor_unitario)",
'lote' => 'almoxarifado_entrada_item.lote',
'validade_lote' => "DATE_FORMAT(almoxarifado_entrada_item.validade_lote, '%d/%m/%Y')",
'documento_numero' => 'CAST(almoxarifado_entrada_documento.numero AS INT)',
'fornecedor_nome_fantasia' => 'cadastro_fornecedor.nome_fantasia',
'origem_programatica_nome' => 'cadastro_origem_programatica.nome',
];
}
$column = $columns[request()->sort_by];
$direction = DataUtil::getBooleanValueFromStringBoolean(request()->sort_desc) ? 'DESC' : 'ASC';
if (request()->movimentacao_tipo === 'entrada') {
$builder->orderByRaw("{$column} {$direction}, entrada_item_id");
} else {
$builder->orderByRaw("{$column} {$direction}, saida_item_id");
}
}
}

View File

@@ -0,0 +1,752 @@
<?php
namespace App\Services\Almoxarifado\Relatorios;
use App\Enums\Cadastro\Grupo\GrupoTipo;
use App\Models\Cadastro\Estabelecimento\CentroCusto;
use App\Models\Cadastro\Estabelecimento\Infraestrutura;
use App\Models\Cadastro\Estabelecimento\Unidade;
use App\Models\Cadastro\Grupo\Grupo;
use App\Models\Cadastro\Material\Material;
use App\Models\Cadastro\Subgrupo\Subgrupo;
use App\Services\Cadastro\Material\MaterialService;
use App\Services\Service;
use App\Utils\DataUtil;
use Illuminate\Support\Facades\DB;
class PosicaoEstoqueService extends Service
{
public static function index()
{
$materiais = collect();
$materiaisComEstoque = DB::table('cadastro_material')
->select([
'cadastro_material.id AS material_id',
'cadastro_material.codigo_material AS material_codigo',
'cadastro_material.is_programa_remedio_em_casa',
'cadastro_material.is_alto_custo',
'cadastro_material.is_acao_judicial',
'cadastro_material.is_remume',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
) . " AS material_descricao"),
'cadastro_grupo.grupo_tipo_id',
'cadastro_grupo.nome AS grupo_nome',
'cadastro_subgrupo.nome AS subgrupo_nome',
'almoxarifado_entrada_item.lote',
DB::raw("DATE_FORMAT(almoxarifado_entrada_item.validade_lote, '%d/%m/%Y') AS validade_lote"),
'almoxarifado_parametrizacao_estoque.estoque_minimo',
'almoxarifado_parametrizacao_estoque.estoque_maximo',
DB::raw("
COALESCE(SUM(
COALESCE(almoxarifado_entrada_item.quantidade, 0)
-
COALESCE((
SELECT SUM(almoxarifado_saida_item_entrada_item.quantidade_saida)
FROM almoxarifado_saida_item_entrada_item
JOIN almoxarifado_saida_item
ON almoxarifado_saida_item.id = almoxarifado_saida_item_entrada_item.saida_item_id
JOIN almoxarifado_saida
ON almoxarifado_saida.id = almoxarifado_saida_item.saida_id
WHERE almoxarifado_saida_item_entrada_item.entrada_item_id = almoxarifado_entrada_item.id
AND almoxarifado_saida.finalizada = 1
), 0)
), 0) AS quantidade
"),
'almoxarifado_entrada_item.id AS entrada_item_id',
])
->join('cadastro_grupo', 'cadastro_grupo.id', 'cadastro_material.grupo_id')
->leftJoin('cadastro_apresentacao', 'cadastro_apresentacao.id', 'cadastro_material.apresentacao_id')
->leftJoin(
'cadastro_unidade_medida as apresentacao_unidade_medida',
'apresentacao_unidade_medida.id',
'cadastro_material.apresentacao_unidade_medida_id'
)
->leftJoin('cadastro_subgrupo', 'cadastro_subgrupo.id', 'cadastro_material.subgrupo_id')
->leftJoin('almoxarifado_entrada_item', function ($join) {
$join->on('almoxarifado_entrada_item.material_id', 'cadastro_material.id')
->whereExists(function ($query) {
$query
->select(DB::raw(1))
->from('almoxarifado_entrada')
->whereColumn('almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->where('almoxarifado_entrada.finalizada', true)
->where('almoxarifado_entrada.centro_custo_id', request()->centro_custo_id);
});
})
->leftJoin('almoxarifado_parametrizacao_estoque', function ($join) {
$join->on('almoxarifado_parametrizacao_estoque.material_id', 'cadastro_material.id')
->where('almoxarifado_parametrizacao_estoque.centro_custo_id', request()->centro_custo_id);
})
->when(request()->query('grupo_id'), fn ($q, $id) => $q->where('cadastro_grupo.id', $id))
->when(request()->query('subgrupo_id'), fn ($q, $id) => $q->where('cadastro_subgrupo.id', $id))
->when(request()->query('material_id'), fn ($q, $id) => $q->where('cadastro_material.id', $id))
->whereNull('cadastro_material.deleted_at')
->when(request()->query('status'), function ($query) {
$sql = "
COALESCE((
SELECT COALESCE(SUM(
COALESCE(almoxarifado_entrada_item.quantidade, 0)
-
COALESCE((
SELECT SUM(almoxarifado_saida_item_entrada_item.quantidade_saida)
FROM almoxarifado_saida_item_entrada_item
JOIN almoxarifado_saida_item
ON almoxarifado_saida_item.id = almoxarifado_saida_item_entrada_item.saida_item_id
JOIN almoxarifado_saida
ON almoxarifado_saida.id = almoxarifado_saida_item.saida_id
WHERE almoxarifado_saida_item_entrada_item.entrada_item_id = almoxarifado_entrada_item.id
AND almoxarifado_saida.finalizada = 1
), 0)
), 0)
FROM almoxarifado_entrada_item
INNER JOIN almoxarifado_entrada
ON almoxarifado_entrada.id = almoxarifado_entrada_item.entrada_id
WHERE almoxarifado_entrada.finalizada = 1
AND almoxarifado_entrada.centro_custo_id = " . request()->centro_custo_id . "
AND almoxarifado_entrada_item.material_id = cadastro_material.id
), 0)
";
$where = null;
switch (request()->status) {
case 'abaixo_minimo':
$where = "$sql < COALESCE(almoxarifado_parametrizacao_estoque.estoque_minimo, 0)";
break;
case 'acima_maximo':
$where = "$sql > COALESCE(almoxarifado_parametrizacao_estoque.estoque_maximo, 0)";
break;
case 'normal':
$where = "$sql > 0 AND $sql >= COALESCE(almoxarifado_parametrizacao_estoque.estoque_minimo, 0) AND $sql <= COALESCE(almoxarifado_parametrizacao_estoque.estoque_maximo, 0)";
break;
case 'zerado':
$where = "$sql = 0";
break;
}
$query->whereRaw($where);
})
->where(function ($query) {
$query->where(function ($query) {
$query
->whereNull('cadastro_material.subgrupo_id')
->whereExists(function ($query) {
$query
->select(DB::raw(1))
->from('almoxarifado_parametrizacao_controle_estoque_grupo')
->whereColumn('almoxarifado_parametrizacao_controle_estoque_grupo.grupo_id', 'cadastro_material.grupo_id')
->where('almoxarifado_parametrizacao_controle_estoque_grupo.centro_custo_id', request()->centro_custo_id);
});
})
->orWhere(function ($query) {
$query
->whereNotNull('cadastro_material.subgrupo_id')
->whereExists(function ($query) {
$query
->select(DB::raw(1))
->from('almoxarifado_parametrizacao_controle_estoque_subgrupo')
->join(
'almoxarifado_parametrizacao_controle_estoque_grupo',
'almoxarifado_parametrizacao_controle_estoque_grupo.id',
'almoxarifado_parametrizacao_controle_estoque_subgrupo.parametrizacao_controle_estoque_grupo_id'
)
->whereColumn('almoxarifado_parametrizacao_controle_estoque_subgrupo.subgrupo_id', 'cadastro_material.subgrupo_id')
->where('almoxarifado_parametrizacao_controle_estoque_grupo.centro_custo_id', request()->centro_custo_id);
});
});
})
->groupBy([
'cadastro_material.id',
'cadastro_material.codigo_material',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
)),
'cadastro_grupo.nome',
'cadastro_subgrupo.nome',
'almoxarifado_entrada_item.lote',
DB::raw("DATE_FORMAT(almoxarifado_entrada_item.validade_lote, '%d/%m/%Y')"),
'almoxarifado_parametrizacao_estoque.estoque_minimo',
'almoxarifado_parametrizacao_estoque.estoque_maximo',
])
->havingRaw("
COALESCE(SUM(
COALESCE(almoxarifado_entrada_item.quantidade, 0)
-
COALESCE((
SELECT SUM(almoxarifado_saida_item_entrada_item.quantidade_saida)
FROM almoxarifado_saida_item_entrada_item
JOIN almoxarifado_saida_item
ON almoxarifado_saida_item.id = almoxarifado_saida_item_entrada_item.saida_item_id
JOIN almoxarifado_saida
ON almoxarifado_saida.id = almoxarifado_saida_item.saida_id
WHERE almoxarifado_saida_item_entrada_item.entrada_item_id = almoxarifado_entrada_item.id
AND almoxarifado_saida.finalizada = 1
), 0)
), 0) > 0
");
$materiaisSemEstoque = DB::table('cadastro_material')
->select([
'cadastro_material.id AS material_id',
'cadastro_material.codigo_material AS material_codigo',
'cadastro_material.is_programa_remedio_em_casa',
'cadastro_material.is_alto_custo',
'cadastro_material.is_acao_judicial',
'cadastro_material.is_remume',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
) . " AS material_descricao"),
'cadastro_grupo.grupo_tipo_id',
'cadastro_grupo.nome AS grupo_nome',
'cadastro_subgrupo.nome AS subgrupo_nome',
DB::raw('NULL AS lote'),
DB::raw('NULL AS validade_lote'),
'almoxarifado_parametrizacao_estoque.estoque_minimo',
'almoxarifado_parametrizacao_estoque.estoque_maximo',
DB::raw('0 AS quantidade'),
'almoxarifado_entrada_item.id AS entrada_item_id',
])
->join('cadastro_grupo', 'cadastro_grupo.id', 'cadastro_material.grupo_id')
->leftJoin('cadastro_apresentacao', 'cadastro_apresentacao.id', 'cadastro_material.apresentacao_id')
->leftJoin(
'cadastro_unidade_medida as apresentacao_unidade_medida',
'apresentacao_unidade_medida.id',
'cadastro_material.apresentacao_unidade_medida_id'
)
->leftJoin('cadastro_subgrupo', 'cadastro_subgrupo.id', 'cadastro_material.subgrupo_id')
->leftJoin('almoxarifado_parametrizacao_estoque', function ($join) {
$join->on('almoxarifado_parametrizacao_estoque.material_id', 'cadastro_material.id')
->where('almoxarifado_parametrizacao_estoque.centro_custo_id', request()->centro_custo_id);
})
->leftJoin('almoxarifado_entrada_item', 'almoxarifado_entrada_item.material_id', 'cadastro_material.id')
->when(request()->query('grupo_id'), fn ($q, $id) => $q->where('cadastro_grupo.id', $id))
->when(request()->query('subgrupo_id'), fn ($q, $id) => $q->where('cadastro_subgrupo.id', $id))
->when(request()->query('material_id'), fn ($q, $id) => $q->where('cadastro_material.id', $id))
->whereNull('cadastro_material.deleted_at')
->when(request()->query('status'), function ($query) {
$sql = "
COALESCE((
SELECT COALESCE(SUM(
COALESCE(almoxarifado_entrada_item.quantidade, 0)
-
COALESCE((
SELECT SUM(almoxarifado_saida_item_entrada_item.quantidade_saida)
FROM almoxarifado_saida_item_entrada_item
JOIN almoxarifado_saida_item
ON almoxarifado_saida_item.id = almoxarifado_saida_item_entrada_item.saida_item_id
JOIN almoxarifado_saida
ON almoxarifado_saida.id = almoxarifado_saida_item.saida_id
WHERE almoxarifado_saida_item_entrada_item.entrada_item_id = almoxarifado_entrada_item.id
AND almoxarifado_saida.finalizada = 1
), 0)
), 0)
FROM almoxarifado_entrada_item
INNER JOIN almoxarifado_entrada
ON almoxarifado_entrada.id = almoxarifado_entrada_item.entrada_id
WHERE almoxarifado_entrada.finalizada = 1
AND almoxarifado_entrada.centro_custo_id = " . request()->centro_custo_id . "
AND almoxarifado_entrada_item.material_id = cadastro_material.id
), 0)
";
$where = null;
switch (request()->status) {
case 'abaixo_minimo':
$where = "$sql < COALESCE(almoxarifado_parametrizacao_estoque.estoque_minimo, 0)";
break;
case 'acima_maximo':
$where = "$sql > COALESCE(almoxarifado_parametrizacao_estoque.estoque_maximo, 0)";
break;
case 'normal':
$where = "$sql > 0 AND $sql >= COALESCE(almoxarifado_parametrizacao_estoque.estoque_minimo, 0) AND $sql <= COALESCE(almoxarifado_parametrizacao_estoque.estoque_maximo, 0)";
break;
case 'zerado':
$where = "$sql = 0";
break;
}
$query->whereRaw($where);
})
->whereNotExists(function ($query) {
$query->select(DB::raw(1))
->from('almoxarifado_entrada_item')
->join('almoxarifado_entrada', 'almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->where('almoxarifado_entrada.finalizada', true)
->where('almoxarifado_entrada.centro_custo_id', request()->centro_custo_id)
->whereRaw("
COALESCE((
COALESCE(almoxarifado_entrada_item.quantidade, 0)
-
COALESCE((
SELECT SUM(almoxarifado_saida_item_entrada_item.quantidade_saida)
FROM almoxarifado_saida_item_entrada_item
JOIN almoxarifado_saida_item
ON almoxarifado_saida_item.id = almoxarifado_saida_item_entrada_item.saida_item_id
JOIN almoxarifado_saida
ON almoxarifado_saida.id = almoxarifado_saida_item.saida_id
WHERE almoxarifado_saida_item_entrada_item.entrada_item_id = almoxarifado_entrada_item.id
AND almoxarifado_saida.finalizada = 1
), 0)
), 0) > 0
")
->whereColumn('almoxarifado_entrada_item.material_id', 'cadastro_material.id');
})
->where(function ($query) {
$query->where(function ($query) {
$query
->whereNull('cadastro_material.subgrupo_id')
->whereExists(function ($query) {
$query
->select(DB::raw(1))
->from('almoxarifado_parametrizacao_controle_estoque_grupo')
->whereColumn('almoxarifado_parametrizacao_controle_estoque_grupo.grupo_id', 'cadastro_material.grupo_id')
->where('almoxarifado_parametrizacao_controle_estoque_grupo.centro_custo_id', request()->centro_custo_id);
});
})
->orWhere(function ($query) {
$query
->whereNotNull('cadastro_material.subgrupo_id')
->whereExists(function ($query) {
$query
->select(DB::raw(1))
->from('almoxarifado_parametrizacao_controle_estoque_subgrupo')
->join(
'almoxarifado_parametrizacao_controle_estoque_grupo',
'almoxarifado_parametrizacao_controle_estoque_grupo.id',
'almoxarifado_parametrizacao_controle_estoque_subgrupo.parametrizacao_controle_estoque_grupo_id'
)
->whereColumn('almoxarifado_parametrizacao_controle_estoque_subgrupo.subgrupo_id', 'cadastro_material.subgrupo_id')
->where('almoxarifado_parametrizacao_controle_estoque_grupo.centro_custo_id', request()->centro_custo_id);
});
});
});
$materiaisComEstoque
->union($materiaisSemEstoque)
->get()
->each(function ($query) use ($materiais) {
$material = $materiais->where('material_id', $query->material_id)->first();
if (is_null($material)) {
$material = (object) [
'material_id' => $query->material_id,
'material_codigo' => $query->material_codigo,
'material_descricao' => $query->material_descricao,
'is_programa_remedio_em_casa' => $query->is_programa_remedio_em_casa,
'is_alto_custo' => $query->is_alto_custo,
'is_acao_judicial' => $query->is_acao_judicial,
'is_remume' => $query->is_remume,
'grupo_tipo_id' => $query->grupo_tipo_id,
'grupo_nome' => $query->grupo_nome,
'subgrupo_nome' => $query->subgrupo_nome,
'lotes' => collect(),
'estoque_minimo' => $query->estoque_minimo ?? 0,
'estoque_maximo' => $query->estoque_maximo ?? 0,
'estoque_disponivel' => 0,
'status' => null,
];
$materiais->push($material);
}
$material->estoque_disponivel += $query->quantidade;
if (is_null($query->lote) && is_null($query->validade_lote) && $query->quantidade == 0) {
$loteExistente = $material->lotes->firstWhere('lote', '-');
if ($loteExistente) {
$loteExistente->quantidade += $query->quantidade;
} else {
$material->lotes->push((object) [
'lote' => '-',
'validade_lote' => '-',
'quantidade' => $query->quantidade,
]);
}
} else {
$material->lotes->push((object) [
'lote' => $query->lote ?? '-',
'validade_lote' => $query->validade_lote ?? '-',
'quantidade' => $query->quantidade,
]);
}
$programa = collect([]);
if($material->grupo_tipo_id === GrupoTipo::MEDICAMENTO) {
if($material->is_programa_remedio_em_casa) $programa->push("Programa remédio em casa");
if($material->is_alto_custo) $programa->push("Alto custo");
if($material->is_acao_judicial) $programa->push("Ação judicial");
if($material->is_remume) $programa->push("REMUME");
}
$material->programa = $programa->isNotEmpty() ? implode(', ', $programa->toArray()) : '-';
});
$materiais->each(function ($query) {
if ($query->estoque_disponivel < $query->estoque_minimo) {
$query->status = ['value' => 'abaixo_minimo', 'text' => 'Abaixo do mínimo'];
}
else if ($query->estoque_disponivel > $query->estoque_maximo) {
$query->status = ['value' => 'acima_maximo', 'text' => 'Acima do máximo'];
}
else {
$query->status = ['value' => 'normal', 'text' => 'Normal'];
}
});
$sortKey = self::setOrderBy(request()->sortBy);
$desc = DataUtil::getBooleanValueFromStringBoolean(request()->sortDesc);
$materiais = collect($materiais);
$materiais = $desc ? $materiais->sortByDesc($sortKey) : $materiais->sortBy($sortKey);
$materiais = $materiais->values();
return $materiais;
}
public static function list()
{
$data = (object) [
'form' => [],
'model' => [],
];
$params = self::getParams();
$sets = [
'unidade' => function () use ($data, $params) {
$unidadesData = self::getUnidadesData($params);
$data->form['unidades'] = $unidadesData['form'];
$data->model['unidade_id'] = $params->unidade_id = $unidadesData['model'];
},
'infraestrutura' => function () use ($data, $params) {
$infraestruturasData = self::getInfraestruturasData($params);
$data->form['infraestruturas'] = $infraestruturasData['form'];
$data->model['infraestrutura_id'] = $params->infraestrutura_id = $infraestruturasData['model'];
},
'centro_custo' => function () use ($data, $params) {
$centrosDeCustoData = self::getCentrosDeCustoData($params);
$data->form['centros_custo'] = $centrosDeCustoData['form'];
$data->model['centro_custo_id'] = $params->centro_custo_id = $centrosDeCustoData['model'];
},
'grupo' => function () use ($data, $params) {
$gruposData = self::getGruposData($params);
$data->form['grupos'] = $gruposData['form'];
$data->model['grupo_id'] = $params->grupo_id = $gruposData['model'];
},
'subgrupo' => function () use ($data, $params) {
$subgruposData = self::getSubgruposData($params);
$data->form['subgrupos'] = $subgruposData['form'];
$data->model['subgrupo_id'] = $params->subgrupo_id = $subgruposData['model'];
},
'material' => function () use ($data) {
$data->model['material'] = null;
},
'status' => function () use ($data, $params) {
$statusData = self::getStatusData();
$data->form['status'] = $statusData['form'];
$data->model['status'] = $params->status = $statusData['model'];
},
];
$load = is_null(request()->load_from);
foreach ($sets as $field => $set) {
if ($load) {
$set();
}
else if ($field === request()->load_from) {
$load = true;
}
}
foreach ($data as $property => $itens) {
if (empty($itens)) {
unset($data->{$property});
}
}
return $data;
}
private static function setOrderBy($sortBy)
{
if (is_null($sortBy)) {
return 'estoque_minimo';
}
$columns = [
'materialDescricao' => 'material_descricao',
'estoqueMinimo' => 'estoque_minimo',
'estoqueMaximo' => 'estoque_maximo',
'estoqueDisponivel' => 'estoque_disponivel',
'status' => 'status',
];
return $columns[$sortBy] ?? 'estoque_minimo';
}
private static function getParams()
{
$params = (object) request()->only([
'unidade_id',
'infraestrutura_id',
'centro_custo_id',
'grupo_id',
'subgrupo_id',
]);
return $params;
}
private static function getUnidadesData($params)
{
$unidades = Unidade::setEagerLoads([])
->whereHas('infraestruturas.centrosCusto', fn ($q) => self::setWhereForFilterCentroCusto($q, $params))
->orderBy('nome_fantasia')
->get(['id', 'nome_fantasia']);
return ['form' => $unidades, 'model' => null];
}
private static function getInfraestruturasData($params)
{
$infraestruturas = collect();
$id = null;
if (!is_null($params->unidade_id)) {
$infraestruturas = Infraestrutura::setEagerLoads([])
->where('unidade_id', $params->unidade_id)
->whereHas('centrosCusto', fn ($q) => self::setWhereForFilterCentroCusto($q, $params))
->get(['id', 'nome', 'principal', 'unidade_id'])
->map(fn ($i) => ['id' => $i->id, 'nome' => $i->nome])
->sortBy('nome')
->values();
if ($infraestruturas->count() === 1) {
$id = $infraestruturas->first()['id'];
}
}
return ['form' => $infraestruturas, 'model' => $id];
}
private static function getCentrosDeCustoData($params)
{
$centrosCusto = collect();
$id = null;
if (!is_null($params->infraestrutura_id)) {
$centrosCusto = CentroCusto::setEagerLoads([])
->where('infraestrutura_id', $params->infraestrutura_id)
->where(fn ($q) => self::setWhereForFilterCentroCusto($q, $params))
->get(['id', 'setor_id'])
->map(fn ($cc) => [
'id' => $cc->id,
'setor_nome' => $cc->setor()->setEagerLoads([])->first('nome')->nome
])
->sortBy('setor_nome')
->values();
if ($centrosCusto->count() === 1) {
$id = $centrosCusto->first()['id'];
}
}
return ['form' => $centrosCusto, 'model' => $id];
}
private static function setWhereForFilterCentroCusto($query)
{
return $query->has('almoxarifadoParametrizacoesControleEstoqueGrupo');
}
private static function getGruposData($params)
{
$grupos = collect();
$id = null;
if (!is_null($params->unidade_id)) {
$grupos = Grupo::setEagerLoads([])
->whereHas('almoxarifadoParametrizacoesControleEstoqueGrupo', fn ($q) => self::setWhereForFilterControlePermissaoGrupo($q, $params))
->orderBy('nome')
->get(['id', 'nome']);
}
return ['form' => $grupos, 'model' => $id];
}
private static function getSubgruposData($params)
{
$subgrupos = collect();
$id = null;
if (!is_null($params->grupo_id)) {
$subgrupos = Subgrupo::setEagerLoads([])
->where('grupo_id', $params->grupo_id)
->whereHas('almoxarifadoParametrizacoesControleEstoqueSubgrupo.parametrizacaoControleEstoqueGrupo', fn ($q) =>
self::setWhereForFilterControlePermissaoGrupo($q, $params)
)
->orderBy('nome')
->get(['id', 'nome']);
}
return ['form' => $subgrupos, 'model' => $id];
}
private static function getStatusData()
{
$status = [
['value' => 'abaixo_minimo', 'text' => 'Abaixo do mínimo'],
['value' => 'acima_maximo', 'text' => 'Acima do máximo'],
['value' => 'normal', 'text' => 'Normal'],
['value' => 'zerado', 'text' => 'Zerado'],
];
return ['form' => $status, 'model' => null];
}
public static function setWhereForFilterControlePermissaoGrupo($query, $params)
{
$query->where('centro_custo_id', $params->centro_custo_id);
}
public static function autocompleteMaterial()
{
$params = self::getParams();
$materiais = Material::setEagerLoads([])
->when($params->grupo_id, fn ($q, $grupoId) => $q->where('grupo_id', $grupoId))
->when($params->subgrupo_id, fn ($q, $subgrupoId) => $q->where('subgrupo_id', $subgrupoId))
->where('cadastro_material.deleted_at', null)
->where(fn ($q) =>
$q->where(fn ($q) =>
$q->whereNull('subgrupo_id')
->whereHas('grupo.almoxarifadoParametrizacoesControleEstoqueGrupo', fn ($q) =>
self::setWhereForFilterControlePermissaoGrupo($q, $params)
)
)
->orWhere(fn ($q) =>
$q->whereNotNull('subgrupo_id')
->whereHas('subgrupo.almoxarifadoParametrizacoesControleEstoqueSubgrupo.parametrizacaoControleEstoqueGrupo', fn ($q) =>
self::setWhereForFilterControlePermissaoGrupo($q, $params)
)
)
)
->getQuery()
->join(
'cadastro_apresentacao',
'cadastro_apresentacao.id',
'cadastro_material.apresentacao_id'
)
->leftJoin(
'cadastro_unidade_medida as apresentacao_unidade_medida',
'apresentacao_unidade_medida.id',
'cadastro_material.apresentacao_unidade_medida_id'
)
->select(
'cadastro_material.id',
'cadastro_material.codigo_material',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
) . " as descricao"),
'cadastro_material.possui_lote'
);
return $materiais;
}
public static function getPrintData()
{
$unidade = Unidade::find(request()->unidade_id);
$infraestrutura = Infraestrutura::find(request()->infraestrutura_id);
$centroCusto = CentroCusto::find(request()->centro_custo_id);
$grupo = Grupo::find(request()->grupo_id);
$subgrupo = Subgrupo::find(request()->subgrupo_id);
$material = Material::find(request()->material_id);
$status = 'Todos';
switch (request()->status) {
case 'abaixo_minimo':
$status = 'Abaixo do mínimo';
break;
case 'acima_maximo':
$status = 'Acima do máximo';
break;
case 'normal':
$status = 'Normal';
break;
case 'zerado':
$status = 'Zerado';
break;
}
return [
'unidade_nome_fantasia' => $unidade->nome_fantasia ?? 'Todas',
'infraestrutura_nome' => $infraestrutura->nome ?? 'Todos',
'setor_nome' => $centroCusto->setor->nome ?? 'Todos',
'grupo_nome' => $grupo->nome ?? 'Todos',
'subgrupo_nome' => $subgrupo->nome ?? 'Todos',
'material_descricao' => $material->descricao_completa ?? 'Todos',
'status' => $status,
'itens' => self::index(),
'colunas' => collect(request()->selectedCols),
];
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,258 @@
<?php
namespace App\Services\Almoxarifado\Relatorios;
use App\Models\Cadastro\Estabelecimento\CentroCusto;
use App\Models\Cadastro\Estabelecimento\Infraestrutura;
use App\Models\Cadastro\Estabelecimento\Unidade;
use App\Models\Cadastro\Grupo\Grupo;
use App\Models\Cadastro\Material\Material;
use App\Models\Cadastro\Subgrupo\Subgrupo;
use App\Services\Cadastro\Material\MaterialService;
use App\Services\Service;
use App\Utils\DataUtil;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
class ValidadeMaterialService extends Service
{
public static function index()
{
$totalizadores = (object) ['quantidade' => 0];
$validadeMaterialBuilder = DB::table('almoxarifado_entrada_item')
->join('almoxarifado_entrada', 'almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->join('cadastro_centro_custo', 'cadastro_centro_custo.id', 'almoxarifado_entrada.centro_custo_id')
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_centro_custo.infraestrutura_id')
->join('cadastro_material', 'cadastro_material.id', 'almoxarifado_entrada_item.material_id')
->join('cadastro_apresentacao', 'cadastro_apresentacao.id', 'cadastro_material.apresentacao_id')
->join('cadastro_grupo', 'cadastro_grupo.id', 'cadastro_material.grupo_id')
->leftJoin(
'cadastro_unidade_medida as apresentacao_unidade_medida',
'apresentacao_unidade_medida.id',
'cadastro_material.apresentacao_unidade_medida_id'
)
->leftJoin('cadastro_subgrupo', 'cadastro_subgrupo.id', 'cadastro_material.subgrupo_id')
->whereNull('almoxarifado_entrada_item.estornado_em')
->where('almoxarifado_entrada.finalizada', true)
->whereNotNull('almoxarifado_entrada_item.lote')
->when(request()->periodo['start'], fn ($q, $data) => $q
->where('almoxarifado_entrada_item.validade_lote', '>=', Carbon::createFromFormat('d/m/Y', $data)
->setTime(0, 0, 0))
)
->when(request()->periodo['end'], fn ($q, $data) => $q
->where('almoxarifado_entrada_item.validade_lote', '<=', Carbon::createFromFormat('d/m/Y', $data)
->setTime(23, 59, 59))
)
->when(request()->query('unidade_id'), fn ($q, $id) => $q->where('cadastro_infraestrutura.unidade_id', $id))
->when(request()->query('infraestrutura_id'), fn ($q, $id) => $q->where('cadastro_infraestrutura.id', $id))
->when(request()->query('centro_custo_id'), fn ($q, $id) => $q->where('cadastro_centro_custo.id', $id))
->when(request()->query('grupo_id'), fn ($q, $id) => $q->where('cadastro_grupo.id', $id))
->when(request()->query('subgrupo_id'), fn ($q, $id) => $q->where('cadastro_subgrupo.id', $id))
->when(request()->query('material_id'), fn ($q, $id) => $q->where('cadastro_material.id', $id))
->when(request()->query('situacao'), fn ($q, $situacao) => $q
->whereRaw("IF((DATEDIFF(almoxarifado_entrada_item.validade_lote, CURRENT_DATE) + 1) > 0, 1, 2) = {$situacao}")
)
->groupBy(
'cadastro_material.id',
'cadastro_material.codigo_material',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
)),
'almoxarifado_entrada_item.lote',
'almoxarifado_entrada_item.validade_lote',
'cadastro_grupo.nome',
'cadastro_subgrupo.nome',
DB::raw("DATEDIFF(almoxarifado_entrada_item.validade_lote, CURRENT_DATE) + 1")
)
->select(
'cadastro_material.id',
'cadastro_material.codigo_material',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
) . " AS descricao"),
'almoxarifado_entrada_item.lote',
DB::raw("almoxarifado_entrada_item.validade_lote AS validade"),
DB::raw("IF((DATEDIFF(almoxarifado_entrada_item.validade_lote, CURRENT_DATE) + 1) > 0, 'A Vencer', 'Vencido') AS situacao"),
'cadastro_grupo.nome AS grupo',
'cadastro_subgrupo.nome AS subgrupo',
DB::raw("DATEDIFF(almoxarifado_entrada_item.validade_lote, CURRENT_DATE) + 1 AS tempo_validade"),
DB::raw("COALESCE(SUM(
COALESCE(almoxarifado_entrada_item.quantidade, 0)
-
COALESCE((
SELECT SUM(almoxarifado_saida_item_entrada_item.quantidade_saida)
FROM almoxarifado_saida_item_entrada_item
JOIN almoxarifado_saida_item
ON almoxarifado_saida_item.id = almoxarifado_saida_item_entrada_item.saida_item_id
JOIN almoxarifado_saida
ON almoxarifado_saida.id = almoxarifado_saida_item.saida_id
WHERE almoxarifado_saida_item_entrada_item.entrada_item_id = almoxarifado_entrada_item.id
AND almoxarifado_saida.finalizada = 1
), 0)
), 0) AS estoque")
);
self::setOrderBy($validadeMaterialBuilder);
$validadeMaterialBuilder->havingRaw('estoque > 0');
$entradasItens = $validadeMaterialBuilder->get();
$totalizadores = [
'total' => $entradasItens->sum('estoque'),
];
return ['entradas_itens' => $entradasItens, 'totalizadores' => $totalizadores];
}
private static function setOrderBy($builder)
{
if (is_null(request()->sortBy)) {
$builder->orderBy('almoxarifado_entrada_item.id');
return;
}
$columns = [
'validade' => 'almoxarifado_entrada_item.validade_lote',
'codigo_material' => 'cadastro_material.codigo_material',
'descricao' => MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
),
'lote' => 'almoxarifado_entrada_item.lote',
'tempo_validade' => DB::raw("DATEDIFF(almoxarifado_entrada_item.validade_lote, CURRENT_DATE) + 1"),
'situacao' => DB::raw("IF((DATEDIFF(almoxarifado_entrada_item.validade_lote, CURRENT_DATE) + 1) > 0, 'A Vencer', 'Vencido')"),
'estoque' => DB::raw("COALESCE(SUM(
COALESCE(almoxarifado_entrada_item.quantidade, 0)
-
COALESCE((
SELECT SUM(almoxarifado_saida_item_entrada_item.quantidade_saida)
FROM almoxarifado_saida_item_entrada_item
JOIN almoxarifado_saida_item
ON almoxarifado_saida_item.id = almoxarifado_saida_item_entrada_item.saida_item_id
JOIN almoxarifado_saida
ON almoxarifado_saida.id = almoxarifado_saida_item.saida_id
WHERE almoxarifado_saida_item_entrada_item.entrada_item_id = almoxarifado_entrada_item.id
AND almoxarifado_saida.finalizada = 1
), 0)
), 0)"),
'grupo' => 'cadastro_grupo.nome',
'subgrupo' => 'cadastro_subgrupo.nome'
];
$column = $columns[request()->sortBy];
$direction = DataUtil::getBooleanValueFromStringBoolean(request()->sortDesc) ? 'DESC' : 'ASC';
$builder->orderByRaw("{$column} {$direction}, almoxarifado_entrada_item.id");
}
public static function list()
{
$now = Carbon::now();
$dataAtual = $now->format('d/m/Y');
$dataValidade = $now->addDays(90)->format('d/m/Y');
$currentLotacao = self::getCurrentLotacao();
return [
'additionals' => [],
'form' => [
'data_atual' => request()->dispensacao == 'true' ? $dataAtual : null,
'data_validade' => request()->dispensacao == 'true' ? $dataValidade : null,
'unidades' => Unidade::orderBy('nome_fantasia')
->whereHas('infraestruturas', function ($query) {
$query->whereHas('centrosCusto');
})
->get()
->map(fn ($unidade) => [
'id' => $unidade->id,
'nome_fantasia' => $unidade->nome_fantasia,
'infraestruturas' => $unidade->infraestruturas()
->whereHas('centrosCusto')
->get()
->sortBy('nome')
->map(fn ($infraestrutura) => [
'id' => $infraestrutura->id,
'nome' => $infraestrutura->nome,
'centros_custo' => $infraestrutura->centrosCusto()
->get()
->map(fn ($centroCusto) => [
'id' => $centroCusto->id,
'setor_nome' => $centroCusto->setor->nome,
])
->sortBy('setor_nome')
->values()
])
->values()
]),
'grupos' => Grupo::orderBy('nome')
->get()
->map(fn ($grupo) => [
'id' => $grupo->id,
'nome' => $grupo->nome,
'subgrupos' => $grupo->subgrupos()->orderBy('nome')->get(['id', 'nome'])
]),
'situacoes' => [
['text' => 'A vencer', 'value' => '1'],
['text' => 'Vencido', 'value' => '2'],
],
],
'model' => [
'periodo' => [
'start' => null,
'end' => null,
],
'unidade_id' => request()->dispensacao == 'true' ? $currentLotacao->infraestrutura->unidade->id : null,
'infraestrutura_id' => null,
'centro_custo_id' => null,
'grupo_id' => null,
'subgrupo_id' => null,
'material' => null,
'situacao' => null,
],
];
}
public static function getPrintExportData()
{
$resultado = self::index();
$itens = $resultado['entradas_itens'];
$itens->each(function ($item) {
$item->validade = (new Carbon($item->validade))->format('d/m/Y');
$item->situacao = $item->tempo_validade > 0 ? 'A vencer' : 'Vencido';
});
$unidade = Unidade::find(request()->unidade_id);
$infraestrutura = Infraestrutura::find(request()->infraestrutura_id);
$centroCusto = CentroCusto::find(request()->centro_custo_id);
$grupo = Grupo::find(request()->grupo_id);
$subgrupo = Subgrupo::find(request()->subgrupo_id);
$material = Material::find(request()->material_id);
return [
'inicio' => request()->periodo['start'],
'fim' => request()->periodo['end'],
'unidade' => $unidade->nome_fantasia ?? 'Todas',
'infraestrutura' => $infraestrutura->nome ?? 'Todas',
'setor' => $centroCusto->setor->nome ?? 'Todos',
'grupo' => $grupo->nome ?? 'Todos',
'subgrupo' => $subgrupo->nome ?? 'Todos',
'material' => $material->descricao_completa ?? 'Todos',
'colunas' => collect(request()->selectedCols),
'itens' => $itens,
'totalizadores' => $resultado['totalizadores'],
];
}
}

View File

@@ -0,0 +1,923 @@
<?php
namespace App\Services\Almoxarifado;
use App\Enums\Almoxarifado\RequisicaoRespostaItemMotivo;
use App\Enums\Almoxarifado\RequisicaoRespostaStatus;
use App\Enums\Almoxarifado\RequisicaoStatus;
use App\Models\Almoxarifado\EntradaItem;
use App\Models\Almoxarifado\ParametrizacaoRequisicao;
use App\Models\Almoxarifado\Requisicao;
use App\Models\Almoxarifado\RequisicaoPermissao;
use App\Models\Almoxarifado\RequisicaoRespostaItem;
use App\Models\Cadastro\Estabelecimento\CentroCusto;
use App\Models\Cadastro\Estabelecimento\Unidade;
use App\Models\Cadastro\Material\Material;
use App\Services\Cadastro\Material\MaterialService;
use App\Services\Service;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
class RequisicaoAberturaFechamentoService extends Service
{
public static function datatable()
{
$requisicoes = DB::table('almoxarifado_requisicao as requisicao')
->join(
'cadastro_centro_custo as centro_custo',
'centro_custo.id',
'requisicao.centro_custo_id'
)
->join(
'cadastro_infraestrutura as infraestrutura',
'infraestrutura.id',
'centro_custo.infraestrutura_id'
)
->join(
'cadastro_unidade as unidade',
'unidade.id',
'infraestrutura.unidade_id'
)
->join(
'cadastro_setor as setor',
'setor.id',
'centro_custo.setor_id'
)
->join(
'cadastro_lotacao as lotacao',
'lotacao.id',
'requisicao.created_lotacao_id'
)
->join(
'cadastro_usuario as usuario',
'usuario.id',
'lotacao.usuario_id'
)
->join(
'cadastro_cidadao as cidadao',
'cidadao.id',
'usuario.cidadao_id'
)
->where('requisicao.created_centro_custo_id', self::getCurrentCentroCusto()->id)
->where('requisicao.status_id', '<>', RequisicaoStatus::FINALIZADA)
->select(
'requisicao.id',
DB::raw("DATE_FORMAT(requisicao.created_at, '%d/%m/%Y') as data_requisicao"),
'unidade.nome_fantasia as unidade_nome_fantasia',
DB::raw("COALESCE(infraestrutura.nome, unidade.nome_fantasia) AS infraestrutura_nome"),
'setor.nome as setor_nome',
'cidadao.nome as usuario_requisitante',
'requisicao.numero',
DB::raw("IF(requisicao.status_id = " . RequisicaoStatus::RESPOSTA_INICIADA . ", 1, 0) as iniciou_resposta"),
)
->addSelect([
'possui_novo_envio' => function ($query) {
$query->select(DB::raw(1))
->from('almoxarifado_requisicao_resposta as resposta')
->whereColumn('resposta.requisicao_id', 'requisicao.id')
->where('resposta.status_id', RequisicaoRespostaStatus::ENVIADA)
->limit(1);
},
'data_ultimo_recebimento' => function ($query) {
$query->select(DB::raw("DATE_FORMAT(resposta.recebida_em, '%d/%m/%Y')"))
->from('almoxarifado_requisicao_resposta as resposta')
->whereColumn('resposta.requisicao_id', 'requisicao.id')
->where('resposta.status_id', RequisicaoRespostaStatus::RECEBIDA)
->orderByDesc('resposta.recebida_em')
->limit(1);
},
]);
return datatables()
->of($requisicoes)
->filterColumn('requisicao.created_at', function ($query, $keyword) {
$query->whereRaw("DATE_FORMAT(requisicao.created_at, '%d/%m/%Y') like ?", ["%{$keyword}%"])
->orWhereRaw(
"CONCAT(
SUBSTR(requisicao.created_at,9,2),
SUBSTR(requisicao.created_at,6,2),
SUBSTR(requisicao.created_at,1,4)
) like ?",
["%{$keyword}%"]
);
})
->filterColumn('infraestrutura.nome', function ($query, $keyword) {
$query->whereRaw("COALESCE(infraestrutura.nome, unidade.nome_fantasia) like ?", ["%{$keyword}%"]);
})
->skipTotalRecords()
->toJson();
}
public static function getEstoque($materialId, $centroCustoAlmoxarifadoId)
{
$estoque = MaterialService::getEstoque($materialId)['total'];
$estoqueMaximo = null;
$permiteRequisitar = null;
$permissao = RequisicaoPermissao::where('created_centro_custo_id', $centroCustoAlmoxarifadoId)
->where('centro_custo_requisitante_id', self::getCurrentCentroCusto()->id)
->where('material_id', $materialId)
->first();
if ($permissao && !is_null($permissao->estoque_maximo)) {
$estoqueMaximo = (int) $permissao->estoque_maximo;
$permiteRequisitar = $estoque > $estoqueMaximo ? 0 : $estoqueMaximo - $estoque;
}
$prazo = ParametrizacaoService::getParametrizacaoRequisicao()['prazo_validade'];
return [
'estoque' => $estoque,
'estoque_maximo' => $estoqueMaximo,
'permite_requisitar' => $permiteRequisitar,
'prazo' => $prazo,
'vencimento' => !empty(self::getValidades($materialId, $prazo)),
];
}
private static function getValidades($id, $prazo)
{
$hoje = Carbon::now()->startOfDay();
$dataFim = $hoje->copy()->addDays($prazo); // Crie uma cópia para não modificar $hoje
return EntradaItem::whereHas('entrada', fn($q) => $q->where('centro_custo_id', self::getCurrentCentroCusto()->id))
->where('material_id', $id)
->whereNull('estornado_em')
->whereBetween('validade_lote', [$hoje->format('Y-m-d'), $dataFim->format('Y-m-d')])
->get()
->map(function($q) {
return [
'validade' => Carbon::parse($q->validade_lote)->format('Y-m-d')
];
})->values()->all();
}
public static function getMateriaisPermitidos($centroCustoAlmoxarifadoId)
{
$permiteRequisitarSemEstoque = ParametrizacaoService::getParametrizacaoRequisicao()
['permite_requisitar_materiais_sem_estoque'];
$materiais = DB::table('cadastro_material')
->join(
'cadastro_apresentacao',
'cadastro_apresentacao.id',
'cadastro_material.apresentacao_id'
)
->join(
'cadastro_grupo',
'cadastro_grupo.id',
'cadastro_material.grupo_id'
)
->join(
'almoxarifado_requisicao_permissao',
'almoxarifado_requisicao_permissao.material_id',
'cadastro_material.id'
)
->leftJoin(
'cadastro_unidade_medida as apresentacao_unidade_medida',
'apresentacao_unidade_medida.id',
'cadastro_material.apresentacao_unidade_medida_id'
)
->leftJoin(
'cadastro_subgrupo',
'cadastro_subgrupo.id',
'cadastro_material.subgrupo_id'
)
->where('cadastro_material.is_ativo', true)
->where('almoxarifado_requisicao_permissao.centro_custo_requisitante_id', self::getCurrentCentroCusto()->id)
->where('almoxarifado_requisicao_permissao.created_centro_custo_id', $centroCustoAlmoxarifadoId)
->whereNull('cadastro_material.deleted_at')
->when(!$permiteRequisitarSemEstoque, function ($query) use ($centroCustoAlmoxarifadoId) {
$query->whereRaw("COALESCE((
SELECT SUM(
COALESCE(almoxarifado_entrada_item.quantidade, 0)
-
COALESCE((
SELECT SUM(almoxarifado_saida_item_entrada_item.quantidade_saida)
FROM almoxarifado_saida_item_entrada_item
JOIN almoxarifado_saida_item
ON almoxarifado_saida_item.id = almoxarifado_saida_item_entrada_item.saida_item_id
JOIN almoxarifado_saida
ON almoxarifado_saida.id = almoxarifado_saida_item.saida_id
WHERE almoxarifado_saida_item_entrada_item.entrada_item_id = almoxarifado_entrada_item.id
AND almoxarifado_saida.finalizada = 1
), 0)
-
COALESCE((
SELECT SUM(almoxarifado_reserva_item_entrada_item.quantidade_saida)
FROM almoxarifado_reserva_item_entrada_item
JOIN almoxarifado_reserva_item
ON almoxarifado_reserva_item.id = almoxarifado_reserva_item_entrada_item.reserva_item_id
WHERE almoxarifado_reserva_item_entrada_item.entrada_item_id = almoxarifado_entrada_item.id
), 0)
)
FROM almoxarifado_entrada_item
JOIN almoxarifado_entrada
ON almoxarifado_entrada.id = almoxarifado_entrada_item.entrada_id
WHERE almoxarifado_entrada.finalizada = 1
AND almoxarifado_entrada_item.material_id = cadastro_material.id
AND almoxarifado_entrada.centro_custo_id = {$centroCustoAlmoxarifadoId}
), 0) > 0");
})
->select(
'cadastro_material.id',
'cadastro_material.codigo_material',
DB::raw(MaterialService::getDescricaoCompletaRaw(
'cadastro_material',
'cadastro_apresentacao',
'apresentacao_unidade_medida'
) . " as descricao"),
'cadastro_grupo.id as grupo_id',
'cadastro_grupo.nome as grupo_nome',
'cadastro_subgrupo.nome as subgrupo',
'almoxarifado_requisicao_permissao.estoque_maximo'
)
->addSelect([
'requisicao_que_nao_concluiu_entrega' => function ($query) use ($centroCustoAlmoxarifadoId) {
$query->select(DB::raw('GROUP_CONCAT(DISTINCT almoxarifado_requisicao.numero ORDER BY almoxarifado_requisicao.numero SEPARATOR ", ")'))
->from('almoxarifado_requisicao_item')
->join(
'almoxarifado_requisicao',
'almoxarifado_requisicao.id',
'almoxarifado_requisicao_item.requisicao_id',
)
->whereColumn('almoxarifado_requisicao_item.material_id', 'cadastro_material.id')
->where('almoxarifado_requisicao.centro_custo_id', $centroCustoAlmoxarifadoId)
->where('almoxarifado_requisicao.created_centro_custo_id', self::getCurrentCentroCusto()->id)
->whereIn('almoxarifado_requisicao.status_id', [
RequisicaoStatus::ABERTA,
RequisicaoStatus::RESPOSTA_INICIADA,
])
->whereNotExists(function ($query) {
$query->select(DB::raw(1))
->from('almoxarifado_requisicao_resposta_item')
->join(
'almoxarifado_requisicao_resposta',
'almoxarifado_requisicao_resposta.id',
'almoxarifado_requisicao_resposta_item.requisicao_resposta_id',
)
->whereColumn(
'almoxarifado_requisicao_resposta_item.requisicao_item_id',
'almoxarifado_requisicao_item.id'
)
->where(
'almoxarifado_requisicao_resposta.status_id',
RequisicaoRespostaStatus::RECEBIDA
)
->where(function ($query) {
$query
->whereNull('almoxarifado_requisicao_resposta_item.motivo_id')
->orWhereNotIn('almoxarifado_requisicao_resposta_item.motivo_id', [
RequisicaoRespostaItemMotivo::ENTREGA_PARCIAL,
RequisicaoRespostaItemMotivo::PENDENTE_DE_ENTREGA,
]);
});
});
},
'estoque' => function ($query) {
$query->selectRaw("COALESCE((
SELECT SUM(
COALESCE(almoxarifado_entrada_item.quantidade, 0)
-
COALESCE((
SELECT SUM(almoxarifado_saida_item_entrada_item.quantidade_saida)
FROM almoxarifado_saida_item_entrada_item
JOIN almoxarifado_saida_item
ON almoxarifado_saida_item.id = almoxarifado_saida_item_entrada_item.saida_item_id
JOIN almoxarifado_saida
ON almoxarifado_saida.id = almoxarifado_saida_item.saida_id
WHERE almoxarifado_saida_item_entrada_item.entrada_item_id = almoxarifado_entrada_item.id
AND almoxarifado_saida.finalizada = 1
), 0)
-
COALESCE((
SELECT SUM(almoxarifado_reserva_item_entrada_item.quantidade_saida)
FROM almoxarifado_reserva_item_entrada_item
JOIN almoxarifado_reserva_item
ON almoxarifado_reserva_item.id = almoxarifado_reserva_item_entrada_item.reserva_item_id
WHERE almoxarifado_reserva_item_entrada_item.entrada_item_id = almoxarifado_entrada_item.id
), 0)
)
FROM almoxarifado_entrada_item
JOIN almoxarifado_entrada
ON almoxarifado_entrada.id = almoxarifado_entrada_item.entrada_id
WHERE almoxarifado_entrada.finalizada = 1
AND almoxarifado_entrada_item.material_id = cadastro_material.id
AND almoxarifado_entrada.centro_custo_id = " . self::getCurrentCentroCusto()->id . "
), 0)");
}
])
->distinct()
->get()
->all();
$grupos = collect();
$prazo = ParametrizacaoService::getParametrizacaoRequisicao()['prazo_validade'];
foreach ($materiais as $material) {
$estoqueMaximo = null;
$permiteRequisitar = null;
if (!is_null($material->estoque_maximo)) {
$estoqueMaximo = (int) $material->estoque_maximo;
$permiteRequisitar = $material->estoque > $estoqueMaximo
? 0 : $estoqueMaximo - $material->estoque;
}
$material->permite_requisitar = $permiteRequisitar;
$material->quantidade = null;
$material->prazo_vencimento = $prazo === null ? false : !empty(self::getValidades($material->id, $prazo));
$grupo = $grupos->where('id', $material->grupo_id)->first();
if (is_null($grupo)) {
$grupo = (object) [
'id' => $material->grupo_id,
'nome' => $material->grupo_nome,
'materiais' => collect()
];
$grupos->push($grupo);
}
unset($material->grupo_id, $material->grupo_nome);
$grupo->materiais->push($material);
}
return $grupos;
}
public static function create()
{
return [
'additionals' => self::getAdditionalsData(),
'form' => self::getFormData(),
'model' => [
'possui_novo_envio' => false,
'tem_recebimento_parcial' => false,
'centro_custo_id' => null,
'numero' => ParametrizacaoService::getParametrizacaoRequisicao()['numero_requisicao_automatico']
? ParametrizacaoService::getNovoNumeroRequisicao() : null,
'itens' => [],
]
];
}
public static function store()
{
self::validateStore();
$requisicao = new Requisicao();
DB::transaction(function () use ($requisicao) {
$requisicao->fill(request()->all());
$requisicao->status_id = RequisicaoStatus::ABERTA;
$requisicao->save();
$requisicao->itens()->createMany(request()->itens);
});
return $requisicao->fresh();
}
public static function validateStore()
{
$rules = [
'centro_custo_id' => [
'required',
'integer',
Rule::exists(CentroCusto::class, 'id'),
],
'numero' => [
'required',
'digits_between:1,20',
Rule::unique(Requisicao::class, 'numero')
],
'itens' => [
'required',
'array',
],
'itens.*.material_id' => [
'required',
'integer',
Rule::exists(Material::class, 'id'),
],
'itens.*.quantidade' => [
'required',
'integer',
'min:1',
'max:99999999'
],
];
$messages = [
'numero.unique' => 'O número da requisição já foi inserido anteriormente.',
];
request()->validate($rules, $messages);
}
public static function edit($id)
{
$requisicao = Requisicao::findOrFail($id);
$envio = self::getPrimeiraRespostaEnviada($requisicao);
$ultimoRecebimento = $requisicao->respostas()
->where('status_id', RequisicaoRespostaStatus::RECEBIDA)
->orderByDesc('id')
->first();
$itens = $requisicao->itens;
if ($ultimoRecebimento) {
$itens = $itens->filter(function ($item) use ($ultimoRecebimento) {
$ultimoRecebimentoItem = $ultimoRecebimento->itens()
->where('requisicao_item_id', $item->id)
->first();
return !is_null($ultimoRecebimentoItem) && collect([
RequisicaoRespostaItemMotivo::ENTREGA_PARCIAL,
RequisicaoRespostaItemMotivo::PENDENTE_DE_ENTREGA,
])->contains($ultimoRecebimentoItem->motivo_id);
});
}
return [
'additionals' => self::getAdditionalsData(),
'form' => self::getFormData($requisicao),
'model' => [
'possui_novo_envio' => !is_null($envio),
'tem_recebimento_parcial' => is_null($envio) ? false : $envio->itens()
->whereIn('motivo_id', [
RequisicaoRespostaItemMotivo::ENTREGA_PARCIAL,
RequisicaoRespostaItemMotivo::PENDENTE_DE_ENTREGA,
])
->exists(),
'centro_custo_id' => $requisicao->centro_custo_id,
'numero' => ParametrizacaoService::getParametrizacaoRequisicao()['numero_requisicao_automatico']
? ParametrizacaoService::getNovoNumeroRequisicao() : null,
'itens' => $itens->map(function ($item) {
$data = [
'material' => [
'id' => $item->material->id,
'codigo' => $item->material->codigo_material,
'descricao_completa' => $item->material->descricao_completa,
],
];
$respostaItemEnviada = $item->respostaItens()
->whereHas('requisicaoResposta', function ($query) {
$query->where('status_id', RequisicaoRespostaStatus::ENVIADA);
})
->orderBy('id')
->first();
$respostaItensRecebidas = $item->respostaItens()
->whereHas('requisicaoResposta', function ($query) {
$query->where('status_id', RequisicaoRespostaStatus::RECEBIDA);
})
->get();
$data['possui_entrada_com_lote'] = is_null($respostaItemEnviada)
|| is_null($respostaItemEnviada->saidaItem) ? false
: $respostaItemEnviada->saidaItem->entradaItens()->whereNotNull('lote')->exists();
if (is_null($respostaItemEnviada)) {
if ($respostaItensRecebidas->isEmpty()) {
$data['quantidade'] = $item->quantidade;
}
else {
$data['recebeu_anteriormente'] = $respostaItensRecebidas->sum('quantidade_recebimento');
$data['restante_requisitado'] = $item->quantidade - $data['recebeu_anteriormente'];
}
}
else {
$data['resposta_item_id'] = $respostaItemEnviada->id;
if ($respostaItensRecebidas->isEmpty()) {
$data['requisitado'] = $item->quantidade;
}
else {
$data['recebeu_anteriormente'] = $respostaItensRecebidas->sum('quantidade_recebimento');
$data['restante_requisitado'] = $item->quantidade - $data['recebeu_anteriormente'];
}
if ($data['possui_entrada_com_lote']) {
$data['entrada_itens'] = $respostaItemEnviada->saidaItem
? $respostaItemEnviada->saidaItem->entradaItens->map(fn ($entradaItem) => [
'entrada_item_id' => $entradaItem->id,
'enviado' => $entradaItem->pivotSaidaItemEntradaItem->quantidade_saida,
'recebido' => $entradaItem->pivotSaidaItemEntradaItem->quantidade_saida,
'lote' => $entradaItem->lote,
'validade_lote' => $entradaItem->validade_lote
? $entradaItem->validade_lote->format('d/m/Y') : null,
'possui_lote' => !is_null($entradaItem->lote),
]) : [];
}
else {
$data['enviado'] = $respostaItemEnviada->saidaItem
? $respostaItemEnviada->saidaItem->quantidade : 0;
$data['recebido'] = $data['enviado'];
}
}
return $data;
})->values()
]
];
}
private static function getPrimeiraRespostaEnviada($requisicao)
{
return $requisicao->respostas()
->where('status_id', RequisicaoRespostaStatus::ENVIADA)
->orderBy('id')
->first();
}
private static function getAdditionalsData()
{
$parametrizacaoRequisicao = ParametrizacaoService::getParametrizacaoRequisicao();
return [
'is_numero_requisicao_automatico' => $parametrizacaoRequisicao['numero_requisicao_automatico'],
'permite_requisitar_materiais_sem_estoque' => $parametrizacaoRequisicao['permite_requisitar_materiais_sem_estoque'],
];
}
private static function getFormData($requisicao = null)
{
$centroCustoLogadoId = self::getCurrentCentroCusto()->id;
$recebimentos = [];
if ($requisicao) {
$recebimentos = $requisicao->respostas()
->whereNotNull('recebida_em')
->orderBy('recebida_em')
->get();
$recebido = [];
$recebimentos = $recebimentos->map(function ($resposta, $i) use (&$recebido) {
$numeroRecebimento = $i + 1;
$itens = $resposta->itens->map(function ($respostaItem) use ($numeroRecebimento, &$recebido) {
$material = $respostaItem->requisicaoItem->material;
if (!isset($recebido[$material->id])) {
$recebido[$material->id] = 0;
}
$item = [
'material' => [
'codigo' => $material->codigo_material,
'descricao_completa' => $material->descricao_completa,
],
];
if ($numeroRecebimento === 1) {
$item['requisitado'] = $respostaItem->requisicaoItem->quantidade;
}
else {
$item['recebeu_anteriormente'] = $recebido[$material->id];
$item['restante_requisitado'] = $respostaItem->requisicaoItem->quantidade - $recebido[$material->id];
}
$item['possui_entrada_com_lote'] = is_null($respostaItem->saidaItem) ? false
: $respostaItem->saidaItem->entradaItens()->whereNotNull('lote')->exists();
if ($item['possui_entrada_com_lote']) {
$item['entrada_itens'] = $respostaItem->saidaItem
? $respostaItem->saidaItem->entradaItens
->map(function ($entradaItem) use ($respostaItem) {
$recebimento = $respostaItem->recebimentos()
->where('entrada_item_origem_id', $entradaItem->id)
->first();
$loteDiferente = $recebimento->lote !== $entradaItem->lote;
$validadeLoteDiferente = !is_null($recebimento->validade_lote)
&& !is_null($entradaItem->validade_lote)
? $recebimento->validade_lote->format('d/m/Y')
!== $entradaItem->validade_lote->format('d/m/Y')
: false;
return [
'enviado' => $entradaItem->pivotSaidaItemEntradaItem->quantidade_saida,
'recebido' => $recebimento->quantidade,
'lote' => $loteDiferente
? "{$entradaItem->lote} (Enviado) | {$recebimento->lote} (Recebido)"
: $recebimento->lote,
'validade_lote' => $entradaItem->validade_lote ? ($validadeLoteDiferente
? "{$entradaItem->validade_lote->format('d/m/Y')} (Enviado) | "
. "{$recebimento->validade_lote->format('d/m/Y')} (Recebido)"
: $recebimento->validade_lote->format('d/m/Y')) : null,
];
})
: [];
$recebido[$material->id] += collect($item['entrada_itens'])->sum('recebido');
}
else {
$item['enviado'] = $respostaItem->saidaItem ? $respostaItem->saidaItem->quantidade : 0;
$item['recebido'] = $respostaItem->quantidade_recebimento;
$recebido[$material->id] += $item['recebido'];
}
return $item;
});
return [
'numero_recebimento' => $numeroRecebimento,
'data_hora' => $resposta->recebida_em->format('d/m/Y H:i'),
'itens' => $itens,
];
});
}
return [
'unidades' => Unidade::orderBy('nome_fantasia')
->whereHas('infraestruturas', function ($query) use ($centroCustoLogadoId) {
$query->whereHas('centrosCusto', function ($query) use ($centroCustoLogadoId) {
$query
->where('id', '<>', $centroCustoLogadoId)
->whereHas('almoxarifadoRequisicaoPermissoesAlmoxarifado',
function ($query) use ($centroCustoLogadoId) {
$query->where('centro_custo_requisitante_id', $centroCustoLogadoId);
});
});
})
->get()
->map(fn ($unidade) => [
'id' => $unidade->id,
'nome_fantasia' => $unidade->nome_fantasia,
'infraestruturas' => $unidade->infraestruturas()
->whereHas('centrosCusto', function ($query) use ($centroCustoLogadoId) {
$query
->where('id', '<>', $centroCustoLogadoId)
->whereHas('almoxarifadoRequisicaoPermissoesAlmoxarifado',
function ($query) use ($centroCustoLogadoId) {
$query->where('centro_custo_requisitante_id', $centroCustoLogadoId);
});
})
->get()
->sortBy('nome')
->map(fn ($infraestrutura) => [
'id' => $infraestrutura->id,
'nome' => $infraestrutura->nome,
'centros_custo' => $infraestrutura->centrosCusto()
->where('id', '<>', $centroCustoLogadoId)
->whereHas('almoxarifadoRequisicaoPermissoesAlmoxarifado',
function ($query) use ($centroCustoLogadoId) {
$query->where('centro_custo_requisitante_id', $centroCustoLogadoId);
})
->get()
->map(fn ($centroCusto) => [
'id' => $centroCusto->id,
'setor_nome' => $centroCusto->setor->nome,
])
->sortBy('setor_nome')
->values()
])
->values()
]),
'modos' => [
['value' => 'padrao', 'text' => 'PADRÃO'],
['value' => 'sequencial', 'text' => 'SEQUENCIAL'],
],
'modo_value' => 'padrao',
'unidade_id' => $requisicao ? $requisicao->centroCusto->infraestrutura->unidade_id : null,
'infraestrutura_id' => $requisicao ? $requisicao->centroCusto->infraestrutura->id : null,
'usuario_requisitante_nome' => $requisicao ? $requisicao->createdLotacao->usuario->cidadao->nome : null,
'recebimentos' => collect($recebimentos)->sortByDesc('numero_recebimento')->values(),
];
}
public static function update($id)
{
self::validateUpdate();
$requisicao = Requisicao::findOrFail($id);
DB::transaction(function () use ($requisicao) {
$respostaItem = null;
$entradaItensData = collect();
$finalizouEntrega = true;
$motivosDeEntregaNaoFinalizada = collect([
RequisicaoRespostaItemMotivo::ENTREGA_PARCIAL,
RequisicaoRespostaItemMotivo::PENDENTE_DE_ENTREGA
]);
foreach (request()->itens as $item) {
$respostaItem = RequisicaoRespostaItem::findOrFail($item['resposta_item_id']);
$material = $respostaItem->requisicaoItem->material;
$controlaEstoque = ParametrizacaoService::controlaEstoque($material->id);
$possuiEntradaComLote = false;
if (isset($item['entrada_itens'])) {
collect($item['entrada_itens'])->each(function ($entradaItem) use (&$possuiEntradaComLote) {
if (!is_null(EntradaItem::findOrFail($entradaItem['entrada_item_id'])->lote)) {
$possuiEntradaComLote = true;
return false;
}
});
}
if ($possuiEntradaComLote) {
$entradaItens = collect();
foreach ($item['entrada_itens'] as $entradaItemData) {
$data = [
'entrada_item_origem_id' => $entradaItemData['entrada_item_id'],
'lote' => $entradaItemData['lote'],
'validade_lote' => $entradaItemData['validade_lote']
? Carbon::createFromFormat('d/m/Y', $entradaItemData['validade_lote'])
: null,
'quantidade' => $entradaItemData['recebido'],
'controlava_estoque' => $controlaEstoque,
];
$respostaItem->recebimentos()->create($data);
if ($entradaItemData['recebido'] > 0) {
$entradaItens->push($data);
}
}
if ($entradaItens->isNotEmpty() && $controlaEstoque) {
$entradaItensData->push([
'saida_item_id' => $respostaItem->saida_item_id,
'possui_entrada_com_lote' => $possuiEntradaComLote,
'entrada_itens' => $entradaItens,
]);
}
}
else {
$data = [
'saida_item_id' => $respostaItem->saida_item_id,
'possui_entrada_com_lote' => $possuiEntradaComLote,
'quantidade' => $item['recebido'],
'controlava_estoque' => $controlaEstoque,
];
$respostaItem->recebimentos()->create($data);
if ($item['recebido'] > 0 && $controlaEstoque) {
$entradaItensData->push($data);
}
}
if ($motivosDeEntregaNaoFinalizada->contains($respostaItem->motivo_id)) {
$finalizouEntrega = false;
}
}
if ($entradaItensData->isNotEmpty()) {
$entradasItensSaved = AlmoxarifadoService::saveEntradasDeRequisicao($entradaItensData);
$entradasItensSaved->each(function ($entradaItem) {
RequisicaoRespostaItem::firstWhere('saida_item_id', $entradaItem['saida_item_id'])
->entradaItens()
->attach($entradaItem['entrada_item_id']);
});
}
$respostaItem->requisicaoResposta()->update([
'status_id' => RequisicaoRespostaStatus::RECEBIDA,
'recebida_em' => Carbon::now(),
]);
if ($finalizouEntrega) {
$requisicao->update(['status_id' => RequisicaoStatus::FINALIZADA]);
}
});
$requisicao->refresh();
$requisicao->possui_novo_envio = !is_null(self::getPrimeiraRespostaEnviada($requisicao));
return $requisicao;
}
public static function validateUpdate()
{
$rules = [
'itens' => [
'required',
'array',
],
'itens.*.resposta_item_id' => [
'required',
'integer',
Rule::exists(RequisicaoRespostaItem::class, 'id'),
],
'itens.*.recebido' => [
'integer',
],
'itens.*.entrada_itens' => [
'array',
],
'itens.*.entrada_itens.*.entrada_item_id' => [
'required',
'integer',
Rule::exists(EntradaItem::class, 'id'),
],
'itens.*.entrada_itens.*.recebido' => [
'required',
'integer',
],
'itens.*.entrada_itens.*.possui_lote' => [
'required',
'boolean',
],
'itens.*.entrada_itens.*.lote' => [
'required_if:itens.*.entrada_itens.*.possui_lote,true',
'nullable',
'string',
'max:15',
],
'itens.*.entrada_itens.*.validade_lote' => [
'required_if:itens.*.entrada_itens.*.possui_lote,true',
'nullable',
'date_format:d/m/Y',
],
];
$messages = [];
request()->validate($rules, $messages);
}
public static function destroy($id)
{
Requisicao::findOrFail($id)->delete();
return null;
}
}

View File

@@ -0,0 +1,964 @@
<?php
namespace App\Services\Almoxarifado;
use App\Enums\Almoxarifado\RequisicaoRespostaItemMotivo as RequisicaoRespostaItemMotivoEnum;
use App\Enums\Almoxarifado\RequisicaoRespostaStatus;
use App\Enums\Almoxarifado\RequisicaoStatus;
use App\Models\Almoxarifado\EntradaItem;
use App\Models\Almoxarifado\ParametrizacaoRequisicao;
use App\Models\Almoxarifado\Requisicao;
use App\Models\Almoxarifado\RequisicaoItem;
use App\Models\Almoxarifado\RequisicaoPermissao;
use App\Models\Almoxarifado\RequisicaoRespostaItemMotivo;
use App\Models\Cadastro\Estabelecimento\CentroCusto;
use App\Models\Cadastro\Estabelecimento\Unidade;
use App\Models\Cadastro\Material\Material;
use App\Services\Service;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
class RequisicaoPendentePermissaoService extends Service
{
public static function datatable()
{
$requisicoes = DB::table('almoxarifado_requisicao as requisicao')
->join(
'cadastro_centro_custo as centro_custo',
'centro_custo.id',
'requisicao.created_centro_custo_id'
)
->join(
'cadastro_infraestrutura as infraestrutura',
'infraestrutura.id',
'centro_custo.infraestrutura_id'
)
->join(
'cadastro_unidade as unidade',
'unidade.id',
'infraestrutura.unidade_id'
)
->join(
'cadastro_setor as setor',
'setor.id',
'centro_custo.setor_id'
)
->join(
'cadastro_lotacao as lotacao',
'lotacao.id',
'requisicao.created_lotacao_id'
)
->join(
'cadastro_usuario as usuario',
'usuario.id',
'lotacao.usuario_id'
)
->join(
'cadastro_cidadao as cidadao',
'cidadao.id',
'usuario.cidadao_id'
)
->where('requisicao.status_id', '<>', RequisicaoStatus::FINALIZADA)
->where('requisicao.centro_custo_id', self::getCurrentCentroCusto()->id)
->where(function ($query) {
$query->whereNotExists(function ($query) {
$query->select(DB::raw(1))
->from('almoxarifado_requisicao_resposta as resposta')
->whereColumn('resposta.requisicao_id', 'requisicao.id')
->where('resposta.status_id', RequisicaoRespostaStatus::ENVIADA);
})->orWhereRaw("EXISTS (
SELECT 1
FROM almoxarifado_requisicao_resposta_item as resposta_item
WHERE resposta_item.requisicao_resposta_id = (
SELECT resposta.id
FROM almoxarifado_requisicao_resposta as resposta
WHERE resposta.requisicao_id = requisicao.id
AND resposta.status_id = " . RequisicaoRespostaStatus::ENVIADA . "
ORDER BY resposta.id DESC
LIMIT 1
)
AND resposta_item.motivo_id IN (
" . RequisicaoRespostaItemMotivoEnum::ENTREGA_PARCIAL . ",
" . RequisicaoRespostaItemMotivoEnum::PENDENTE_DE_ENTREGA . "
)
)");
})
->select(
'requisicao.id',
DB::raw("DATE_FORMAT(requisicao.created_at, '%d/%m/%Y') as data_requisicao"),
'unidade.nome_fantasia as unidade_nome_fantasia',
DB::raw("COALESCE(infraestrutura.nome, unidade.nome_fantasia) AS infraestrutura_nome"),
'setor.nome as setor_nome',
'cidadao.nome as usuarioNome',
'requisicao.numero',
DB::raw("IF(requisicao.status_id = " . RequisicaoStatus::RESPOSTA_INICIADA . ", 1, 0) as iniciou_resposta"),
)
->addSelect([
'possui_envio_pendente' => function ($query) {
$query->selectRaw("COALESCE((
SELECT 1
FROM almoxarifado_requisicao_resposta_item as resposta_item
WHERE resposta_item.requisicao_resposta_id = (
SELECT resposta.id
FROM almoxarifado_requisicao_resposta as resposta
WHERE resposta.requisicao_id = requisicao.id
AND resposta.enviada_em IS NOT NULL
ORDER BY resposta.id DESC
LIMIT 1
)
AND resposta_item.motivo_id IN (
" . RequisicaoRespostaItemMotivoEnum::ENTREGA_PARCIAL . ",
" . RequisicaoRespostaItemMotivoEnum::PENDENTE_DE_ENTREGA . "
)
LIMIT 1
), 0)");
}
]);
return datatables()
->of($requisicoes)
->filterColumn('requisicao.created_at', function ($query, $keyword) {
$query->whereRaw("DATE_FORMAT(requisicao.created_at, '%d/%m/%Y') like ?", ["%{$keyword}%"])
->orWhereRaw(
"CONCAT(
SUBSTR(requisicao.created_at,9,2),
SUBSTR(requisicao.created_at,6,2),
SUBSTR(requisicao.created_at,1,4)
) like ?",
["%{$keyword}%"]
);
})
->filterColumn('infraestrutura.nome', function ($query, $keyword) {
$query->whereRaw("COALESCE(infraestrutura.nome, unidade.nome_fantasia) like ?", ["%{$keyword}%"]);
})
->skipTotalRecords()
->toJson();
}
public static function datatablePermissao()
{
$centrosCusto = DB::table('cadastro_centro_custo as centro_custo')
->join(
'cadastro_infraestrutura as infraestrutura',
'infraestrutura.id',
'centro_custo.infraestrutura_id'
)
->join(
'cadastro_unidade as unidade',
'unidade.id',
'infraestrutura.unidade_id'
)
->join(
'cadastro_setor as setor',
'setor.id',
'centro_custo.setor_id'
)
->whereNull('centro_custo.deleted_at')
->where('centro_custo.id', '<>', self::getCurrentCentroCusto()->id)
->select(
'centro_custo.id',
'unidade.cnes',
'unidade.nome_fantasia as unidade_nome_fantasia',
DB::raw("COALESCE(infraestrutura.nome, unidade.nome_fantasia) AS infraestrutura_nome"),
'setor.nome as setor_nome',
);
return datatables()
->of($centrosCusto)
->filterColumn('infraestrutura.nome', function ($query, $keyword) {
$query->whereRaw("COALESCE(infraestrutura.nome, unidade.nome_fantasia) like ?", ["%{$keyword}%"]);
})
->skipTotalRecords()
->toJson();
}
public static function getMateriais($centroCustoRequisitanteId)
{
$centroCustoLogadoId = self::getCurrentCentroCusto()->id;
$grupos = self::getCurrentCentroCusto()
->almoxarifadoParametrizacoesControleEstoqueGrupo
->map(fn ($parametrizacaoGrupo) => [
'id' => $parametrizacaoGrupo->grupo->id,
'nome' => $parametrizacaoGrupo->grupo->nome,
'materiais' => $parametrizacaoGrupo->grupo->materiais()
->where('is_ativo', true)
->where(function ($query) use ($parametrizacaoGrupo) {
$query
->whereDoesntHave('subgrupo')
->orWhereHas('subgrupo', function ($query) use ($parametrizacaoGrupo) {
$query->whereHas('almoxarifadoParametrizacoesControleEstoqueSubgrupo',
function ($query) use ($parametrizacaoGrupo) {
$query->where('parametrizacao_controle_estoque_grupo_id', $parametrizacaoGrupo->id);
}
);
});
})
->get()
->map(function ($material) use ($centroCustoLogadoId, $centroCustoRequisitanteId) {
$permissao = $material->almoxarifadoRequisicaoPermissoes()
->where('created_centro_custo_id', $centroCustoLogadoId)
->where('centro_custo_requisitante_id', $centroCustoRequisitanteId)
->first();
return [
'id' => $material->id,
'permite_requisitar' => !is_null($permissao),
'codigo' => $material->codigo_material,
'descricao_completa' => $material->descricao_completa,
'subgrupo_nome' => $material->subgrupo->nome ?? null,
'estoque_maximo' => $permissao->estoque_maximo ?? null,
];
}),
])
->all();
foreach ($grupos as &$grupo) {
$grupo['permite_requisitar'] = collect($grupo['materiais'])
->contains('permite_requisitar', true);
}
unset($grupo);
return $grupos;
}
public static function datatableHistorico()
{
$requisicoes = DB::table('almoxarifado_requisicao as requisicao')
->join(
'cadastro_centro_custo as centro_custo',
'centro_custo.id',
'requisicao.created_centro_custo_id'
)
->join(
'cadastro_infraestrutura as infraestrutura',
'infraestrutura.id',
'centro_custo.infraestrutura_id'
)
->join(
'cadastro_unidade as unidade',
'unidade.id',
'infraestrutura.unidade_id'
)
->join(
'cadastro_setor as setor',
'setor.id',
'centro_custo.setor_id'
)
->join(
'cadastro_lotacao as lotacao',
'lotacao.id',
'requisicao.created_lotacao_id'
)
->join(
'cadastro_usuario as usuario',
'usuario.id',
'lotacao.usuario_id'
)
->join(
'cadastro_cidadao as cidadao',
'cidadao.id',
'usuario.cidadao_id'
)
->where('requisicao.centro_custo_id', self::getCurrentCentroCusto()->id)
->where('unidade.id', request()->unidade_requisitante_id)
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('almoxarifado_requisicao_item as item')
->join(
'almoxarifado_requisicao_resposta_item as resposta_item',
'resposta_item.requisicao_item_id',
'item.id'
)
->whereColumn('item.requisicao_id', 'requisicao.id')
->where('item.material_id', request()->material_id)
->whereNotNull('saida_item_id');
})
->select(
'requisicao.id',
'requisicao.numero',
DB::raw("DATE_FORMAT(requisicao.created_at, '%d/%m/%Y') as data_requisicao"),
DB::raw("COALESCE(infraestrutura.nome, unidade.nome_fantasia) AS infraestrutura_nome"),
'setor.nome as setor_nome',
'cidadao.nome as usuario_nome',
)
->addSelect([
'concedido' => function ($query) {
$query->select(DB::raw('SUM(saida_item_entrada_item.quantidade_saida)'))
->from('almoxarifado_saida_item_entrada_item as saida_item_entrada_item')
->join(
'almoxarifado_saida_item as saida_item',
'saida_item.id',
'saida_item_entrada_item.saida_item_id'
)
->join(
'almoxarifado_requisicao_resposta_item as resposta_item',
'resposta_item.saida_item_id',
'saida_item.id'
)
->join(
'almoxarifado_requisicao_item as requisicao_item',
'requisicao_item.id',
'resposta_item.requisicao_item_id'
)
->whereColumn('requisicao_item.requisicao_id', 'requisicao.id')
->where('requisicao_item.material_id', request()->material_id);
}
]);
return datatables()
->of($requisicoes)
->filterColumn('requisicao.created_at', function ($query, $keyword) {
$query->whereRaw("DATE_FORMAT(requisicao.created_at, '%d/%m/%Y') like ?", ["%{$keyword}%"]);
})
->filterColumn('infraestrutura.nome', function ($query, $keyword) {
$query->whereRaw("COALESCE(infraestrutura.nome, unidade.nome_fantasia) like ?", ["%{$keyword}%"]);
})
->toJson();
}
public static function storePermissoes()
{
self::validatePermissao();
DB::transaction(function () {
RequisicaoPermissao::where('created_centro_custo_id', self::getCurrentCentroCusto()->id)
->where('centro_custo_requisitante_id', request()->centro_custo_requisitante_id)
->whereNotIn('material_id', collect(request()->materiais)->pluck('id'))
->delete();
foreach (request()->materiais as $material) {
RequisicaoPermissao::updateOrCreate(
[
'created_centro_custo_id' => self::getCurrentCentroCusto()->id,
'centro_custo_requisitante_id' => request()->centro_custo_requisitante_id,
'material_id' => $material['id'],
],
[
'estoque_maximo' => $material['estoque_maximo'],
]
);
}
});
}
private static function validatePermissao()
{
$rules = [
'centro_custo_requisitante_id' => [
'required',
'integer',
Rule::exists(CentroCusto::class, 'id'),
],
'materiais' => [
'present',
'array',
],
'materiais.*.id' => [
'required',
'integer',
Rule::exists(Material::class, 'id'),
],
'materiais.*.estoque_maximo' => [
'nullable',
'integer',
'max:99999999',
]
];
$messages = [];
request()->validate($rules, $messages);
}
public static function createImportacao($centroCustoDestinoId)
{
$centroCustoLogadoId = self::getCurrentCentroCusto()->id;
return [
'form' => [
'unidades' => Unidade::orderBy('nome_fantasia')
->whereHas('infraestruturas', function ($query) use ($centroCustoDestinoId, $centroCustoLogadoId) {
$query->whereHas('centrosCusto', function ($query) use ($centroCustoDestinoId, $centroCustoLogadoId) {
$query
->where('id', '<>', $centroCustoDestinoId)
->whereHas('almoxarifadoRequisicaoPermissoesRequisitante', function ($query) use ($centroCustoLogadoId) {
$query->where('created_centro_custo_id', $centroCustoLogadoId);
});
});
})
->get()
->map(fn ($unidade) => [
'id' => $unidade->id,
'nome_fantasia' => $unidade->nome_fantasia,
'infraestruturas' => $unidade->infraestruturas()
->whereHas('centrosCusto', function ($query) use ($centroCustoDestinoId, $centroCustoLogadoId) {
$query
->where('id', '<>', $centroCustoDestinoId)
->whereHas('almoxarifadoRequisicaoPermissoesRequisitante', function ($query) use ($centroCustoLogadoId) {
$query->where('created_centro_custo_id', $centroCustoLogadoId);
});
})
->get()
->sortBy('nome')
->map(fn ($infraestrutura) => [
'id' => $infraestrutura->id,
'nome' => $infraestrutura->nome,
'centros_custo' => $infraestrutura->centrosCusto()
->where('id', '<>', $centroCustoDestinoId)
->whereHas('almoxarifadoRequisicaoPermissoesRequisitante', function ($query) use ($centroCustoLogadoId) {
$query->where('created_centro_custo_id', $centroCustoLogadoId);
})
->get()
->map(fn ($centroCusto) => [
'id' => $centroCusto->id,
'setor_nome' => $centroCusto->setor->nome,
])
->sortBy('setor_nome')
->values()
])
->values()
]),
'unidade_id' => null,
'infraestrutura_id' => null,
],
'model' => [
'centro_custo_origem_id' => null,
],
];
}
public static function storeImportacao()
{
self::validateImportacao();
DB::transaction(function () {
RequisicaoPermissao::where('created_centro_custo_id', self::getCurrentCentroCusto()->id)
->where('centro_custo_requisitante_id', request()->centro_custo_destino_id)
->delete();
RequisicaoPermissao::where('created_centro_custo_id', self::getCurrentCentroCusto()->id)
->where('centro_custo_requisitante_id', request()->centro_custo_origem_id)
->get()
->each(function ($permissao) {
if ($permissao->material->is_ativo) {
RequisicaoPermissao::create([
'centro_custo_requisitante_id' => request()->centro_custo_destino_id,
'material_id' => $permissao->material_id,
'estoque_maximo' => request()->importar_estoque_maximo ? $permissao->estoque_maximo : null,
]);
}
});
});
}
private static function validateImportacao()
{
$rules = [
'centro_custo_origem_id' => [
'required',
'integer',
Rule::exists(CentroCusto::class, 'id'),
],
'centro_custo_destino_id' => [
'required',
'integer',
Rule::exists(CentroCusto::class, 'id'),
],
'importar_estoque_maximo' => [
'required',
'boolean',
]
];
$messages = [];
request()->validate($rules, $messages);
}
public static function edit($id)
{
$requisicao = Requisicao::findOrFail($id);
$ultimoEnvio = $requisicao->respostas()
->whereNotNull('enviada_em')
->orderByDesc('id')
->first();
$respostaIniciada = $requisicao->respostas()
->where('status_id', RequisicaoRespostaStatus::INICIADA)
->first();
$itens = $requisicao->itens()->withAggregate('material', 'descricao')
->when(request()->has('sort') && request()->sort !== 'null', function ($query) {
return $query->orderBy('material_descricao', request()->sort);
})
->get();
if ($ultimoEnvio) {
$itens = $itens->filter(function ($item) use ($ultimoEnvio) {
$ultimoEnvioItem = $ultimoEnvio->itens()->where('requisicao_item_id', $item->id)->first();
return !is_null($ultimoEnvioItem) && collect([
RequisicaoRespostaItemMotivoEnum::ENTREGA_PARCIAL,
RequisicaoRespostaItemMotivoEnum::PENDENTE_DE_ENTREGA,
])->contains($ultimoEnvioItem->motivo_id);
});
}
return [
'form' => self::getFormData($requisicao),
'model' => [
'itens' => $itens->map(function ($item) use ($respostaIniciada) {
$respostaItemIniciada = $respostaIniciada
? $respostaIniciada->itens()->where('requisicao_item_id', $item->id)->first()
: null;
$estoque = AlmoxarifadoService::getEstoque(
$item->material->id,
null,
$respostaItemIniciada->reserva_item_id ?? null
);
$estoqueTotal = $estoque['total'];
$reservas = AlmoxarifadoService::getReservas($item->material->id)['agrupadas'];
$estoqueTotalRequisitante = AlmoxarifadoService::getEstoque(
$item->material->id,
$item->requisicao->created_centro_custo_id
)['total'];
$respostaItemEnviadas = $item->respostaItens()
->whereHas('requisicaoResposta', function ($query) {
$query->whereNotNull('enviada_em');
})
->get();
$entregue = $respostaItemEnviadas ? $respostaItemEnviadas
->map(fn ($respostaItemEnviada) => $respostaItemEnviada->saidaItem->quantidade ?? 0)
->sum() : 0;
$restanteRequisitado = $item->quantidade - $entregue;
$concedido = 0;
$escolheuEntradaItemManualmente = false;
$entradaItens = [];
$motivoId = null;
if ($respostaItemIniciada) {
$entradaItensReservados = [];
if ($respostaItemIniciada->reservaItem) {
$concedido = $respostaItemIniciada->reservaItem->quantidade;
$escolheuEntradaItemManualmente = $respostaItemIniciada->reservaItem
->escolheu_entrada_item_manualmente;
$entradaItensReservados = $respostaItemIniciada->reservaItem->entradaItens
->map(fn ($entradaItem) => [
'entrada_item_id' => $entradaItem->id,
'quantidade_saida' => $entradaItem->pivotReservaItemEntradaItem->quantidade_saida,
]);
}
$entradaItens = collect($estoque['por_entrada'])
->map(function ($entradaItem) use ($entradaItensReservados) {
$entradaItem['quantidade_saida'] = collect($entradaItensReservados)
->where('entrada_item_id', $entradaItem['entrada_item_id'])
->first()['quantidade_saida'] ?? 0;
return $entradaItem;
});
$motivoId = $respostaItemIniciada->motivo_id;
}
else {
$quantidade = $respostaItemEnviadas->isEmpty() ? $item->quantidade : $restanteRequisitado;
$concedido = $quantidade > $estoqueTotal ? $estoqueTotal : $quantidade;
$entradaItensData = AlmoxarifadoService::getEntradaItensData(
$item->material->id,
[
'escolheu_entrada_item_manualmente' => false,
'quantidade' => $concedido,
]
);
$entradaItensAutomaticos = [];
foreach ($entradaItensData as $entradaItemId => $entradaItemData) {
$entradaItensAutomaticos[] = [
'entrada_item_id' => $entradaItemId,
'quantidade_saida' => $entradaItemData['quantidade_saida'],
];
}
$entradaItens = collect($estoque['por_entrada'])
->map(function ($entradaItem) use ($entradaItensAutomaticos) {
$entradaItem['quantidade_saida'] = collect($entradaItensAutomaticos)
->where('entrada_item_id', $entradaItem['entrada_item_id'])
->first()['quantidade_saida'] ?? 0;
return $entradaItem;
});
$motivoId = $estoqueTotal === 0 ? RequisicaoRespostaItemMotivoEnum::SEM_ESTOQUE : null;
}
$possuiEntradaComLote = !is_null(collect($entradaItens)->whereNotNull('lote')->first());
$data = [
'requisicao_item_id' => $item->id,
'unidade_requisitante' => [
'id' => $item->requisicao->createdCentroCusto->infraestrutura->unidade->id,
'nome_fantasia' => $item->requisicao->createdCentroCusto->infraestrutura->unidade->nome_fantasia
],
'material' => [
'id' => $item->material->id,
'codigo' => $item->material->codigo_material,
'descricao_completa' => $item->material->descricao_completa,
],
'possui_entrada_com_lote' => $possuiEntradaComLote,
'estoque_disponivel' => $estoqueTotal,
'reservas' => $reservas,
'estoque_requisitante' => $estoqueTotalRequisitante,
'concedido' => $concedido,
'escolheu_entrada_item_manualmente' => $escolheuEntradaItemManualmente,
'entrada_itens' => $entradaItens,
'motivo_id' => $motivoId,
'motivo_outro' => $respostaItemIniciada->motivo_outro ?? null,
];
if ($respostaItemEnviadas->isEmpty()) {
$data['requisitado'] = $item->quantidade;
}
else {
$data['entregue'] = $entregue;
$data['restante_requisitado'] = $restanteRequisitado;
}
return $data;
})->values(),
'observacoes' => $respostaIniciada->observacoes ?? null,
]
];
}
private static function getFormData($requisicao)
{
$parametrizacao = ParametrizacaoRequisicao::first();
return [
'data_requisicao' => (new Carbon($requisicao->created_at))->format('d/m/Y'),
'numero' => $requisicao->numero,
'requisitante' => [
'unidade_nome_fantasia' => $requisicao->createdCentroCusto->infraestrutura->unidade->nome_fantasia,
'infraestrutura_nome' => $requisicao->createdCentroCusto->infraestrutura->nome,
'setor_nome' => $requisicao->createdCentroCusto->setor->nome,
'usuario_nome' => $requisicao->createdLotacao->usuario->cidadao->nome,
],
'envios' => self::getEnvios($requisicao),
'motivos' => RequisicaoRespostaItemMotivo::orderBy('nome')->get(['id', 'nome']),
'motivo_obrigatorio' => $parametrizacao->motivo_obrigatorio ?? false
];
}
private static function getEnvios($requisicao)
{
$envios = $requisicao->respostas()
->whereNotNull('enviada_em')
->orderBy('enviada_em')
->get();
$entregue = [];
$envios = $envios->map(function ($resposta, $i) use (&$entregue) {
$numeroEnvio = $i + 1;
$itens = $resposta->itens->map(function ($respostaItem) use ($numeroEnvio, &$entregue) {
$material = $respostaItem->requisicaoItem->material;
if (!isset($entregue[$material->id])) {
$entregue[$material->id] = 0;
}
$item = [
'material' => [
'codigo' => $material->codigo_material,
'descricao_completa' => $material->descricao_completa,
],
'motivo_nome' => $respostaItem->motivo->nome ?? null,
'motivo_outro' => $respostaItem->motivo_outro,
];
if ($numeroEnvio === 1) {
$item['requisitado'] = $respostaItem->requisicaoItem->quantidade;
}
else {
$item['entregue'] = $entregue[$material->id];
$item['restante_requisitado'] = $respostaItem->requisicaoItem->quantidade - $entregue[$material->id];
}
$item['possui_entrada_com_lote'] = is_null($respostaItem->saidaItem) ? false
: $respostaItem->saidaItem->entradaItens()->whereNotNull('lote')->exists();
if ($item['possui_entrada_com_lote']) {
$item['entrada_itens'] = $respostaItem->saidaItem
? $respostaItem->saidaItem->entradaItens->map(fn ($entradaItem) => [
'concedido' => $entradaItem->pivotSaidaItemEntradaItem->quantidade_saida,
'lote' => $entradaItem->lote,
'validade_lote' => $entradaItem->validade_lote
? $entradaItem->validade_lote->format('d/m/Y')
: null,
]) : [];
$entregue[$material->id] += collect($item['entrada_itens'])->sum('concedido');
}
else {
$item['concedido'] = $respostaItem->saidaItem ? $respostaItem->saidaItem->quantidade : 0;
$entregue[$material->id] += $item['concedido'];
}
return $item;
});
return [
'numero_envio' => $numeroEnvio,
'data_hora' => $resposta->enviada_em->format('d/m/Y H:i'),
'usuario' => $resposta->enviadaLotacao->usuario->cidadao->nome ?? null,
'itens' => $itens,
'observacoes' => $resposta->observacoes,
];
});
return collect($envios)->sortByDesc('numero_envio')->values();
}
public static function update($id)
{
self::validate();
$requisicao = Requisicao::findOrFail($id);
DB::transaction(function () use ($requisicao) {
$resposta = $requisicao->respostas()->updateOrCreate(
['status_id' => RequisicaoRespostaStatus::INICIADA],
['observacoes' => request()->observacoes]
);
$reservaAnteriorId = $resposta->reserva_id;
$resposta->update(['reserva_id' => null]);
$resposta->itens->each(fn ($i) => $i->update(['reserva_item_id' => null]));
$itens = request()->itens;
foreach ($itens as &$item) {
$requisicaoItem = RequisicaoItem::findOrFail($item['requisicao_item_id']);
$item['material_id'] = $requisicaoItem->material_id;
}
unset($item);
$itensComQuantidadeConcedida = collect($itens)
->filter(fn ($i) => $i['concedido'] > 0)
->map(fn ($item) => [
'material_id' => $item['material_id'],
'quantidade' => $item['concedido'],
'escolheu_entrada_item_manualmente' => $item['escolheu_entrada_item_manualmente'],
'entrada_itens' => $item['entrada_itens'],
]);
if (request()->enviar_resposta) {
$saida = AlmoxarifadoService::saveSaidaDeRequisicao(
$itensComQuantidadeConcedida,
$reservaAnteriorId
);
$resposta->update([
'saida_id' => $saida->id ?? null,
'status_id' => RequisicaoRespostaStatus::ENVIADA,
'enviada_em' => Carbon::now(),
'enviada_lotacao_id' => self::getCurrentLotacao()->id,
]);
foreach ($itens as $item) {
$saidaItemId = null;
if ($saida) {
$saidaItemId = $saida->itens()
->where('material_id', $item['material_id'])
->first()->id ?? null;
}
$resposta->itens()->updateOrCreate(
['requisicao_item_id' => $item['requisicao_item_id']],
array_merge(self::getItemData($item), [
'saida_item_id' => $saidaItemId,
])
);
}
}
else {
$reserva = AlmoxarifadoService::saveReservaDeRequisicao(
$itensComQuantidadeConcedida,
$reservaAnteriorId
);
if ($reserva) {
$resposta->update(['reserva_id' => $reserva->id]);
}
foreach ($itens as $item) {
$reservaItemId = null;
if ($reserva) {
$reservaItemId = $reserva->itens()
->where('material_id', $item['material_id'])
->first()->id ?? null;
}
$resposta->itens()->updateOrCreate(
['requisicao_item_id' => $item['requisicao_item_id']],
array_merge(self::getItemData($item), [
'reserva_item_id' => $reservaItemId,
])
);
}
}
if ($requisicao->status_id !== RequisicaoStatus::RESPOSTA_INICIADA) {
$requisicao->update(['status_id' => RequisicaoStatus::RESPOSTA_INICIADA]);
}
});
return $requisicao->fresh();
}
private static function getItemData($item)
{
return [
'motivo_id' => $item['motivo_id'],
'motivo_outro' => $item['motivo_id'] === RequisicaoRespostaItemMotivoEnum::OUTRO
? $item['motivo_outro'] : null,
];
}
public static function validate()
{
$rules = [
'enviar_resposta' => [
'required',
'boolean',
],
'observacoes' => [
'nullable',
'string',
'max:1000',
],
'itens' => [
'required',
'array',
],
'itens.*.requisicao_item_id' => [
'required',
'integer',
Rule::exists(RequisicaoItem::class, 'id'),
],
'itens.*.concedido' => [
'required',
'integer',
],
'itens.*.escolheu_entrada_item_manualmente' => [
'required',
'boolean',
],
'itens.*.entrada_itens' => [
'present',
'array',
],
'itens.*.entrada_itens.*.entrada_item_id' => [
'required',
'integer',
Rule::exists(EntradaItem::class, 'id'),
],
'itens.*.entrada_itens.*.quantidade_saida' => [
'required',
'integer',
'min:1',
],
'itens.*.motivo_id' => [
'nullable',
'integer',
Rule::exists(RequisicaoRespostaItemMotivo::class, 'id'),
],
'itens.*.motivo_outro' => [
'nullable',
'string',
'max:300',
],
];
$messages = [];
request()->validate($rules, $messages);
}
}

View File

@@ -0,0 +1,367 @@
<?php
namespace App\Services\Almoxarifado;
use App\Enums\Almoxarifado\SaidaTipo;
use App\Models\Almoxarifado\EntradaItem;
use App\Models\Almoxarifado\Saida;
use App\Models\Almoxarifado\SaidaItem;
use App\Models\Almoxarifado\SaidaRequisicao;
use App\Models\Cadastro\Estabelecimento\CentroCusto;
use App\Models\Cadastro\Estabelecimento\Unidade;
use App\Models\Cadastro\Material\Material;
use App\Models\Cadastro\SujeitoAtencao\Usuario;
use App\Models\Almoxarifado\BalanceteFechamento;
use App\Services\Service;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
class SaidaService extends Service
{
public static function datatable()
{
$saidas = DB::table('almoxarifado_saida')
->join(
'almoxarifado_saida_requisicao',
'almoxarifado_saida_requisicao.saida_id',
'almoxarifado_saida.id'
)
->join(
'cadastro_centro_custo',
'cadastro_centro_custo.id',
'almoxarifado_saida_requisicao.centro_custo_id'
)
->join(
'cadastro_setor',
'cadastro_setor.id',
'cadastro_centro_custo.setor_id'
)
->join(
'cadastro_infraestrutura',
'cadastro_infraestrutura.id',
'cadastro_centro_custo.infraestrutura_id'
)
->join(
'cadastro_unidade',
'cadastro_unidade.id',
'cadastro_infraestrutura.unidade_id'
)
->join(
'cadastro_usuario',
'cadastro_usuario.id',
'almoxarifado_saida_requisicao.usuario_id'
)
->join(
'cadastro_cidadao',
'cadastro_cidadao.id',
'cadastro_usuario.cidadao_id'
)
->select(
'almoxarifado_saida.id',
DB::raw("DATE_FORMAT(almoxarifado_saida_requisicao.data, '%d/%m/%Y') as data_requisicao"),
DB::raw("cadastro_unidade.nome_fantasia AS unidade_nome_fantasia"),
DB::raw("COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) AS infraestrutura_nome"),
'cadastro_setor.nome as setor_nome',
'cadastro_cidadao.nome AS usuario_nome',
'almoxarifado_saida_requisicao.numero',
DB::raw("DATE_FORMAT(almoxarifado_saida.created_at, '%d/%m/%Y') as data_saida"),
'almoxarifado_saida.finalizada',
)
->where('almoxarifado_saida.tipo_id', SaidaTipo::MANUAL)
->where('almoxarifado_saida.centro_custo_id', self::getCurrentCentroCusto()->id);
return datatables()
->of($saidas)
->filterColumn('almoxarifado_saida_requisicao.data', function ($query, $keyword) {
$query->whereRaw("DATE_FORMAT(almoxarifado_saida_requisicao.data, '%d/%m/%Y') like ?", ["%{$keyword}%"])
->orWhereRaw(
"CONCAT(
SUBSTR(almoxarifado_saida_requisicao.data,9,2),
SUBSTR(almoxarifado_saida_requisicao.data,6,2),
SUBSTR(almoxarifado_saida_requisicao.data,1,4)
) like ?",
["%{$keyword}%"]
);
})
->filterColumn('almoxarifado_saida.created_at', function ($query, $keyword) {
$query->whereRaw("DATE_FORMAT(almoxarifado_saida.created_at, '%d/%m/%Y') like ?", ["%{$keyword}%"])
->orWhereRaw(
"CONCAT(
SUBSTR(almoxarifado_saida.created_at,9,2),
SUBSTR(almoxarifado_saida.created_at,6,2),
SUBSTR(almoxarifado_saida.created_at,1,4)
) like ?",
["%{$keyword}%"]
);
})
->filterColumn('cadastro_infraestrutura.nome', function ($query, $keyword) {
$query->whereRaw("COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) like ?", ["%{$keyword}%"]);
})
->skipTotalRecords()
->toJson();
}
public static function create()
{
return [
'additionals' => self::getAdditionalsData(),
'form' => self::getFormData(),
'model' => [
'finalizada' => false,
'requisicao' => [
'centro_custo_id' => null,
'usuario' => null,
'numero' => ParametrizacaoService::getParametrizacaoRequisicao()['numero_requisicao_automatico']
? ParametrizacaoService::getNovoNumeroRequisicao() : null,
'data' => null,
],
'itens' => [],
]
];
}
public static function store()
{
self::validate();
$saida = null;
DB::transaction(function () use (&$saida) {
$saida = AlmoxarifadoService::saveSaidaManual(self::getParams());
});
return $saida;
}
public static function edit($id)
{
$saida = Saida::findOrFail($id);
return [
'additionals' => self::getAdditionalsData(),
'form' => self::getFormData($saida),
'model' => [
'finalizada' => $saida->finalizada,
'requisicao' => [
'centro_custo_id' => $saida->requisicao->centroCusto->id,
'usuario' => [
'id' => $saida->requisicao->usuario->id,
'cidadao_nome' => $saida->requisicao->usuario->cidadao->nome,
],
'numero' => $saida->requisicao->numero,
'data' => $saida->requisicao->data->format('d/m/Y'),
],
'itens' => $saida->itens->map(fn ($item) => [
'id' => $item->id,
'material' => [
'id' => $item->material->id,
'codigo_material' => $item->material->codigo_material,
'descricao_completa' => $item->material->descricao_completa,
],
'quantidade' => $item->quantidade,
'estorno_salvo' => $item->estornado,
'estornado' => $item->estornado,
'entrada_itens' => $item->entradaItens->map(fn ($entradaItem) => [
'entrada_item_id' => $entradaItem->id,
'quantidade_saida' => $entradaItem->pivotSaidaItemEntradaItem->quantidade_saida,
'lote' => $entradaItem->lote,
'validade_lote' => $entradaItem->validade_lote,
]),
'escolheu_entrada_item_manualmente' => $item->escolheu_entrada_item_manualmente,
])
]
];
}
private static function getFormData($saida = null)
{
$centroCustoLogadoId = self::getCurrentCentroCusto()->id;
return [
'requisicao' => [
'unidades' => Unidade::orderBy('nome_fantasia')
->whereHas('infraestruturas', function ($query) use ($centroCustoLogadoId) {
$query->whereHas('centrosCusto', function ($query) use ($centroCustoLogadoId) {
$query->where('id', '<>', $centroCustoLogadoId)
->whereDoesntHave('almoxarifadoParametrizacoesControleEstoqueGrupo');
});
})
->get()
->map(fn ($unidade) => [
'id' => $unidade->id,
'nome_fantasia' => $unidade->nome_fantasia,
'infraestruturas' => $unidade->infraestruturas()
->whereHas('centrosCusto', function ($query) use ($centroCustoLogadoId) {
$query->where('id', '<>', $centroCustoLogadoId)
->whereDoesntHave('almoxarifadoParametrizacoesControleEstoqueGrupo');
})
->get()
->sortBy('nome')
->map(fn ($infraestrutura) => [
'id' => $infraestrutura->id,
'nome' => $infraestrutura->nome,
'centros_custo' => $infraestrutura->centrosCusto()
->where('id', '<>', $centroCustoLogadoId)
->whereDoesntHave('almoxarifadoParametrizacoesControleEstoqueGrupo')
->get()
->map(fn ($centroCusto) => [
'id' => $centroCusto->id,
'setor_nome' => $centroCusto->setor->nome,
])
->sortBy('setor_nome')
->values()
])
->values()
]),
'unidade_id' => $saida ? $saida->requisicao->centroCusto->infraestrutura->unidade_id : null,
'infraestrutura_id' => $saida ? $saida->requisicao->centroCusto->infraestrutura->id : null,
'balancete_lastest' => BalanceteFechamento::select('id','mes','ano')->orderBy('id','desc')->first() ?? null,
]
];
}
private static function getAdditionalsData()
{
return [
'data_atual' => Carbon::now()->format('d/m/Y'),
'is_numero_requisicao_automatico' => ParametrizacaoService::getParametrizacaoRequisicao()
['numero_requisicao_automatico'],
];
}
public static function update($id)
{
self::validate();
$saida = Saida::findOrFail($id);
DB::transaction(function () use (&$saida) {
$saida = AlmoxarifadoService::saveSaidaManual(self::getParams(), $saida->id);
});
return $saida;
}
private static function getParams()
{
return [
'finalizada' => request()->finalizada,
'requisicao' => [
'centro_custo_id' => request()->requisicao['centro_custo_id'],
'usuario_id' => request()->requisicao['usuario_id'],
'numero' => request()->requisicao['numero'],
'data' => Carbon::createFromFormat('d/m/Y', request()->requisicao['data']),
],
'itens' => collect(request()->itens)->map(fn ($item) => [
'id' => $item['id'],
'material_id' => $item['material_id'],
'quantidade' => (int) $item['quantidade'],
'estornado' => $item['estornado'],
'entrada_itens' => collect($item['entrada_itens'])->map(fn ($entradaItem) => [
'entrada_item_id' => $entradaItem['entrada_item_id'],
'quantidade_saida' => (int) $entradaItem['quantidade_saida'],
]),
'escolheu_entrada_item_manualmente' => $item['escolheu_entrada_item_manualmente'],
])
];
}
public static function validate()
{
$rules = [
'finalizada' => [
'required',
'boolean',
],
'requisicao.centro_custo_id' => [
'required',
'integer',
Rule::exists(CentroCusto::class, 'id'),
],
'requisicao.usuario_id' => [
'required',
'integer',
Rule::exists(Usuario::class, 'id'),
],
'requisicao.numero' => [
'required',
'digits_between:1,20',
Rule::unique(SaidaRequisicao::class, 'numero')->ignore(request()->route('saida'), 'saida_id'),
],
'requisicao.data' => [
'required',
'date_format:d/m/Y',
'before_or_equal:now',
],
'itens' => [
'required',
'array',
],
'itens.*.id' => [
'nullable',
'integer',
Rule::exists(SaidaItem::class, 'id'),
],
'itens.*.material_id' => [
'required',
'integer',
Rule::exists(Material::class, 'id'),
],
'itens.*.quantidade' => [
'required',
'integer',
'min:1',
],
'itens.*.escolheu_entrada_item_manualmente' => [
'required',
'boolean',
],
'itens.*.estornado' => [
'required',
'boolean',
],
'itens.*.entrada_itens' => [
'present',
'array',
],
'itens.*.entrada_itens.*.entrada_item_id' => [
'required',
'integer',
Rule::exists(EntradaItem::class, 'id'),
],
'itens.*.entrada_itens.*.quantidade_saida' => [
'required',
'integer',
'min:1',
],
];
$messages = [
'requisicao.numero.unique' => 'O número da requisição já foi inserido anteriormente.',
];
request()->validate($rules, $messages);
}
public static function destroy($id)
{
$saida = Saida::findOrFail($id);
DB::transaction(function () use ($saida) {
$saida->itens->each(fn ($i) => $i->entradaItens()->detach());
$saida->delete();
});
return null;
}
}

View File

@@ -0,0 +1,472 @@
<?php
namespace App\Services\Almoxarifado;
use App\Enums\Almoxarifado\SaidaTipo;
use App\Exceptions\Almoxarifado\TransferenciaRespondidaPeloDestinoException;
use App\Models\Almoxarifado\EntradaItem;
use App\Models\Almoxarifado\Saida;
use App\Models\Almoxarifado\SaidaItem;
use App\Models\Almoxarifado\BalanceteFechamento;
use App\Models\Cadastro\Estabelecimento\CentroCusto;
use App\Models\Cadastro\Estabelecimento\Unidade;
use App\Models\Cadastro\Material\Material;
use App\Models\Cadastro\SujeitoAtencao\Usuario;
use App\Services\Service;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
class TransferenciaService extends Service
{
public static function datatableEnviadas()
{
$saidas = DB::table('almoxarifado_saida')
->join(
'almoxarifado_saida_transferencia',
'almoxarifado_saida_transferencia.saida_id',
'almoxarifado_saida.id'
)
->join(
'cadastro_centro_custo',
'cadastro_centro_custo.id',
'almoxarifado_saida_transferencia.centro_custo_id'
)
->join(
'cadastro_setor',
'cadastro_setor.id',
'cadastro_centro_custo.setor_id'
)
->join(
'cadastro_infraestrutura',
'cadastro_infraestrutura.id',
'cadastro_centro_custo.infraestrutura_id'
)
->join(
'cadastro_unidade',
'cadastro_unidade.id',
'cadastro_infraestrutura.unidade_id'
)
->join(
'cadastro_usuario',
'cadastro_usuario.id',
'almoxarifado_saida_transferencia.usuario_id'
)
->join(
'cadastro_cidadao',
'cadastro_cidadao.id',
'cadastro_usuario.cidadao_id'
)
->select(
'almoxarifado_saida.id',
DB::raw("cadastro_unidade.nome_fantasia AS unidade_nome_fantasia"),
DB::raw("COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) AS infraestrutura_nome"),
'cadastro_setor.nome as setor_nome',
'cadastro_cidadao.nome AS usuario_nome',
DB::raw("DATE_FORMAT(almoxarifado_saida.created_at, '%d/%m/%Y') as data_transferencia"),
'almoxarifado_saida.finalizada',
'almoxarifado_saida_transferencia.confirmado',
'almoxarifado_saida_transferencia.recusado'
)
->where('almoxarifado_saida.tipo_id', SaidaTipo::TRANSFERENCIA)
->where('almoxarifado_saida.centro_custo_id', self::getCurrentCentroCusto()->id);
return datatables()
->of($saidas)
->filterColumn('almoxarifado_saida.created_at', function ($query, $keyword) {
$query->whereRaw("DATE_FORMAT(almoxarifado_saida.created_at, '%d/%m/%Y') like ?", ["%{$keyword}%"])
->orWhereRaw(
"CONCAT(
SUBSTR(almoxarifado_saida.created_at,9,2),
SUBSTR(almoxarifado_saida.created_at,6,2),
SUBSTR(almoxarifado_saida.created_at,1,4)
) like ?",
["%{$keyword}%"]
);
})
->filterColumn('cadastro_infraestrutura.nome', function ($query, $keyword) {
$query->whereRaw("COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) like ?", ["%{$keyword}%"]);
})
->filterColumn('almoxarifado_saida.finalizada', function ($query, $keyword) {
$query->whereRaw("IF(almoxarifado_saida.finalizada = 1, 'SIM', 'NÃO') = ?", [Str::upper($keyword)]);
})
->skipTotalRecords()
->toJson();
}
public static function datatableRecebidas()
{
$saidas = DB::table('almoxarifado_saida')
->join(
'almoxarifado_saida_transferencia',
'almoxarifado_saida_transferencia.saida_id',
'almoxarifado_saida.id'
)
->join(
'cadastro_centro_custo',
'cadastro_centro_custo.id',
'almoxarifado_saida.centro_custo_id'
)
->join(
'cadastro_setor',
'cadastro_setor.id',
'cadastro_centro_custo.setor_id'
)
->join(
'cadastro_infraestrutura',
'cadastro_infraestrutura.id',
'cadastro_centro_custo.infraestrutura_id'
)
->join(
'cadastro_unidade',
'cadastro_unidade.id',
'cadastro_infraestrutura.unidade_id'
)
->join(
'cadastro_usuario',
'cadastro_usuario.id',
'almoxarifado_saida_transferencia.usuario_id'
)
->join(
'cadastro_cidadao',
'cadastro_cidadao.id',
'cadastro_usuario.cidadao_id'
)
->select(
'almoxarifado_saida.id',
DB::raw("cadastro_unidade.nome_fantasia AS unidade_nome_fantasia"),
DB::raw("COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) AS infraestrutura_nome"),
'cadastro_setor.nome as setor_nome',
'cadastro_cidadao.nome AS usuario_nome',
DB::raw("DATE_FORMAT(almoxarifado_saida.created_at, '%d/%m/%Y') as data_transferencia"),
'almoxarifado_saida_transferencia.confirmado',
'almoxarifado_saida_transferencia.recusado'
)
->where('almoxarifado_saida.tipo_id', SaidaTipo::TRANSFERENCIA)
->where('almoxarifado_saida.finalizada', true)
->where('almoxarifado_saida_transferencia.centro_custo_id', self::getCurrentCentroCusto()->id);
return datatables()
->of($saidas)
->filterColumn('almoxarifado_saida.created_at', function ($query, $keyword) {
$query->whereRaw("DATE_FORMAT(almoxarifado_saida.created_at, '%d/%m/%Y') like ?", ["%{$keyword}%"])
->orWhereRaw(
"CONCAT(
SUBSTR(almoxarifado_saida.created_at,9,2),
SUBSTR(almoxarifado_saida.created_at,6,2),
SUBSTR(almoxarifado_saida.created_at,1,4)
) like ?",
["%{$keyword}%"]
);
})
->filterColumn('cadastro_infraestrutura.nome', function ($query, $keyword) {
$query->whereRaw("COALESCE(cadastro_infraestrutura.nome, cadastro_unidade.nome_fantasia) like ?", ["%{$keyword}%"]);
})
->skipTotalRecords()
->toJson();
}
public static function create()
{
return [
'form' => self::getFormData(),
'model' => [
'finalizada' => false,
'confirmado' => false,
'recusado' => false,
'destino' => [
'centro_custo_id' => null,
'usuario' => null,
],
'itens' => [],
'ultimo_balancete_fechado' => [BalanceteFechamento::Latest()
->select('mes', 'ano')
->first() ?? null, Carbon::now()]
]
];
}
public static function store()
{
self::validate();
$saida = null;
DB::transaction(function () use (&$saida) {
$saida = AlmoxarifadoService::saveTransferencia(self::getParams());
});
return $saida;
}
public static function edit($id)
{
$saida = Saida::findOrFail($id);
return [
'form' => self::getFormData($saida),
'model' => [
'finalizada' => $saida->finalizada,
'confirmado' => $saida->transferencia->confirmado,
'recusado' => $saida->transferencia->recusado,
'destino' => [
'centro_custo_id' => $saida->transferencia->centroCusto->id,
'usuario' => [
'id' => $saida->transferencia->usuario->id,
'cidadao_nome' => $saida->transferencia->usuario->cidadao->nome,
],
],
'itens' => $saida->itens->map(fn ($item) => [
'id' => $item->id,
'material' => [
'id' => $item->material->id,
'codigo_material' => $item->material->codigo_material,
'descricao_completa' => $item->material->descricao_completa,
],
'quantidade' => $item->quantidade,
'estorno_salvo' => $item->estornado,
'estornado' => $item->estornado,
'entrada_itens' => $item->entradaItens->map(fn ($entradaItem) => [
'entrada_item_id' => $entradaItem->id,
'quantidade_saida' => $entradaItem->pivotSaidaItemEntradaItem->quantidade_saida,
'lote' => $entradaItem->lote,
'validade_lote' => $entradaItem->validade_lote,
]),
'escolheu_entrada_item_manualmente' => $item->escolheu_entrada_item_manualmente,
]),
'ultimo_balancete_fechado' => [BalanceteFechamento::Latest()
->select('mes', 'ano')
->first() ?? null, Carbon::now()]
]
];
}
private static function getFormData($saida = null)
{
$centroCustoLogadoId = self::getCurrentCentroCusto()->id;
return [
'destino' => [
'unidades' => Unidade::orderBy('nome_fantasia')
->whereHas('infraestruturas', function ($query) use ($centroCustoLogadoId) {
$query->whereHas('centrosCusto', function ($query) use ($centroCustoLogadoId) {
$query->where('id', '<>', $centroCustoLogadoId);
});
})
->get()
->map(fn ($unidade) => [
'id' => $unidade->id,
'nome_fantasia' => $unidade->nome_fantasia,
'infraestruturas' => $unidade->infraestruturas()
->whereHas('centrosCusto', function ($query) use ($centroCustoLogadoId) {
$query->where('id', '<>', $centroCustoLogadoId);
})
->get()
->sortBy('nome')
->map(fn ($infraestrutura) => [
'id' => $infraestrutura->id,
'nome' => $infraestrutura->nome,
'centros_custo' => $infraestrutura->centrosCusto()
->where('id', '<>', $centroCustoLogadoId)
->get()
->map(fn ($centroCusto) => [
'id' => $centroCusto->id,
'setor_nome' => $centroCusto->setor->nome,
])
->sortBy('setor_nome')
->values()
])
->values()
]),
'unidade_id' => $saida ? $saida->transferencia->centroCusto->infraestrutura->unidade_id : null,
'infraestrutura_id' => $saida ? $saida->transferencia->centroCusto->infraestrutura->id : null,
]
];
}
public static function update($id)
{
self::validate();
$saida = Saida::findOrFail($id);
if ($saida->transferencia->confirmado || $saida->transferencia->recusado) {
throw new TransferenciaRespondidaPeloDestinoException();
}
DB::transaction(function () use (&$saida) {
$saida = AlmoxarifadoService::saveTransferencia(self::getParams(), $saida->id);
});
return $saida;
}
private static function getParams()
{
return [
'finalizada' => request()->finalizada,
'destino' => [
'centro_custo_id' => request()->destino['centro_custo_id'],
'usuario_id' => request()->destino['usuario_id'],
],
'itens' => collect(request()->itens)->map(fn ($item) => [
'id' => $item['id'],
'material_id' => $item['material_id'],
'quantidade' => (int) $item['quantidade'],
'estornado' => $item['estornado'],
'entrada_itens' => collect($item['entrada_itens'])->map(fn ($entradaItem) => [
'entrada_item_id' => $entradaItem['entrada_item_id'],
'quantidade_saida' => (int) $entradaItem['quantidade_saida'],
]),
'escolheu_entrada_item_manualmente' => $item['escolheu_entrada_item_manualmente'],
])
];
}
public static function validate()
{
$rules = [
'finalizada' => [
'required',
'boolean',
],
'destino.centro_custo_id' => [
'required',
'integer',
Rule::exists(CentroCusto::class, 'id'),
],
'destino.usuario_id' => [
'required',
'integer',
Rule::exists(Usuario::class, 'id'),
],
'itens' => [
'required',
'array',
],
'itens.*.id' => [
'nullable',
'integer',
Rule::exists(SaidaItem::class, 'id'),
],
'itens.*.material_id' => [
'required',
'integer',
Rule::exists(Material::class, 'id'),
],
'itens.*.quantidade' => [
'required',
'integer',
'min:1',
],
'itens.*.escolheu_entrada_item_manualmente' => [
'required',
'boolean',
],
'itens.*.estornado' => [
'required',
'boolean',
],
'itens.*.entrada_itens' => [
'present',
'array',
],
'itens.*.entrada_itens.*.entrada_item_id' => [
'required',
'integer',
Rule::exists(EntradaItem::class, 'id'),
],
'itens.*.entrada_itens.*.quantidade_saida' => [
'required',
'integer',
'min:1',
],
];
$messages = [];
request()->validate($rules, $messages);
}
public static function destroy($id)
{
$saida = Saida::findOrFail($id);
DB::transaction(function () use ($saida) {
$saida->itens->each(fn ($i) => $i->entradaItens()->detach());
$saida->delete();
});
return null;
}
public static function getTransferenciaRecebida($id)
{
$saida = Saida::findOrFail($id);
return [
'origem' => [
'unidade_nome_fantasia' => $saida->centroCusto->infraestrutura->unidade->nome_fantasia,
'infraestrutura_nome' => $saida->centroCusto->infraestrutura->nome,
'setor_nome' => $saida->centroCusto->setor->nome,
],
'itens' => $saida->transferencia->recusado
? $saida->itensRecusadosTransferencia->map(fn ($item) => [
'material_descricao' => $item->saidaItem->material->descricao_completa,
'quantidade' => $item->saidaItem->quantidade,
])
: $saida->itens->filter(fn ($i) => !$i->estornado)->map(fn ($item) => [
'material_descricao' => $item->material->descricao_completa,
'quantidade' => $item->quantidade,
])->values()
];
}
public static function accept($id)
{
$saida = Saida::findOrFail($id);
DB::transaction(function () use ($saida) {
AlmoxarifadoService::saveEntradasDeTransferencia($saida);
$saida->transferencia->confirmado = true;
$saida->transferencia->save();
});
}
public static function reject($id)
{
$saida = Saida::findOrFail($id);
DB::transaction(function () use ($saida) {
$itensNaoEstornados = collect();
$saida->itens->filter(fn ($i) => !$i->estornado)->each(function ($item) use ($saida, $itensNaoEstornados) {
$saida->itensRecusadosTransferencia()->create(['saida_item_id' => $item->id]);
$itensNaoEstornados->push(['id' => $item->id]);
});
AlmoxarifadoService::saveEstornoDeTransferencia($itensNaoEstornados);
$saida->transferencia->recusado = true;
$saida->transferencia->save();
});
}
}