$productSalesForecast = $service->calculateProductForecastInPiecesProductsWithHistory(
$filters['store_id'],
$filters['month'],
- $productSalesShare,
+ $filters['year'],
$goals,
- $filters['subcategory'],
+ $productSalesShare,
$filters['category'],
+ $filters['subcategory'],
$filters['species']
);
$productSalesForecast = $service->calculateProductForecastInPiecesProductsWithHistory(
$filters['store_id'],
$filters['month'],
- $productSalesShare,
+ $filters['year'],
$goals,
- $filters['subcategory'],
+ $productSalesShare,
$filters['category'],
+ $filters['subcategory'],
$filters['species']
+
);
$matrixForecast = MatrixBouquetForecast::find()
$filters['plan_date'] = $filters['year'] . '-' . str_pad($filters['month'], 2, '0', STR_PAD_LEFT) . '-01';
// var_dump( $filters['plan_date']); die();
$service = new AutoPlannogrammaService();
-//$goals = $service->calculateFullGoalChain($filters);
+ //$goals = $service->calculateFullGoalChain($filters);
+ //$forecast = $service->calculateFullForecastForWeek($filters);
+ //var_dump( $forecast); die();
$monthCategoryShare = $service->getMonthCategoryShareOrWriteOff($filters['plan_date'], $filters);
$monthCategoryGoal = $service->getMonthCategoryGoal($monthCategoryShare, $filters['plan_date']);
$monthSubcategoryShare = $service->getMonthSubcategoryShareOrWriteOff($filters['plan_date'], $filters);
}
- $result = StorePlanService::calculateHistoricalShare(
+ /* $result = StorePlanService::calculateHistoricalShare(
$filters['store_id'],
$filters['month'],
$filters['year'],
- $filters['category'],
- $filters['subcategory'],
- $filters['species']
- );
+ null,
+ null,
+ null
+ );*/
$noHistoryProductData = $service->calculateSpeciesForecastForProductsWithoutHistory($filters['plan_date'], $filters);
+ $historyProductData = $service->calculateSpeciesForecastForProductsWithHistory($filters['plan_date'], $filters, $goals);
- $productSalesShare = StorePlanService::calculateProductSalesShareProductsWithHistory(
+ /* $productSalesShare = StorePlanService::calculateProductSalesShareProductsWithHistory(
$filters['store_id'],
$filters['month'],
$result['with_history']
$filters['subcategory'],
$filters['category'],
$filters['species']
- );
+ );*/
$matrixForecast = MatrixBouquetForecast::find()
->where(['year' => $filters['year'], 'month' => $filters['month']])
$cleanedSpeciesGoals = $service->subtractSpeciesGoals($goals, $bouquetSpeciesForecast, $noHistoryProductData);
- $salesProductForecastShare = $service->calculateProductForecastShare($noHistoryProductData, $productSalesForecast);
+ $salesProductForecastShare = $service->calculateProductForecastShare($noHistoryProductData, $historyProductData);
$productForecastSpecies = $service->calculateProductSalesBySpecies($salesProductForecastShare, $cleanedSpeciesGoals);
$weeklySalesForecast = $service->calculateWeeklyProductForecastPieces($productForecastSpecies, $weeklySales);
-
$weeklySalesForecastFormated = $service->pivotWeeklyForecast($weeklySalesForecast);
$flatData = array_filter($weeklySalesForecastFormated, function ($row) use ($filters) {
$dataProvider = new ArrayDataProvider([
'allModels' => $flatData,
- 'pagination' => ['pageSize' => 100],
+ 'pagination' => ['pageSize' => 1000],
]);
}
return $this->render('week-sales-products_forecast', [
use yii_app\records\CityStore;
use yii_app\records\CityStoreParams;
use yii_app\records\ExportImportTable;
+use yii_app\records\MatrixBouquetForecast;
use yii_app\records\PricesDynamic;
use yii_app\records\Products1c;
use yii_app\records\Products1cNomenclature;
$dateFromForCategory = (new \DateTime($datePlan))->modify('-' . (self::CATEGORY_LOOKBACK_MONTHS + self::LOOKBACK_MONTHS) . ' months')->format('Y-m-d');
$monthCategoryShare = $this->getMonthCategoryShareOrWriteOff($dateFromForCategory, $filters);
- $monthCategoryGoal = $this->getMonthCategoryGoal($monthCategoryShare, $datePlan, $filters);
+ $monthCategoryGoal = $this->getMonthCategoryGoal($monthCategoryShare, $datePlan, $filters['type']);
$monthSubcategoryShare = $this->getMonthSubcategoryShareOrWriteOff($datePlan, $filters);
$monthSubcategoryGoal = $this->getMonthSubcategoryGoal($monthSubcategoryShare, $monthCategoryGoal);
return $result;
}
+
+ public function calculateSpeciesForecastForProductsWithHistory($dateFrom, $filters, $goals): array
+ {
+ // Получение ID видимых магазинов
+ $storeIds = array_map(fn($store) => $store->id, $this->getVisibleStores());
+
+ $subcategory = !empty($filters['subcategory']) ? $filters['subcategory'] : null;
+ $species = !empty($filters['species']) ? $filters['species'] : null;
+
+ // Применение фильтра по магазину, если указан
+ if (!empty($filters['store_id'])) {
+ $storeIds = array_intersect($storeIds, [(int)$filters['store_id']]);
+ }
+ $date = new \DateTime($dateFrom);
+ $month = $date->format('m');
+ $year = $date->format('Y');
+
+ $result = [];
+
+ foreach ($storeIds as $storeId) {
+ $histResult = StorePlanService::calculateHistoricalShare(
+ $storeId,
+ $month,
+ $year,
+ $filters['category'],
+ $subcategory,
+ $species
+ );
+
+ $productsWithHistory = $histResult['with_history'] ?? [];
+ if (empty($productsWithHistory)) {
+ continue;
+ }
+
+ $productSalesShare = StorePlanService::calculateProductSalesShareProductsWithHistory(
+ $filters['store_id'],
+ $filters['month'],
+ $productsWithHistory
+ );
+
+ if (empty($productSalesShare)) {
+ continue;
+ }
+
+ $productSalesForecast = $this->calculateProductForecastInPiecesProductsWithHistory(
+ $filters['store_id'],
+ $filters['month'],
+ $year,
+ $goals,
+ $productSalesShare,
+ $filters['category'],
+ $filters['subcategory'],
+ $filters['species']
+
+ );
+
+
+ if (!empty($productSalesForecast)) {
+ $result = array_merge($result, $productSalesForecast);
+ }
+ }
+
+ return $result;
+ }
+
public function mapGoalsBySpecies(array $rows): array {
$mapped = [];
foreach ($rows as $row) {
}
public function calculateProductForecastInPiecesProductsWithHistory(
- int $storeId,
- string $month,
- array $productSalesShare,
- array $speciesGoals,
- string $subcategory = null,
+ int $storeId,
+ string $month, string $year,
+ array $speciesGoals,
+ array $productSalesShare,
string $category = null,
+ string $subcategory = null,
string $species = null
): array {
$result = [];
$forecastCount = $forecastSum / $priceRecord->price;
$result[] = [
+ 'month' => $month,
+ 'year' => $year,
'product_id' => $productId,
'goal' => $goal,
'goal_share' => round($forecastSum, 2),
array $pieciesForecastProductsNoHistyory,
array $pieciesForecastProductWithHistory
): array {
- $shareResult = [];
+ $groupedForecasts = [];
+
+ // Обработка товаров без истории
+ foreach ($pieciesForecastProductsNoHistyory as $group) {
+ $base = [
+ 'store_id' => $group['store_id'],
+ 'month' => $group['month'],
+ 'year' => $group['year'],
+ 'category' => $group['category'],
+ 'subcategory' => $group['subcategory'],
+ 'species' => $group['species'],
+ ];
- $info = $pieciesForecastProductsNoHistyory[0] ?? null;
- if (!$info) {
- return [];
- }
+ foreach ($group['forecasts'] as $productId => $forecast) {
+ $key = implode('|', [
+ $base['store_id'], $base['category'], $base['subcategory'], $base['species']
+ ]);
- $noHistoryMap = $info['forecasts'] ?? [];
+ $groupedForecasts[$key]['meta'] = $base;
+ $groupedForecasts[$key]['products'][$productId] = [
+ 'product_id' => $productId,
+ 'forecast_pieces' => (float)$forecast,
+ 'history_status' => 'No history',
+ ];
+ }
+ }
- $piecesMap = [];
+ // Обработка товаров с историей
foreach ($pieciesForecastProductWithHistory as $item) {
- if (isset($item['product_id'], $item['forecast_pieces'])) {
- $piecesMap[$item['product_id']] = $item['forecast_pieces'];
- }
+ $key = implode('|', [
+ $item['store_id'], $item['category'], $item['subcategory'], $item['species']
+ ]);
+
+ $groupedForecasts[$key]['meta'] = [
+ 'store_id' => $item['store_id'],
+ 'month' => $item['month'],
+ 'year' => $item['year'],
+ 'category' => $item['category'],
+ 'subcategory' => $item['subcategory'],
+ 'species' => $item['species'],
+ ];
+
+ $groupedForecasts[$key]['products'][$item['product_id']] = [
+ 'product_id' => $item['product_id'],
+ 'forecast_pieces' => (float)$item['forecast_pieces'],
+ 'history_status' => 'With history',
+ ];
}
- $allProductIds = array_merge(
- array_keys($noHistoryMap),
- array_keys($piecesMap)
- );
+ $result = [];
- $quantityMap = [];
- foreach ($allProductIds as $pid) {
- if (isset($piecesMap[$pid])) {
- $quantityMap[$pid] = $piecesMap[$pid];
- } elseif (isset($noHistoryMap[$pid])) {
- $quantityMap[$pid] = (float)$noHistoryMap[$pid];
- } else {
- $quantityMap[$pid] = 0;
+ foreach ($groupedForecasts as $group) {
+ $meta = $group['meta'];
+ $products = $group['products'];
+
+ $totalForecast = array_sum(array_column($products, 'forecast_pieces'));
+
+ if ($totalForecast <= 0) {
+ continue;
}
- }
- $totalPieces = array_sum($quantityMap);
- if ($totalPieces <= 0) {
- return [];
- }
+ foreach ($products as $product) {
+ $share = round($product['forecast_pieces'] / $totalForecast, 4);
- $storeId = $info['store_id'];
- $month = $info['month'];
- $year = $info['year'];
- $category = $info['category'];
- $subcategory = $info['subcategory'];
- $species = $info['species'];
-
- foreach ($quantityMap as $pid => $count) {
- $share = $count / $totalPieces;
-
- $shareResult[] = [
- 'store_id' => $storeId,
- 'month' => $month,
- 'year' => $year,
- 'category' => $category,
- 'subcategory' => $subcategory,
- 'species' => $species,
- 'product_id' => $pid,
- 'forecast_pieces'=> $count,
- 'share' => round($share, 4),
- 'history_status' => in_array($pid, array_keys($noHistoryMap)) ? 'No history' : 'With history'
- ];
+ $result[] = array_merge($meta, [
+ 'product_id' => $product['product_id'],
+ 'forecast_pieces' => $product['forecast_pieces'],
+ 'share' => $share,
+ 'history_status' => $product['history_status'],
+ ]);
+ }
}
- return $shareResult;
+ return $result;
}
/**
}
+ public function calculateFullForecastForWeek(array $filters): array
+ {
+ $bouquetSpeciesForecast = [];
+ $goals = $this->calculateFullGoalChain($filters);
+ $noHistoryProductData = $this->calculateSpeciesForecastForProductsWithoutHistory($filters['plan_date'], $filters);
+ $historyProductData = $this->calculateSpeciesForecastForProductsWithHistory($filters['plan_date'], $filters, $goals);
+ $matrixForecast = MatrixBouquetForecast::find()
+ ->where(['year' => $filters['year'], 'month' => $filters['month']])
+ ->asArray()
+ ->all();
+ $matrixGroups = array_unique(ArrayHelper::getColumn($matrixForecast, 'group'));
+ $bouquetForecast = StorePlanService::getBouquetSpiecesMonthGoalFromForecast($filters['month'], $filters['year'], $filters['store_id'], $matrixGroups);
+ $speciesData = $bouquetForecast['final'];
+ foreach ($speciesData as $store_id => $categoryData) {
+ foreach ($categoryData as $category => $subcategoryData) {
+ foreach ($subcategoryData as $subcategory => $species) {
+ foreach ($species as $speciesInd => $row) {
+ $bouquetSpeciesForecast[] = [
+ 'category' => $category,
+ 'subcategory' => $subcategory,
+ 'store_id' => $store_id,
+ 'species' => $speciesInd,
+ 'goal' => $row
+ ];
+ }
+ }
+ }
+
+ }
+ $cleanedSpeciesGoals = $this->subtractSpeciesGoals($goals, $bouquetSpeciesForecast, $noHistoryProductData);
+
+ $salesProductForecastShare = $this->calculateProductForecastShare($noHistoryProductData, $historyProductData);
+
+ $productForecastSpecies = $this->calculateProductSalesBySpecies($salesProductForecastShare, $cleanedSpeciesGoals);
+
+ $weeklySales = $this->getHistoricalSpeciesShareByWeek($filters['plan_date'], $filters);
+
+ $weeklySalesForecast = $this->calculateWeeklyProductForecastPieces($productForecastSpecies, $weeklySales);
+
+ return $weeklySalesForecast;
+ }
+
+
}
\ No newline at end of file