commit13
This commit is contained in:
@@ -14,6 +14,7 @@ use App\Models\Warehouse;
|
||||
use Brick\Math\BigDecimal;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
@@ -26,14 +27,17 @@ class ReceiptWorkflow
|
||||
return BigDecimal::of($quantity)->multipliedBy(1000)->toScale(0)->toInt();
|
||||
}
|
||||
|
||||
private function recordedQuantity(int $lineId, string $column): int
|
||||
public function recordedQuantity(int $lineId, string $column): int
|
||||
{
|
||||
if (! in_array($column, ['received_milli', 'accepted_milli'], true)) {
|
||||
throw new \InvalidArgumentException('Quantidade de recepção desconhecida.');
|
||||
}
|
||||
$sum = GoodsReceiptItem::query()->where('purchase_order_item_id', $lineId)->sum($column);
|
||||
if (! is_int($sum) && ! is_string($sum)) {
|
||||
throw new \LogicException('A soma das quantidades deve ser um inteiro exacto.');
|
||||
}
|
||||
|
||||
return BigDecimal::of($sum)->toInt();
|
||||
return BigDecimal::of($sum)->minus(app(InventoryReversals::class)->voidedReceiptQuantity($lineId, $column))->toInt();
|
||||
}
|
||||
|
||||
/** @return array{lines: list<array<string, mixed>>, state: string, has_divergences: bool} */
|
||||
@@ -48,13 +52,16 @@ class ReceiptWorkflow
|
||||
$ordered = self::milli($item->quantity);
|
||||
$received = $this->recordedQuantity($item->id, 'received_milli');
|
||||
$accepted = $this->recordedQuantity($item->id, 'accepted_milli');
|
||||
$returned = app(InventoryDispositions::class)->returnedForOrderLine($item->id);
|
||||
$effective = $accepted - $returned;
|
||||
$lines[] = [
|
||||
...$item->only(['id', 'description', 'unit', 'purchase_type']),
|
||||
...(isset($order->snapshot['catalogue_sources'][$item->requisition_item_id]['stock_item_id']) ? ['stock_item_id' => $order->snapshot['catalogue_sources'][$item->requisition_item_id]['stock_item_id']] : []),
|
||||
'ordered_milli' => $ordered, 'received_milli' => $received, 'accepted_milli' => $accepted,
|
||||
'rejected_milli' => $received - $accepted, 'delivery_pending_milli' => $ordered - $received, 'acceptance_pending_milli' => $ordered - $accepted,
|
||||
'rejected_milli' => $received - $accepted, 'delivery_pending_milli' => $ordered - $received, 'acceptance_pending_milli' => $ordered - $effective,
|
||||
...($returned > 0 ? ['supplier_returned_milli' => $returned, 'effective_accepted_milli' => $effective] : []),
|
||||
];
|
||||
$complete = $complete && $accepted === $ordered;
|
||||
$complete = $complete && $effective === $ordered;
|
||||
$delivered = $delivered && $received === $ordered;
|
||||
$started = $started || $received > 0;
|
||||
$divergences = $divergences || GoodsReceiptItem::query()->where('purchase_order_item_id', $item->id)->where('quality_status', '!=', 'compliant')->exists();
|
||||
@@ -76,9 +83,18 @@ class ReceiptWorkflow
|
||||
throw ValidationException::withMessages(['delivery_note' => 'Indique a guia de remessa do fornecedor.']);
|
||||
}
|
||||
$inputs = [];
|
||||
/** @var list<array{purchase_order_item_id: int, received_quantity: string, accepted_quantity: string, quality_status: string, stock_item_id?: int|null, notes?: string|null}> $requested */
|
||||
/** @var list<array{purchase_order_item_id: int, received_quantity: string, accepted_quantity: string, quality_status: string, stock_item_id?: int|null, notes?: string|null, lots?:list<array<string,mixed>>}> $requested */
|
||||
$requested = $data['items'];
|
||||
$supplyMappings = Schema::hasTable('supply_records')
|
||||
? app(SupplyPlanning::class)->latest('delivery')->where('purchase_order_id', $order->id)->get() : collect();
|
||||
foreach ($requested as $line) {
|
||||
$mapping = $supplyMappings->first(fn ($record) => $record->data['purchase_order_item_id'] == $line['purchase_order_item_id']);
|
||||
if ($mapping !== null) {
|
||||
if ((! empty($line['stock_item_id']) && (int) $line['stock_item_id'] !== $mapping->stock_item_id) || (int) ($data['warehouse_id'] ?? 0) !== $mapping->warehouse_id) {
|
||||
throw ValidationException::withMessages(['items' => 'Reutilize o artigo e armazém já associados à confirmação desta linha.']);
|
||||
}
|
||||
$line['stock_item_id'] = $mapping->stock_item_id;
|
||||
}
|
||||
if (! empty($order->snapshot['catalogue_sources']) && empty($line['stock_item_id'])) {
|
||||
$orderLine = $order->items()->whereKey($line['purchase_order_item_id'])->first();
|
||||
if ($orderLine !== null && isset($order->snapshot['catalogue_sources'][$orderLine->requisition_item_id]['stock_item_id'])) {
|
||||
@@ -90,6 +106,7 @@ class ReceiptWorkflow
|
||||
}
|
||||
}
|
||||
$inputs[] = [
|
||||
...(! empty($line['lots']) ? ['lots' => $line['lots']] : []),
|
||||
'purchase_order_item_id' => $line['purchase_order_item_id'],
|
||||
'received_milli' => self::milli($line['received_quantity']), 'accepted_milli' => self::milli($line['accepted_quantity']),
|
||||
'quality_status' => $line['quality_status'], 'stock_item_id' => $line['stock_item_id'] ?? null,
|
||||
@@ -117,6 +134,12 @@ class ReceiptWorkflow
|
||||
if (GoodsReceipt::query()->where('purchase_order_id', $order->id)->where('delivery_note', $deliveryNote)->exists()) {
|
||||
throw ValidationException::withMessages(['delivery_note' => 'Esta guia já foi confirmada nesta ordem. Consulte o histórico em vez de repetir a recepção.']);
|
||||
}
|
||||
if (Schema::hasTable('supply_records')) {
|
||||
$import = app(SupplyPlanning::class)->latest('import')->where('purchase_order_id', $order->id)->first();
|
||||
if ($import !== null && $import->state !== 'released') {
|
||||
throw ValidationException::withMessages(['items' => 'A importação ainda não tem libertação aduaneira comprovada. A chegada ou o pagamento não autorizam entrada utilizável.']);
|
||||
}
|
||||
}
|
||||
if ($order->status !== 'issued' || $data['received_on'] < substr((string) $order->getRawOriginal('issued_at'), 0, 10)) {
|
||||
throw ValidationException::withMessages(['received_on' => 'A recepção deve referir uma ordem emitida e não pode anteceder a sua emissão.']);
|
||||
}
|
||||
@@ -193,12 +216,15 @@ class ReceiptWorkflow
|
||||
foreach ($lines as $line) {
|
||||
$item = $receipt->items()->create($line);
|
||||
if ($line['accepted_milli'] > 0 && $line['snapshot']['physical']) {
|
||||
StockMovement::query()->create([
|
||||
$movement = StockMovement::query()->create([
|
||||
'tenant_id' => $user->tenant_id, 'goods_receipt_item_id' => $item->id, 'stock_item_id' => $line['stock_item_id'],
|
||||
'warehouse_id' => $warehouse?->id, 'moved_by' => $user->id, 'quantity_milli' => $line['accepted_milli'], 'moved_at' => now(),
|
||||
'equipment_id' => $line['snapshot']['equipment_id'], 'spare_part_id' => $line['snapshot']['spare_part_id'],
|
||||
'snapshot' => [...$line['snapshot'], 'receipt_id' => $receipt->id, 'order_number' => $order->number, 'delivery_note' => $deliveryNote],
|
||||
]);
|
||||
$sourceInput = collect($inputs)->firstWhere('purchase_order_item_id', $line['purchase_order_item_id']);
|
||||
app(InventoryLots::class)->receive($user, $movement, $sourceInput['lots'] ?? [], $data['received_on']);
|
||||
app(AutomaticPurchases::class)->signal($user,$line['stock_item_id'],$warehouse->id);
|
||||
}
|
||||
}
|
||||
$progress = $this->progress($order);
|
||||
|
||||
Reference in New Issue
Block a user