Warenwirtschaft: OPT-3 Index-Limits + OPT-4 show()-Refactoring
- Wareneingang-/Produktions-Uebersicht: Eingegangene auf 500 gedeckelt (offene Bestellungen immer vollstaendig), ?all=1 + Hinweis-Link; ungenutzte User-Eager-Loads entfernt - RawMaterialStockController::show() entschlackt: Chargen-Restmengen (FEFO) und offene Bestellungen im InventoryService, letzter Netto-Preis je Lieferant als Window-Function-Query im StockEntryRepository Tests: RawMaterialStockTest +2, volle Suite 186 gruen, 663 Assertions Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
209ea467eb
commit
e47d848d3d
10 changed files with 165 additions and 75 deletions
|
|
@ -22,10 +22,13 @@ class ProductionController extends Controller
|
|||
protected ProductionService $productionService
|
||||
) {}
|
||||
|
||||
public function index(): View
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$limit = $request->boolean('all') ? null : 500;
|
||||
|
||||
return view('admin.inventory.productions.index', [
|
||||
'values' => $this->productionRepository->listForIndex(),
|
||||
'values' => $this->productionRepository->listForIndex($limit),
|
||||
'listLimit' => $limit,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ use App\Models\Ingredient;
|
|||
use App\Models\Location;
|
||||
use App\Models\StockEntry;
|
||||
use App\Models\TaxRate;
|
||||
use App\Repositories\StockEntryRepository;
|
||||
use App\Services\InventoryService;
|
||||
use App\Services\ProductionService;
|
||||
use App\Services\ProductStockService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
|
@ -17,8 +17,8 @@ class RawMaterialStockController extends Controller
|
|||
{
|
||||
public function __construct(
|
||||
protected InventoryService $inventoryService,
|
||||
protected ProductionService $productionService,
|
||||
protected ProductStockService $productStockService,
|
||||
protected StockEntryRepository $stockEntryRepository,
|
||||
) {}
|
||||
|
||||
public function index(Request $request): View
|
||||
|
|
@ -76,47 +76,19 @@ class RawMaterialStockController extends Controller
|
|||
'products' => fn ($q) => $q->where('active', true),
|
||||
]);
|
||||
|
||||
$entries = StockEntry::query()
|
||||
->with(['supplier', 'location'])
|
||||
->where('status', 'received')
|
||||
->where('entry_type', 'ingredient')
|
||||
->where('ingredient_id', $ingredient->id)
|
||||
->orderByRaw('best_before is null, best_before asc')
|
||||
->orderBy('id')
|
||||
->get();
|
||||
|
||||
$consumed = $this->productionService->consumedByStockEntry($entries->pluck('id')->all());
|
||||
|
||||
$charges = $entries->map(function (StockEntry $entry) use ($consumed) {
|
||||
$received = $entry->received_quantity !== null ? (float) $entry->received_quantity : 0.0;
|
||||
$entry->setAttribute('remaining_quantity', round($received - ($consumed[(int) $entry->id] ?? 0.0), 2));
|
||||
|
||||
return $entry;
|
||||
})->filter(fn (StockEntry $entry) => (float) $entry->getAttribute('remaining_quantity') > 0.0)
|
||||
->values();
|
||||
|
||||
$remaining = array_sum(array_map(
|
||||
fn (StockEntry $entry) => (float) $entry->getAttribute('remaining_quantity'),
|
||||
$charges->all()
|
||||
));
|
||||
$charges = $this->inventoryService->chargesWithRemainingForIngredient($ingredient->id);
|
||||
$remaining = round((float) $charges->sum(fn (StockEntry $entry) => (float) $entry->getAttribute('remaining_quantity')), 2);
|
||||
|
||||
$remainingByLocation = $this->inventoryService->remainingByLocationForIngredient($ingredient->id);
|
||||
|
||||
$openOrders = StockEntry::query()
|
||||
->with(['supplier', 'location'])
|
||||
->where('status', 'pending')
|
||||
->where('entry_type', 'ingredient')
|
||||
->where('ingredient_id', $ingredient->id)
|
||||
->orderBy('ordered_at')
|
||||
->orderBy('id')
|
||||
->get();
|
||||
$openOrders = $this->inventoryService->openOrdersForIngredient($ingredient->id);
|
||||
$openTotal = round((float) $openOrders->sum('ordered_quantity'), 2);
|
||||
|
||||
$daily = ($this->inventoryService->dailyConsumptionByIngredient([$ingredient->id]))[$ingredient->id] ?? null;
|
||||
$minAlert = $ingredient->min_stock_alert !== null ? (float) $ingredient->min_stock_alert : null;
|
||||
$leadDays = $ingredient->delivery_time_days !== null ? (int) $ingredient->delivery_time_days : null;
|
||||
|
||||
$lastPriceBySupplier = $this->lastNetPricePerSupplier($ingredient->id);
|
||||
$lastPriceBySupplier = $this->stockEntryRepository->lastNetPricePerSupplier($ingredient->id);
|
||||
|
||||
$productStock = $this->productStockService->currentStockByProduct($ingredient->products->pluck('id')->all());
|
||||
|
||||
|
|
@ -138,33 +110,6 @@ class RawMaterialStockController extends Controller
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Letzter Netto-kg-Preis je Lieferant für diesen Rohstoff (für die Bestell-/Lieferantenliste).
|
||||
*
|
||||
* @return array<int, float> [supplier_id => price_per_kg_net]
|
||||
*/
|
||||
protected function lastNetPricePerSupplier(int $ingredientId): array
|
||||
{
|
||||
$entries = StockEntry::query()
|
||||
->where('entry_type', 'ingredient')
|
||||
->where('ingredient_id', $ingredientId)
|
||||
->whereNotNull('supplier_id')
|
||||
->whereNotNull('price_per_kg')
|
||||
->orderBy('ordered_at', 'desc')
|
||||
->orderBy('id', 'desc')
|
||||
->get(['supplier_id', 'price_per_kg']);
|
||||
|
||||
$result = [];
|
||||
foreach ($entries as $entry) {
|
||||
$supplierId = (int) $entry->supplier_id;
|
||||
if (! isset($result[$supplierId])) {
|
||||
$result[$supplierId] = (float) $entry->price_per_kg;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, string> [days => label]
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -25,10 +25,13 @@ class StockEntryController extends Controller
|
|||
protected StockEntryRepository $stockEntryRepository
|
||||
) {}
|
||||
|
||||
public function index(): View
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$limit = $request->boolean('all') ? null : 500;
|
||||
|
||||
return view('admin.inventory.stock-entries.index', array_merge($this->formSharedData(), [
|
||||
'values' => $this->stockEntryRepository->listForIndex(),
|
||||
'values' => $this->stockEntryRepository->listForIndex($limit),
|
||||
'listLimit' => $limit,
|
||||
]));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue