342 lines
12 KiB
PHP
342 lines
12 KiB
PHP
<?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;
|
|
}
|
|
}
|