Anchor next lot forecast after current lot
This commit is contained in:
1 parent
959586ecc9
commit
3ae9951b13
2 files changed
+23
-7
No files matched your search
@@ -23,7 +23,7 @@ Direkt ausgeführter Lager-Prozess mit zwei Triggern: synchron nach jeder erfolg
|
||||
4. `allocated`- und `reserved`-Mengen nach Bestell- beziehungsweise OTC-Verkaufsdatum je Produkt und Kalendertag aggregieren.
|
||||
5. Stornierte Auftrags- und Positionsmengen aus der Nachfrage herausrechnen.
|
||||
6. Den gewichteten Tagesabsatz mit einer Halbwertszeit von 60 Tagen berechnen.
|
||||
7. Das Leer-Datum der aktuellen Charge und – sofern vorhanden – der nächsten Charge getrennt aus dem jeweiligen physischen Bestand und derselben gewichteten Nachfrage berechnen.
|
||||
7. Das Leer-Datum der aktuellen Charge aus ihrem physischen Bestand und der gewichteten Nachfrage berechnen. Das Leer-Datum der nächsten Charge wird mit derselben Nachfrage ab dem Leer-Datum der aktuellen Charge weitergerechnet; bei bereits leerer aktueller Charge beginnt es am aktuellen Datum.
|
||||
8. Jede erfolgreiche Berechnung je Charge in `stock_lot_forecast_history` speichern und den jeweiligen Snapshot in `stock_lot` aktualisieren.
|
||||
9. Im Cron Fehler einzelner Produkte sammeln und mit den übrigen Produkten fortfahren.
|
||||
|
||||
|
||||
@@ -124,7 +124,12 @@ function lager_forecast_load_daily_sales(PDO $pdo, DateTimeImmutable $asOfDate,
|
||||
return $sales;
|
||||
}
|
||||
|
||||
function lager_forecast_calculate(DateTimeImmutable $asOfDate, float $physicalQty, array $dailySales): array
|
||||
function lager_forecast_calculate(
|
||||
DateTimeImmutable $asOfDate,
|
||||
float $physicalQty,
|
||||
array $dailySales,
|
||||
?DateTimeImmutable $forecastStartDate = null
|
||||
): array
|
||||
{
|
||||
$lookbackDays = 365;
|
||||
$halfLifeDays = 60;
|
||||
@@ -176,8 +181,9 @@ function lager_forecast_calculate(DateTimeImmutable $asOfDate, float $physicalQt
|
||||
? 'high'
|
||||
: ($salesDays >= 10 ? 'medium' : 'low');
|
||||
$daysUntilDepleted = (int) ceil($physicalQty / $dailyDemand);
|
||||
$forecastStartDate ??= $asOfDate;
|
||||
return [
|
||||
'forecast_date' => $asOfDate->modify('+' . $daysUntilDepleted . ' days')->format('Y-m-d'),
|
||||
'forecast_date' => $forecastStartDate->modify('+' . $daysUntilDepleted . ' days')->format('Y-m-d'),
|
||||
'forecast_status' => 'forecast', 'confidence' => $confidence, 'daily_demand' => $dailyDemand,
|
||||
'sales_units' => $salesUnits, 'sales_days' => $salesDays, 'observed_span_days' => $observedSpanDays,
|
||||
'lookback_days' => $lookbackDays, 'half_life_days' => $halfLifeDays,
|
||||
@@ -255,12 +261,17 @@ function refresh_lager_stock_lot_forecast_for_product(PDO $pdo, int $productId):
|
||||
$dailySales[$productId] ?? []
|
||||
);
|
||||
lager_forecast_persist($pdo, $lot, $forecast, $asOfDate);
|
||||
if ($lot['next_lot_id'] !== null) {
|
||||
if ($lot['next_lot_id'] !== null && $forecast['forecast_date'] !== null) {
|
||||
lager_forecast_persist($pdo, [
|
||||
'lot_id' => $lot['next_lot_id'],
|
||||
'product_id' => $productId,
|
||||
'physical_qty' => $lot['next_physical_qty'],
|
||||
], lager_forecast_calculate($asOfDate, (float) $lot['next_physical_qty'], $dailySales[$productId] ?? []), $asOfDate);
|
||||
], lager_forecast_calculate(
|
||||
$asOfDate,
|
||||
(float) $lot['next_physical_qty'],
|
||||
$dailySales[$productId] ?? [],
|
||||
new DateTimeImmutable($forecast['forecast_date'])
|
||||
), $asOfDate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,12 +298,17 @@ function run_lager_stock_lot_forecast(PDO $pdo): array
|
||||
try {
|
||||
$forecast = lager_forecast_calculate($asOfDate, (float) $lot['physical_qty'], $dailySales[$productId] ?? []);
|
||||
lager_forecast_persist($pdo, $lot, $forecast, $asOfDate);
|
||||
if ($lot['next_lot_id'] !== null) {
|
||||
if ($lot['next_lot_id'] !== null && $forecast['forecast_date'] !== null) {
|
||||
lager_forecast_persist($pdo, [
|
||||
'lot_id' => $lot['next_lot_id'],
|
||||
'product_id' => $productId,
|
||||
'physical_qty' => $lot['next_physical_qty'],
|
||||
], lager_forecast_calculate($asOfDate, (float) $lot['next_physical_qty'], $dailySales[$productId] ?? []), $asOfDate);
|
||||
], lager_forecast_calculate(
|
||||
$asOfDate,
|
||||
(float) $lot['next_physical_qty'],
|
||||
$dailySales[$productId] ?? [],
|
||||
new DateTimeImmutable($forecast['forecast_date'])
|
||||
), $asOfDate);
|
||||
}
|
||||
$result['processed_products']++;
|
||||
} catch (Throwable $error) {
|
||||
|
||||
Reference in new issue
Block a user