Files
Antonio Lopes dos Santos afec302c3e
All checks were successful
build-api-image / build (push) Successful in 51s
init commit
2026-08-04 16:52:02 -03:00

345 lines
17 KiB
PHP

<?php
namespace App\Services\Integracao\Bnafar;
use App\Enums\Cadastro\Fabricante\Tipo as FabricanteTipo;
use App\Enums\Integracao\Bnafar\BnafarOperacaoTipo;
use App\Enums\Integracao\Bnafar\BnafarProcessamentoStatus;
use App\Enums\Integracao\Bnafar\BnafarServicoTipo;
use App\Models\Integracao\Bnafar\PosicaoEstoque;
use App\Models\Integracao\Bnafar\PosicaoEstoqueItem;
use App\Models\Integracao\Bnafar\Protocolo;
use App\Models\Integracao\Bnafar\ProtocoloResposta;
use App\Services\Integracao\BnafarService;
use App\Services\Service;
use App\Services\Telegram\TelegramService;
use Exception;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class PosicaoEstoqueService extends Service
{
private const POSICOES_ESTOQUE_POR_PROTOCOLO = 1000;
private const ITENS_POR_POSICAO_ESTOQUE = 60;
public static function store()
{
$posicaoEstoqueId = null;
$posicoes = self::getAlmoxarifadoPosicoesEstoque();
if (sizeof($posicoes) > 0) {
$protocoloId = Protocolo::create([
'servico_tipo_id' => BnafarServicoTipo::POSICAO_ESTOQUE,
'operacao_tipo_id' => BnafarOperacaoTipo::OPERACAO_INCLUSAO_REGISTRO,
])->id;
}
foreach ($posicoes as $posicao) {
$posicaoEstoqueId = DB::table('integracao_bnafar_posicao_estoque')
->where('id', $posicaoEstoqueId)
->whereRaw('
(
SELECT COUNT(*)
FROM integracao_bnafar_posicao_estoque_item
WHERE integracao_bnafar_posicao_estoque_item.posicao_estoque_id = integracao_bnafar_posicao_estoque.id
) < ' . self::ITENS_POR_POSICAO_ESTOQUE . '
')
->first()->id ?? null;
if (is_null($posicaoEstoqueId)) {
$protocoloId = DB::table('integracao_bnafar_protocolo')
->where('id', $protocoloId)
->whereRaw('
(
SELECT COUNT(*)
FROM integracao_bnafar_posicao_estoque
WHERE integracao_bnafar_posicao_estoque.protocolo_id = integracao_bnafar_protocolo.id
) < ' . self::POSICOES_ESTOQUE_POR_PROTOCOLO . '
')
->first()->id ?? null;
if (is_null($protocoloId)) {
$protocoloId = Protocolo::create([
'servico_tipo_id' => BnafarServicoTipo::POSICAO_ESTOQUE,
'operacao_tipo_id' => BnafarOperacaoTipo::OPERACAO_INCLUSAO_REGISTRO,
])->id;
}
$posicaoEstoqueId = PosicaoEstoque::create([
'protocolo_id' => $protocoloId,
'centro_custo_id' => $posicao->centro_custo_id,
'data_posicao_estoque' => $posicao->data_posicao_estoque,
])->id;
}
PosicaoEstoqueItem::create([
'posicao_estoque_id' => $posicaoEstoqueId,
'material_id' => $posicao->material_id,
'fabricante_id' => $posicao->fabricante_id,
'integracao_bnafar_medicamento_id' => $posicao->integracao_bnafar_medicamento_id,
'lote' => $posicao->lote,
'data_validade' => $posicao->data_validade,
'quantidade' => $posicao->quantidade,
'valor_unitario' => $posicao->valor_unitario,
]);
}
}
public static function post($cliente, $token, $ibge)
{
$protocolos = self::getPosicoesEstoque();
foreach ($protocolos as $protocolo) {
try {
$response = BnafarService::post(['action' => 'posicao-estoque-lote', 'token' => $token, 'ibge' => $ibge], $protocolo['posicoes']);
if ($response->status() === Response::HTTP_OK) {
Protocolo::where('id', $protocolo['id'])->update([
'processamento_status_id' => $response['situacao'],
'protocolo' => $response['protocolo'],
'data_protocolo' => $response['dataProtocolo'],
]);
} else {
Protocolo::where('id', $protocolo['id'])->update(['processamento_status_id' => BnafarProcessamentoStatus::ERRO_INTERNO_SERVIDOR]);
ProtocoloResposta::create([
'protocolo_id' => $protocolo['id'],
'resposta' => json_encode($response->json()),
]);
}
} catch (Exception $error) {
Log::channel('integracao-bnafar')->error('Erro ao executar o comando', [
'cliente' => $cliente,
'origem' => 'PosicaoEstoqueService',
'erro' => $error->getMessage(),
]);
if (env('APP_ENV') === 'production') {
TelegramService::send('<strong>Integração BNAFAR (' . $cliente . '):</strong> (Erro ao executar o comando: EnviarPosicaoEstoqueCommand).');
}
continue;
}
}
}
public static function check($cliente, $token, $ibge)
{
Protocolo::whereNull('protocolo')->delete();
$protocolos = self::getProtocolos();
foreach ($protocolos as $protocolo) {
try {
$response = BnafarService::getDetalheProcessamento($token, $ibge, $protocolo->protocolo);
if (isset($response['protocolo'])) {
Protocolo::where('id', $protocolo->id)->update(['processamento_status_id' => $response['protocolo']['situacao']]);
}
$resposta = BnafarService::getInconsistencias($token, $ibge, $protocolo->protocolo);
if (!is_null($resposta)) {
ProtocoloResposta::create([
'protocolo_id' => $protocolo->id,
'resposta' => $resposta,
]);
self::salvarInconsistenciasItens($resposta);
} else {
ProtocoloResposta::where('protocolo_id', $protocolo->id)->delete();
}
if (isset($response['itensProcessados'])) {
foreach ($response['itensProcessados'] as $itemProcessado) {
PosicaoEstoque::where('id', $itemProcessado['codigoOrigem'])->update([
'codigo_registro' => isset($itemProcessado['codigoBnafar']) && $itemProcessado['codigoBnafar'] > 0 ? $itemProcessado['codigoBnafar'] : null,
'processado_sucesso' => $itemProcessado['sucesso'],
]);
}
}
} catch (Exception $error) {
Log::channel('integracao-bnafar')->error('Erro ao executar o comando', [
'cliente' => $cliente,
'origem' => 'PosicaoEstoqueService',
'erro' => $error->getMessage(),
]);
if (env('APP_ENV') === 'production') {
TelegramService::send('<strong>Integração BNAFAR (' . $cliente . '):</strong> (Erro ao executar o comando: EnviarPosicaoEstoqueCommand).');
}
continue;
}
}
}
private static function salvarInconsistenciasItens($resposta)
{
collect(json_decode($resposta, true))
->pluck('inconsistencias')
->filter()
->flatten(1)
->groupBy('codigoOrigem')
->each(function ($inconsistencias, $codigoOrigem) {
$mensagem = $inconsistencias
->pluck('mensagem')
->map(fn ($mensagem) => BnafarService::formatarMensagem($mensagem))
->filter()
->unique()
->implode(' ');
PosicaoEstoqueItem::where('id', $codigoOrigem)->update(['mensagem' => $mensagem]);
});
}
private static function getPosicoesEstoque()
{
return DB::table('integracao_bnafar_protocolo')
->select('id')
->where('servico_tipo_id', BnafarServicoTipo::POSICAO_ESTOQUE)
->whereNull('integracao_bnafar_protocolo.processamento_status_id')
->get()
->map(function($protocolo) {
$posicoes = DB::table('integracao_bnafar_posicao_estoque')
->select([
'cadastro_unidade.cnes AS cnes',
'cadastro_setor.tipo_id AS setor_tipo_id',
'integracao_bnafar_posicao_estoque.id AS codigo_origem',
'integracao_bnafar_posicao_estoque.data_posicao_estoque',
])
->join('cadastro_centro_custo', 'cadastro_centro_custo.id', 'integracao_bnafar_posicao_estoque.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')
->where('integracao_bnafar_posicao_estoque.protocolo_id', $protocolo->id)
->where(function($query) {
$query
->whereNull('integracao_bnafar_posicao_estoque.processado_sucesso')
->orWhere('integracao_bnafar_posicao_estoque.processado_sucesso', false);
})
->get()
->map(function($posicao){
$itens = DB::table('integracao_bnafar_posicao_estoque_item')
->select([
'integracao_bnafar_posicao_estoque_item.posicao_estoque_id',
'integracao_bnafar_posicao_estoque_item.id AS codigo_origem',
'cadastro_material_bnafar.codigo AS numero',
'cadastro_material_bnafar.tipo AS tipo_produto',
'integracao_bnafar_posicao_estoque_item.lote',
DB::raw("DATE_FORMAT(integracao_bnafar_posicao_estoque_item.data_validade, '%Y-%m-%d') AS data_validade"),
'cadastro_fabricante.tipo_id AS tipo_fabricante',
'cadastro_fabricante.cnpj AS cnpj_fabricante',
'cadastro_fabricante.nome AS nome_fabricante',
'integracao_bnafar_medicamento.codigo AS integracao_bnafar_medicamento_codigo',
'integracao_bnafar_posicao_estoque_item.quantidade',
'integracao_bnafar_posicao_estoque_item.valor_unitario',
])
->join('cadastro_material', 'cadastro_material.id', 'integracao_bnafar_posicao_estoque_item.material_id')
->join('cadastro_material_bnafar', 'cadastro_material_bnafar.id', 'cadastro_material.material_bnafar_id')
->join('cadastro_fabricante', 'cadastro_fabricante.id', 'integracao_bnafar_posicao_estoque_item.fabricante_id')
->leftJoin('integracao_bnafar_medicamento', 'integracao_bnafar_medicamento.id', 'integracao_bnafar_posicao_estoque_item.integracao_bnafar_medicamento_id')
->where('integracao_bnafar_posicao_estoque_item.posicao_estoque_id', $posicao->codigo_origem)
->get()
->map(function($item) {
return [
'codigoOrigem' => $item->codigo_origem,
'numero' => $item->numero,
'terminologia' => $item->integracao_bnafar_medicamento_codigo ? 'OBM' : 'CATMAT',
'codigoAmpp' => $item->integracao_bnafar_medicamento_codigo,
'tipoProduto' => $item->tipo_produto,
'lote' => $item->lote,
'dataValidade' => $item->data_validade,
'cnpjFabricante' => $item->tipo_fabricante === FabricanteTipo::NACIONAL ? $item->cnpj_fabricante : null,
'nomeFabricanteInternacional' => $item->tipo_fabricante === FabricanteTipo::INTERNACIONAL ? $item->nome_fabricante : null,
'quantidade' => $item->quantidade,
'valorUnitario' => $item->valor_unitario,
];
})
->toArray();
return [
'estabelecimento' => [
'cnes' => $posicao->cnes,
'tipo' => BnafarService::getEstabelecimentoTipo($posicao->setor_tipo_id),
],
'caracterizacao' => [
'codigoOrigem' => $posicao->codigo_origem,
'dataPosicaoEstoque' => $posicao->data_posicao_estoque,
],
'itens' => $itens,
];
})
->toArray();
return [
'id' => $protocolo->id,
'posicoes' => $posicoes,
];
})
->toArray();
}
private static function getProtocolos()
{
return DB::table('integracao_bnafar_protocolo')
->select([
'id',
'protocolo',
])
->where('servico_tipo_id', BnafarServicoTipo::POSICAO_ESTOQUE)
->where('processamento_status_id', '!=', BnafarProcessamentoStatus::PROCESSAMENTO_FINALIZADO_SEM_INCONSISTENCIA)
->whereNotNull('processamento_status_id')
->get();
}
private static function getAlmoxarifadoPosicoesEstoque()
{
return DB::table('almoxarifado_entrada_item')
->select([
'almoxarifado_entrada.centro_custo_id',
'almoxarifado_entrada_item.material_id',
'almoxarifado_entrada_item.fabricante_id',
'almoxarifado_entrada_item.integracao_bnafar_medicamento_id',
'almoxarifado_entrada_item.lote',
'almoxarifado_entrada_item.validade_lote AS data_validade',
DB::raw('CURRENT_DATE AS data_posicao_estoque'),
DB::raw('MAX(almoxarifado_entrada_item.valor_unitario) AS valor_unitario'),
DB::raw('
SUM(almoxarifado_entrada_item.quantidade - COALESCE((
SELECT SUM(almoxarifado_saida_item_entrada_item.quantidade_saida)
FROM almoxarifado_saida_item_entrada_item
INNER JOIN almoxarifado_saida_item
ON almoxarifado_saida_item.id = almoxarifado_saida_item_entrada_item.saida_item_id
INNER JOIN almoxarifado_saida
ON almoxarifado_saida.id = almoxarifado_saida_item.saida_id
WHERE almoxarifado_saida.finalizada = true
AND almoxarifado_saida_item_entrada_item.entrada_item_id = almoxarifado_entrada_item.id
), 0)) AS quantidade
'),
])
->join('almoxarifado_entrada', 'almoxarifado_entrada.id', 'almoxarifado_entrada_item.entrada_id')
->where('almoxarifado_entrada.finalizada', true)
->whereNotNull('almoxarifado_entrada_item.fabricante_id')
->whereNotNull('almoxarifado_entrada_item.lote')
->where(DB::raw('ROUND(almoxarifado_entrada_item.valor_unitario, 2)'), '>', 0)
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('cadastro_material')
->join('cadastro_material_bnafar', 'cadastro_material_bnafar.id', 'cadastro_material.material_bnafar_id')
->whereColumn('cadastro_material.id', 'almoxarifado_entrada_item.material_id')
)
->groupBy([
'almoxarifado_entrada.centro_custo_id',
'almoxarifado_entrada_item.material_id',
'almoxarifado_entrada_item.fabricante_id',
'almoxarifado_entrada_item.integracao_bnafar_medicamento_id',
'almoxarifado_entrada_item.lote',
'almoxarifado_entrada_item.validade_lote',
DB::raw('CURRENT_DATE'),
])
->get();
}
}