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

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();
}
}