This commit is contained in:
@@ -0,0 +1,341 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WebService\Almoxarifado\Cliente;
|
||||
|
||||
use App\Enums\WebService\Almoxarifado\Cliente\EntradaDocumentoTipo as ClienteEntradaDocumentoTipo;
|
||||
use App\Enums\WebService\Almoxarifado\Cliente\EntradaStatus as EntradaStatusEnum;
|
||||
use App\Exceptions\WebService\Almoxarifado\Cliente\Entrada\BalanceteConectaSusClosedException;
|
||||
use App\Exceptions\WebService\Almoxarifado\Cliente\Entrada\CannotDeleteEntradaAprovadaException;
|
||||
use App\Exceptions\WebService\Almoxarifado\Cliente\Entrada\ConflictEntradaException;
|
||||
use App\Exceptions\WebService\Almoxarifado\Cliente\Entrada\DuplicatedMaterialLoteException;
|
||||
use App\Exceptions\WebService\Almoxarifado\Cliente\Entrada\EntradaNotFoundException;
|
||||
use App\Exceptions\WebService\Almoxarifado\Cliente\Entrada\InvalidSearchPeriodException;
|
||||
use App\Exceptions\WebService\Almoxarifado\Cliente\Entrada\PeriodoContabilClosedException;
|
||||
use App\Models\WebService\Almoxarifado\Cliente\Entrada;
|
||||
use App\Models\WebService\Almoxarifado\Cliente\EntradaDocumentoTipo;
|
||||
use App\Models\WebService\Almoxarifado\Cliente\EntradaStatus;
|
||||
use App\Models\WebService\Almoxarifado\Cliente\Fabricante;
|
||||
use App\Models\WebService\Almoxarifado\Cliente\Fornecedor;
|
||||
use App\Models\WebService\Almoxarifado\Cliente\Material;
|
||||
use App\Models\WebService\Almoxarifado\Cliente\PeriodoContabil;
|
||||
use App\Models\WebService\Almoxarifado\Cliente\Unidade;
|
||||
use App\Services\Almoxarifado\BalanceteService;
|
||||
use App\Services\Service;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class EntradaService extends Service
|
||||
{
|
||||
public const LIMITE_DIAS_PERIODO_BUSCA = 31;
|
||||
|
||||
public static function index($request)
|
||||
{
|
||||
self::validateIndex($request);
|
||||
|
||||
$entradas = collect();
|
||||
|
||||
DB::table('web_service_almoxarifado_cliente_entrada_item AS entrada_item')
|
||||
->join('web_service_almoxarifado_cliente_entrada AS entrada', 'entrada.id', 'entrada_item.entrada_id')
|
||||
->whereBetween('entrada.data_documento', [
|
||||
$request->query('data_documento_inicial'),
|
||||
$request->query('data_documento_final')
|
||||
])
|
||||
->when($request->query('status_id'), fn ($q, $id) => $q->where('entrada.status_id', $id))
|
||||
->select([
|
||||
'entrada.id AS entrada_id',
|
||||
'entrada.unidade_id',
|
||||
'entrada.fornecedor_id',
|
||||
'entrada.codigo_nota',
|
||||
'entrada.documento_tipo_id',
|
||||
'entrada.data_documento',
|
||||
'entrada.numero_documento',
|
||||
'entrada.numero_pedido',
|
||||
'entrada.status_id',
|
||||
'entrada_item.material_id',
|
||||
'entrada_item.fabricante_id',
|
||||
'entrada_item.lote',
|
||||
'entrada_item.validade_lote',
|
||||
'entrada_item.quantidade',
|
||||
'entrada_item.valor_unitario',
|
||||
])
|
||||
->orderBy('entrada.data_documento')
|
||||
->each(function ($entradaItem) use ($entradas) {
|
||||
|
||||
$entrada = $entradas->where('id', $entradaItem->entrada_id)->first();
|
||||
|
||||
if (is_null($entrada)) {
|
||||
|
||||
$entrada = (object) [
|
||||
'id' => $entradaItem->entrada_id,
|
||||
'unidade_id' => $entradaItem->unidade_id,
|
||||
'fornecedor_id' => $entradaItem->fornecedor_id,
|
||||
'codigo_nota' => $entradaItem->codigo_nota,
|
||||
'documento_tipo_id' => $entradaItem->documento_tipo_id,
|
||||
'data_documento' => $entradaItem->data_documento,
|
||||
'numero_documento' => $entradaItem->numero_documento,
|
||||
'numero_pedido' => $entradaItem->numero_pedido,
|
||||
'status_id' => $entradaItem->status_id,
|
||||
'itens' => collect(),
|
||||
];
|
||||
|
||||
$entradas->push($entrada);
|
||||
}
|
||||
|
||||
$entrada->itens->push((object) [
|
||||
'material_id' => $entradaItem->material_id,
|
||||
'fabricante_id' => $entradaItem->fabricante_id,
|
||||
'lote' => $entradaItem->lote,
|
||||
'validade_lote' => $entradaItem->validade_lote,
|
||||
'quantidade' => $entradaItem->quantidade,
|
||||
'valor_unitario' => (float) $entradaItem->valor_unitario,
|
||||
]);
|
||||
});
|
||||
|
||||
return $entradas;
|
||||
}
|
||||
|
||||
private static function validateIndex($request)
|
||||
{
|
||||
$request->validate([
|
||||
'data_documento_inicial' => [
|
||||
'required',
|
||||
'date_format:Y-m-d',
|
||||
'before_or_equal:data_documento_final',
|
||||
],
|
||||
'data_documento_final' => [
|
||||
'required',
|
||||
'date_format:Y-m-d',
|
||||
'after_or_equal:data_documento_inicial',
|
||||
],
|
||||
'status_id' => [
|
||||
'integer',
|
||||
Rule::exists(EntradaStatus::class, 'id'),
|
||||
]
|
||||
]);
|
||||
|
||||
$dataDocumentoInicial = Carbon::create($request->data_documento_inicial);
|
||||
$dataDocumentoFinal = Carbon::create($request->data_documento_final);
|
||||
|
||||
if ($dataDocumentoInicial->diff($dataDocumentoFinal)->days > self::LIMITE_DIAS_PERIODO_BUSCA) {
|
||||
|
||||
throw new InvalidSearchPeriodException();
|
||||
}
|
||||
}
|
||||
|
||||
public static function show($id)
|
||||
{
|
||||
$entrada = self::getEntradaModel($id)->load('itens');
|
||||
|
||||
$entrada->itens->each(function ($item) {
|
||||
|
||||
$item->valor_unitario = (float) $item->valor_unitario;
|
||||
});
|
||||
|
||||
return $entrada;
|
||||
}
|
||||
|
||||
public static function store($request)
|
||||
{
|
||||
self::validate($request);
|
||||
|
||||
$data = self::getEntradaData($request);
|
||||
$entrada = new Entrada();
|
||||
|
||||
DB::transaction(function () use ($entrada, $data) {
|
||||
|
||||
$entrada->fill($data);
|
||||
$entrada->save();
|
||||
|
||||
$entrada->itens()->createMany($data['itens']);
|
||||
});
|
||||
|
||||
return self::show($entrada->id);
|
||||
}
|
||||
|
||||
private static function getEntradaData($request)
|
||||
{
|
||||
$data = $request->only([
|
||||
'unidade_id',
|
||||
'fornecedor_id',
|
||||
'codigo_nota',
|
||||
'documento_tipo_id',
|
||||
'data_documento',
|
||||
'numero_documento',
|
||||
'numero_pedido',
|
||||
]);
|
||||
|
||||
$data['status_id'] = EntradaStatusEnum::PENDENTE;
|
||||
|
||||
$data['itens'] = collect($request->itens)->map(fn ($item) => [
|
||||
'material_id' => $item['material_id'],
|
||||
'fabricante_id' => $item['fabricante_id'],
|
||||
'lote' => $item['lote'],
|
||||
'validade_lote' => $item['validade_lote'],
|
||||
'quantidade' => $item['quantidade'],
|
||||
'valor_unitario' => $item['valor_unitario'],
|
||||
]);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public static function destroy($id)
|
||||
{
|
||||
$entrada = self::getEntradaModel($id);
|
||||
|
||||
if ($entrada->status_id === EntradaStatusEnum::APROVADA) {
|
||||
|
||||
throw new CannotDeleteEntradaAprovadaException();
|
||||
}
|
||||
|
||||
$entrada->delete();
|
||||
}
|
||||
|
||||
private static function validate($request)
|
||||
{
|
||||
$request->validate([
|
||||
'unidade_id' => [
|
||||
'bail',
|
||||
'required',
|
||||
'integer',
|
||||
Rule::exists(Unidade::class, 'id'),
|
||||
function ($attribute, $value, $fail) {
|
||||
|
||||
if (!Unidade::find($value)->is_almoxarifado) {
|
||||
|
||||
$fail("O campo {$attribute} não é um almoxarifado.");
|
||||
}
|
||||
},
|
||||
],
|
||||
'fornecedor_id' => [
|
||||
'required',
|
||||
'integer',
|
||||
Rule::exists(Fornecedor::class, 'id'),
|
||||
],
|
||||
'codigo_nota' => [
|
||||
'required',
|
||||
'integer',
|
||||
],
|
||||
'documento_tipo_id' => [
|
||||
'required',
|
||||
'integer',
|
||||
Rule::exists(EntradaDocumentoTipo::class, 'id'),
|
||||
],
|
||||
'data_documento' => [
|
||||
'bail',
|
||||
'required',
|
||||
'date_format:Y-m-d',
|
||||
'before_or_equal:' . Carbon::today()->format('Y-m-d'),
|
||||
],
|
||||
'numero_documento' => [
|
||||
'nullable',
|
||||
'present',
|
||||
'digits_between:1,10',
|
||||
],
|
||||
'numero_pedido' => [
|
||||
'nullable',
|
||||
'present',
|
||||
'digits_between:1,20',
|
||||
],
|
||||
'itens' => [
|
||||
'required',
|
||||
'array',
|
||||
],
|
||||
'itens.*.material_id' => [
|
||||
'required',
|
||||
'integer',
|
||||
Rule::exists(Material::class, 'id'),
|
||||
],
|
||||
'itens.*.fabricante_id' => [
|
||||
'required',
|
||||
'integer',
|
||||
Rule::exists(Fabricante::class, 'id'),
|
||||
],
|
||||
'itens.*.lote' => [
|
||||
'required',
|
||||
'string',
|
||||
'max:15',
|
||||
],
|
||||
'itens.*.validade_lote' => [
|
||||
'bail',
|
||||
'required',
|
||||
'date_format:Y-m-d',
|
||||
'after_or_equal:data_documento',
|
||||
],
|
||||
'itens.*.quantidade' => [
|
||||
'required',
|
||||
'integer',
|
||||
'between:1,99999999'
|
||||
],
|
||||
'itens.*.valor_unitario' => [
|
||||
'required',
|
||||
'numeric',
|
||||
'min:' . (
|
||||
(EntradaDocumentoTipo::find($request->documento_tipo_id)->id ?? null) === ClienteEntradaDocumentoTipo::DOACAO
|
||||
? '0.000000'
|
||||
: '0.000001'
|
||||
),
|
||||
'max:99999999.999999'
|
||||
],
|
||||
]);
|
||||
|
||||
$hasDuplicatedMaterialLote = collect($request->itens)
|
||||
->groupBy(['material_id', 'lote'])
|
||||
->filter(fn ($m) => $m->filter(fn ($l) => $l->count() > 1)->isNotEmpty())
|
||||
->isNotEmpty();
|
||||
|
||||
if ($hasDuplicatedMaterialLote) {
|
||||
|
||||
throw new DuplicatedMaterialLoteException();
|
||||
}
|
||||
|
||||
$entradaConflitante = Entrada::where('unidade_id', $request->unidade_id)
|
||||
->where('fornecedor_id', $request->fornecedor_id)
|
||||
->where('codigo_nota', $request->codigo_nota)
|
||||
->where('documento_tipo_id', $request->documento_tipo_id)
|
||||
->where('data_documento', $request->data_documento)
|
||||
->where('numero_documento', $request->numero_documento)
|
||||
->where('numero_pedido', $request->numero_pedido)
|
||||
->whereIn('status_id', [EntradaStatusEnum::PENDENTE, EntradaStatusEnum::APROVADA])
|
||||
->exists();
|
||||
|
||||
if ($entradaConflitante) {
|
||||
|
||||
throw new ConflictEntradaException();
|
||||
}
|
||||
|
||||
if (self::isDataDocumentoEmPeriodoContabilFechado($request->data_documento)) {
|
||||
|
||||
throw new PeriodoContabilClosedException();
|
||||
}
|
||||
|
||||
if (self::isDataDocumentoEmBalanceteDoAlmoxarifadoFechado($request->data_documento)) {
|
||||
|
||||
throw new BalanceteConectaSusClosedException();
|
||||
}
|
||||
}
|
||||
|
||||
private static function isDataDocumentoEmPeriodoContabilFechado($dataDocumento)
|
||||
{
|
||||
return PeriodoContabil::where('inicio', '<=', $dataDocumento)
|
||||
->where('fim', '>=', $dataDocumento)
|
||||
->exists();
|
||||
}
|
||||
|
||||
private static function isDataDocumentoEmBalanceteDoAlmoxarifadoFechado($dataDocumento)
|
||||
{
|
||||
return BalanceteService::checkDate($dataDocumento)['mes_fechado'];
|
||||
}
|
||||
|
||||
private static function getEntradaModel($id)
|
||||
{
|
||||
$entrada = Entrada::find($id);
|
||||
|
||||
if (is_null($entrada)) {
|
||||
|
||||
throw new EntradaNotFoundException();
|
||||
}
|
||||
|
||||
return $entrada;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user