return $enablePlanAdd;
}
- public static function calculateHistoricalShare($storeId, $selectedMonth, $category, $subcategory = null, $species = null)
+ /**
+ * Рассчитывает недельные продажи товаров за 3 предыдущих месяца относительно переданного месяца и года
+ * для конкретного магазина и фильтрации по категориям/подкатегориям/видам.
+ *
+ * @param int $storeId ID магазина.
+ * @param string $selectedMonth Месяц в формате "01" - "12".
+ * @param string $selectedYear Год в формате "YYYY".
+ * @param string $category Категория товаров.
+ * @param string|null $subcategory Подкатегория товаров (опционально).
+ * @param string|null $species Вид товаров (опционально).
+ *
+ * @return array [
+ * 'with_history' => [ // товары, у которых есть данные по продажам во всех периодах и активности минимум в 2 недели каждого периода.
+ * [
+ * 'guid' => string, // идентификатор товара.
+ * 'weekly_sales' => [ // продажи по неделям для каждого периода.
+ * '2025-01' => [int, int, ...],
+ * '2024-12' => [int, int, ...],
+ * '2024-11' => [int, int, ...],
+ * ]
+ * ],
+ * ...
+ * ],
+ * 'without_history' => [ // товары с неполными данными по истории продаж.
+ * // Структура аналогична.
+ * ]
+ * ]
+ */
+ public static function calculateHistoricalShare($storeId, $selectedMonth, $selectedYear, $category, $subcategory = null, $species = null)
+ {
+ $baseDate = strtotime("{$selectedYear}-{$selectedMonth}-01");
+
+ // Получаем периоды за 3 предыдущих месяца.
+ $periods = self::getPeriods($baseDate, 3);
+
+ // Получаем историю продаж для каждого периода.
+ $salesHistory = self::getSalesHistory($storeId, $periods, $category, $subcategory, $species);
+
+ // Анализируем и разделяем товары по наличию полноценной истории продаж.
+ return self::analyzeHistory($salesHistory, $periods);
+ }
+
+ /**
+ * Формирует периоды (месяц + недели) за заданное количество предыдущих месяцев от базовой даты.
+ *
+ * @param int $baseDate Timestamp базовой даты.
+ * @param int $count Количество периодов для получения (по умолчанию 3).
+ *
+ * @return array Массив периодов с ключами вида "YYYY-MM".
+ */
+ private static function getPeriods($baseDate, $count = 3)
{
- $currentTimestamp = time();
- $year = date('Y', $currentTimestamp);
$periods = [];
- for ($i = 1; $i <= 3; $i++) {
- $prevTimestamp = strtotime("-{$i} month", $currentTimestamp);
- $month = date('m', $prevTimestamp);
- $periods[$month] = [];
- }
- //var_dump($periods); die();
- foreach ($periods as $monthKey => $month) {
- $days = cal_days_in_month(CAL_GREGORIAN, (int)$monthKey, (int)$year);
- $weeks = $days > 28 ? 5 : 4;
- for ($weekNumber = 1; $weekNumber <= $weeks; $weekNumber++) {
- $range = Motivation::getWeekRange(null, $weekNumber, (int)$monthKey, $year);
- $periods[$monthKey][$weekNumber - 1] = $range;
+ for ($i = $count; $i >= 1; $i--) {
+ $timestamp = strtotime("-{$i} month", $baseDate);
+ $month = date('m', $timestamp);
+ $year = date('Y', $timestamp);
+
+ $periodKey = "{$year}-{$month}";
+ $periods[$periodKey] = [
+ 'year' => $year,
+ 'month' => $month,
+ 'weeks' => [],
+ ];
+
+ $daysInMonth = cal_days_in_month(CAL_GREGORIAN, (int)$month, (int)$year);
+ $weeksCount = $daysInMonth > 28 ? 5 : 4;
+
+ for ($weekNumber = 1; $weekNumber <= $weeksCount; $weekNumber++) {
+ $range = Motivation::getWeekRange(null, $weekNumber, (int)$month, (int)$year);
+ $periods[$periodKey]['weeks'][$weekNumber - 1] = $range;
}
}
- // var_dump($periods); die();
+
+ return $periods;
+ }
+
+ /**
+ * Получает историю продаж за каждый период по неделям.
+ *
+ * @param int $storeId
+ * @param array $periods Массив периодов, сформированный функцией getPeriods.
+ * @param string $category
+ * @param string|null $subcategory
+ * @param string|null $species
+ *
+ * @return array Структура данных:
+ * [
+ * 'product_guid1' => [
+ * 'YYYY-MM' => [
+ * 0 => salesCount_week1,
+ * 1 => salesCount_week2,
+ * ...
+ * ],
+ * ...
+ * ],
+ * ...
+ * ]
+ */
+ private static function getSalesHistory($storeId, $periods, $category, $subcategory, $species)
+ {
$salesHistory = [];
- foreach ($periods as $monthKey => $weeks) {
- foreach ($weeks as $weekIndex => $week) {
+ foreach ($periods as $periodKey => $periodData) {
+ $year = $periodData['year'];
+ $month = $periodData['month'];
+
+ foreach ($periodData['weeks'] as $weekIndex => $week) {
$dateStart = $week['start_time'] . ' 00:00:00';
- $dateEnd = $week['end_time'] . ' 23:59:59';
+ $dateEnd = $week['end_time'] . ' 23:59:59';
$query = Sales::find()->alias('s')
->select([
->innerJoin('products_1c_nomenclature p1c', 'p1c.id = sp.product_id')
->where(['s.store_id' => $storeId])
->andWhere(['between', 's.date', $dateStart, $dateEnd])
- // Условие для чеков: order_id равен '' или '0'
->andWhere(['order_id' => ['', '0']])
->andWhere(['p1c.category' => $category]);
$query->groupBy('p1c.id');
$results = $query->asArray()->all();
-
foreach ($results as $result) {
$guid = $result['product_guid'];
if (!isset($salesHistory[$guid])) {
$salesHistory[$guid] = [];
}
- if (!isset($salesHistory[$guid][$monthKey])) {
- $salesHistory[$guid][$monthKey] = [];
+ if (!isset($salesHistory[$guid][$periodKey])) {
+ $salesHistory[$guid][$periodKey] = [];
}
- $salesHistory[$guid][$monthKey][$weekIndex] = (int)$result['sales_count'];
+ $salesHistory[$guid][$periodKey][$weekIndex] = (int)$result['sales_count'];
}
}
}
- $productsWithHistory = [];
+
+ return $salesHistory;
+ }
+
+ /**
+ * Анализирует историю продаж, разделяя товары на группы:
+ * - с историей продаж во всех периодах (активность не менее 2-х недель в каждом периоде),
+ * - без полноценной истории продаж.
+ *
+ * @param array $salesHistory Структура продаж, сформированная функцией getSalesHistory.
+ * @param array $periods Массив периодов, полученный функцией getPeriods.
+ *
+ * @return array [
+ * 'with_history' => [...],
+ * 'without_history' => [...],
+ * ]
+ */
+ private static function analyzeHistory($salesHistory, $periods)
+ {
+ $productsWithHistory = [];
$productsWithoutHistory = [];
foreach ($salesHistory as $guid => $monthsData) {
- $hasHistoryInAllMonths = true;
+ $hasHistoryInAllPeriods = true;
$weeklySalesData = [];
- foreach ($periods as $monthKey => $monthData) {
- if (!isset($monthsData[$monthKey])) {
- $hasHistoryInAllMonths = false;
- $weekData = [0, 0, 0, 0];
+ foreach ($periods as $periodKey => $periodData) {
+ $weeksCount = count($periodData['weeks']);
+ $checkWeeksCount = min(4, $weeksCount);
+
+ if (!isset($monthsData[$periodKey])) {
+ $hasHistoryInAllPeriods = false;
+ $weekData = array_fill(0, $weeksCount, 0);
} else {
$weekData = [];
$activeWeeks = 0;
- for ($weekIndex = 0; $weekIndex < 5; $weekIndex++) {
- $salesCount = isset($monthsData[$monthKey][$weekIndex]) ? $monthsData[$monthKey][$weekIndex] : 0;
+ for ($weekIndex = 0; $weekIndex < $checkWeeksCount; $weekIndex++) {
+ $salesCount = isset($monthsData[$periodKey][$weekIndex]) ? $monthsData[$periodKey][$weekIndex] : 0;
$weekData[$weekIndex] = $salesCount;
if ($salesCount > 0) {
$activeWeeks++;
}
}
if ($activeWeeks < 2) {
- $hasHistoryInAllMonths = false;
+ $hasHistoryInAllPeriods = false;
}
}
- $weeklySalesData[$monthKey] = $weekData;
+ $weeklySalesData[$periodKey] = $weekData;
}
$productData = [
- 'guid' => $guid,
+ 'guid' => $guid,
'weekly_sales' => $weeklySalesData,
];
- if ($hasHistoryInAllMonths) {
+ if ($hasHistoryInAllPeriods) {
$productsWithHistory[] = $productData;
} else {
$productsWithoutHistory[] = $productData;
}
return [
- 'with_history' => $productsWithHistory,
+ 'with_history' => $productsWithHistory,
'without_history' => $productsWithoutHistory,
];
}
/**
* Метод вычисляет взвешенное значение продаж для товаров без истории.
*
- * @param int $storeId Идентификатор магазина.
- * @param string $selectedMonth Выбранный месяц в формате "mm" (целевой месяц).
+ * @param int $storeId Идентификатор магазина.
+ * @param string $selectedMonth Выбранный месяц в формате "mm" (целевой месяц).
* @param array $productsWithoutHistory Массив товаров без истории, где каждый элемент имеет вид:
* [
* 'guid' => <GUID товара>,
- * 'weekly_sales' => [ 'YYYY-mm' => [ ... ], ... ]
+ * 'weekly_sales' => [ 'YYYY-MM' => [ ... ], ... ]
* ]
+ *
* @return array Возвращает массив, где ключ – GUID товара, а значение – рассчитанное взвешенное значение продаж.
*/
public static function calculateWeightedSalesForProductsWithoutHistory($storeId, $selectedMonth, $productsWithoutHistory)
{
-
- $year = date('Y');
- $targetDate = strtotime("$year-$selectedMonth-01");
-
- $months = [];
- for ($i = 1; $i <= 3; $i++) {
- $monthTimestamp = strtotime("-{$i} month", $targetDate);
- $m = date('m', $monthTimestamp);
- $y = date('Y', $monthTimestamp);
- $months[] = ['year' => $y, 'month' => $m];
- }
+ $targetDate = strtotime(date('Y') . "-$selectedMonth-01");
+ $periods = self::generateWeightedPeriods($targetDate, 3);
$weightedResults = [];
foreach ($productsWithoutHistory as $product) {
$guid = $product['guid'];
- //var_dump( $guid); die();
- $myChars = Products1cAdditionalCharacteristics::find()
- ->where(['product_id' => $guid])
- ->asArray()
- ->all();
-
- $mySet = [];
- foreach ($myChars as $char) {
- $mySet[$char['property_id']] = $char['value'];
- }
- ksort($mySet);
- // var_dump($mySet); die();
- $countChars = count($mySet);
- // var_dump($countChars); die();
- if ($countChars == 0) {
- $weightedResults[$guid] = 0;
- continue;
- }
- $conditions = [];
- foreach ($mySet as $propId => $val) {
- $conditions[] = [$propId, $val];
- }
- $query = Products1cAdditionalCharacteristics::find()
- ->select('product_id')
- ->where(new \yii\db\Expression('(property_id, value) IN (' . implode(', ', array_map(function($pair) {
- return "('" . implode("','", $pair) . "')";
- }, $conditions)) . ')'))
- ->groupBy('product_id')
- ->having('COUNT(*) = :cnt', [':cnt' => $countChars]);
-
- $similarProductIds = $query->column();
- // var_dump($similarProductIds); die();
+ $similarProductIds = self::getSimilarProductIDs($guid);
if (empty($similarProductIds)) {
$weightedResults[$guid] = 0;
continue;
$medianSales = [];
$salesValuesForEachMonth = [];
- foreach ($months as $monthInfo) {
- $startDate = sprintf('%04d-%02d-01', $monthInfo['year'], $monthInfo['month']);
- $endDate = sprintf('%04d-%02d-%02d',
- $monthInfo['year'],
- $monthInfo['month'],
- cal_days_in_month(CAL_GREGORIAN, $monthInfo['month'], $monthInfo['year']));
-
- $salesValues = [];
-
- foreach ($similarProductIds as $simProdId) {
- $sales = Sales::find()->alias('s')
- ->innerJoin('sales_products sp', 's.id = sp.check_id')
- ->innerJoin('products_1c_nomenclature p1c', 'p1c.id = sp.product_id')
- ->where(['p1c.id' => $simProdId])
- ->andWhere(['s.store_id' => $storeId])
- ->andWhere(['between', 's.date', $startDate . ' 00:00:00', $endDate . ' 23:59:59'])
- // Условие для чеков: order_id равен '' или '0'
- ->andWhere(['order_id' => ['', '0']])
- ->count();
- $salesValues[] = (int)$sales;
- }
- $salesValuesForEachMonth[] = $salesValues;
- $nonZeroSales = array_filter($salesValues, function($val) {
- return $val > 0;
- });
- sort($nonZeroSales, SORT_NUMERIC);
- $n = count($nonZeroSales);
- if ($n === 0) {
- $median = 0;
- } elseif ($n % 2 == 1) {
- $median = $nonZeroSales[floor($n / 2)];
- } else {
- $median = ($nonZeroSales[$n / 2 - 1] + $nonZeroSales[$n / 2]) / 2;
- }
- $medianSales[] = $median;
+ foreach ($periods as $periodKey => $monthInfo) {
+ list($median, $salesValues) = self::calculateMedianSalesForPeriod($storeId, $similarProductIds, $monthInfo);
+ $medianSales[$periodKey] = $median;
+ $salesValuesForEachMonth[$periodKey] = $salesValues;
}
$weights = [3, 2, 1];
- $weightedValue = 0;
- for ($i = 0; $i < count($medianSales); $i++) {
- $weightedValue += $medianSales[$i] * $weights[$i];
- }
+ $weightedValue = self::computeWeightedValue($medianSales, $weights);
+
$weightedResults[$guid] = [
'weightedValue' => $weightedValue,
'medianSales' => $medianSales,
'salesValues' => $salesValuesForEachMonth,
];
}
+
return $weightedResults;
}
+ /**
+ * Генерирует периоды для расчёта продаж.
+ *
+ * @param int $targetDate Timestamp целевой даты.
+ * @param int $count Количество предыдущих месяцев.
+ * @param bool $withWeight Если true – к каждому периоду добавляется вес (ключ 'weight').
+ *
+ * @return array Ассоциативный массив, где ключ – "YYYY-MM", а значение – массив с ключами 'year', 'month'
+ * и, если $withWeight равен true, 'weight'.
+ */
+ private static function generateWeightedPeriods($targetDate, $count = 3, $withWeight = false)
+ {
+ $periods = [];
+ for ($i = 1; $i <= $count; $i++) {
+ $timestamp = strtotime("-{$i} month", $targetDate);
+ $year = date('Y', $timestamp);
+ $month = date('m', $timestamp);
+ $periodKey = sprintf('%04d-%02d', $year, $month);
+
+ $periodData = [
+ 'year' => $year,
+ 'month' => $month,
+ ];
+
+ if ($withWeight) {
+ // Вес рассчитывается как 4 - $i, то есть для ближайшего месяца – вес 3, затем 2 и 1.
+ $periodData['weight'] = 4 - $i;
+ }
+
+ $periods[$periodKey] = $periodData;
+ }
+ return $periods;
+ }
+
+ /**
+ * Получает идентификаторы товаров, похожих на указанный товар,
+ * исходя из набора его дополнительных характеристик.
+ *
+ * @param string $guid Идентификатор товара.
+ *
+ * @return array Массив идентификаторов похожих товаров.
+ */
+ private static function getSimilarProductIDs($guid)
+ {
+ $myChars = Products1cAdditionalCharacteristics::find()
+ ->where(['product_id' => $guid])
+ ->asArray()
+ ->all();
+
+ $mySet = [];
+ foreach ($myChars as $char) {
+ $mySet[$char['property_id']] = $char['value'];
+ }
+ ksort($mySet);
+ $countChars = count($mySet);
+ if ($countChars === 0) {
+ return [];
+ }
+
+ $conditions = [];
+ foreach ($mySet as $propId => $val) {
+ $conditions[] = [$propId, $val];
+ }
+ $query = Products1cAdditionalCharacteristics::find()
+ ->select('product_id')
+ ->where(new \yii\db\Expression('(property_id, value) IN (' .
+ implode(', ', array_map(function($pair) {
+ return "('" . implode("','", $pair) . "')";
+ }, $conditions)) . ')'))
+ ->groupBy('product_id')
+ ->having('COUNT(*) = :cnt', [':cnt' => $countChars]);
+
+ return $query->column();
+ }
+
+ /**
+ * Вычисляет медианное значение продаж для похожих товаров в заданном периоде.
+ *
+ * @param int $storeId Идентификатор магазина.
+ * @param array $similarProductIds Массив идентификаторов похожих товаров.
+ * @param array $monthInfo Массив с ключами 'year' и 'month'.
+ *
+ * @return array Возвращает массив: [медианное значение продаж, массив продаж по каждому товару]
+ */
+ private static function calculateMedianSalesForPeriod($storeId, $similarProductIds, $monthInfo)
+ {
+ $startDate = sprintf('%04d-%02d-01', $monthInfo['year'], $monthInfo['month']);
+ $endDate = sprintf('%04d-%02d-%02d',
+ $monthInfo['year'],
+ $monthInfo['month'],
+ cal_days_in_month(CAL_GREGORIAN, $monthInfo['month'], $monthInfo['year']));
+
+ $salesValues = [];
+
+ foreach ($similarProductIds as $simProdId) {
+ $sales = Sales::find()->alias('s')
+ ->innerJoin('sales_products sp', 's.id = sp.check_id')
+ ->innerJoin('products_1c_nomenclature p1c', 'p1c.id = sp.product_id')
+ ->where(['p1c.id' => $simProdId])
+ ->andWhere(['s.store_id' => $storeId])
+ ->andWhere(['between', 's.date', $startDate . ' 00:00:00', $endDate . ' 23:59:59'])
+ ->andWhere(['order_id' => ['', '0']])
+ ->count();
+ $salesValues[] = (int)$sales;
+ }
+
+ $nonZeroSales = array_filter($salesValues, function($val) {
+ return $val > 0;
+ });
+ sort($nonZeroSales, SORT_NUMERIC);
+ $n = count($nonZeroSales);
+ if ($n === 0) {
+ $median = 0;
+ } elseif ($n % 2 === 1) {
+ $median = $nonZeroSales[floor($n / 2)];
+ } else {
+ $median = ($nonZeroSales[$n / 2 - 1] + $nonZeroSales[$n / 2]) / 2;
+ }
+
+ return [$median, $salesValues];
+ }
+
+ /**
+ * Вычисляет взвешенное значение на основании медианных продаж по периодам.
+ *
+ * @param array $medianSales Ассоциативный массив медианных продаж, ключи – периоды ("YYYY-MM").
+ * @param array $weights Массив весов (порядок должен соответствовать порядку перебора медианных продаж).
+ *
+ * @return float Взвешенное значение.
+ */
+ private static function computeWeightedValue($medianSales, $weights)
+ {
+ $weightedValue = 0;
+ $i = 0;
+ foreach ($medianSales as $periodKey => $median) {
+ if (isset($weights[$i])) {
+ $weightedValue += $median * $weights[$i];
+ }
+ $i++;
+ }
+ return $weightedValue;
+ }
+
/**
* Получает цену для товара для указанного месяца.
*
['>=', 'date_to', $monthStart],
['date_to' => '2100-01-01 03:00:00+03']
])->all();
+
+
if (CityStore::find()->where(['id' => $storeId])->one()->city_id == 1342) {
$region = 52;
} elseif (CityStore::find()->where(['id' => $storeId])->one()->city_id == 1) {
} else {
$region = null;
}
-
//$priceRecords->andWhere(['or',['region_id' => $region],['region_id' => null]])
//->all();
-
if (!empty($priceRecords)) {
$totalPrice = 0;
$count = 0;
$averagePrice = 0;
}
-
return $averagePrice;
}
+
/**
* Вычисляет для каждого товара с историей:
* - месячные продажи (сумма недельных продаж за месяц),
* - итоговую взвешенную сумму,
* - долю товара от общей взвешенной суммы по всем товарам.
*
- * @param int $storeId Идентификатор магазина.
- * @param string $selectedMonth Целевой месяц в формате "mm".
- * @param array $productsWithHistory Массив товаров с историей (из calculateHistoricalShare), каждый элемент содержит:
- * [
+ * @param int $storeId Идентификатор магазина.
+ * @param string $selectedMonth Целевой месяц в формате "mm".
+ * @param array $productsWithHistory Массив товаров с историей, где каждый элемент имеет вид:
+ * [
* 'guid' => <GUID товара>,
- * 'weekly_sales' => [ 'mm' => [week0, week1, week2, week3], ... ]
- * ]
+ * 'weekly_sales' => [ 'YYYY-MM' => [ ... ], ... ]
+ * ]
+ *
* @return array Массив, где ключ – GUID товара, а значение – массив с данными:
* [
- * 'monthlySales' => [ 'mm' => суммарные продажи за месяц, ... ],
- * 'monthlyWeighted' => [ 'mm' => (продажи * цена * вес), ... ],
+ * 'monthlySales' => [ 'YYYY-MM' => суммарные продажи за месяц, ... ],
+ * 'monthlyWeighted' => [ 'YYYY-MM' => (продажи * цена * вес), ... ],
* 'weightedSum' => итоговая взвешенная сумма,
- * 'share' => доля товара (от 0 до 1)
+ * 'share' => доля товара (от 0 до 1),
+ * 'monthlyPrice' => [ 'YYYY-MM' => цена ]
* ]
*/
public static function calculateProductSalesShare($storeId, $selectedMonth, $productsWithHistory)
{
- $year = date('Y');
-
+ $targetDate = strtotime(date('Y') . "-$selectedMonth-01");
- $weightedMonths = [];
- for ($i = 1; $i <= 3; $i++) {
- $timestamp = strtotime("-{$i} month", strtotime("$year-$selectedMonth-01"));
- $weightedMonths[] = [
- 'year' => date('Y', $timestamp),
- 'month' => date('m', $timestamp),
- 'weight' => 4 - $i,
- ];
- }
+ $weightedPeriods = self::generateWeightedPeriods($targetDate, 3, true);
$productsData = [];
$globalTotal = 0;
-
foreach ($productsWithHistory as $product) {
$guid = $product['guid'];
- $monthlySales = [];
- $monthlyWeighted = [];
- $weightedSum = 0;
- $monthlyPrice = [];
-
- foreach ($weightedMonths as $mInfo) {
- $mKey = $mInfo['month'];
- $sales = isset($product['weekly_sales'][$mKey]) ? array_sum($product['weekly_sales'][$mKey]) : 0;
-
- $price = self::getPriceForProductAndMonth($guid, $mInfo['year'], $mInfo['month'], $storeId);
- $monthlySales[$mKey] = $sales;
- $weightedValue = $sales * $price * $mInfo['weight'];
- $monthlyWeighted[$mKey] = $weightedValue;
- $monthlyPrice[$mKey] = $price;
- $weightedSum += $weightedValue;
- }
- $productsData[$guid] = [
- 'monthlySales' => $monthlySales,
- 'monthlyWeighted' => $monthlyWeighted,
- 'weightedSum' => $weightedSum,
- 'monthlyPrice' => $monthlyPrice,
- ];
- $globalTotal += $weightedSum;
+ $result = self::processProductWithHistory($storeId, $product, $weightedPeriods);
+ $productsData[$guid] = $result;
+ $globalTotal += $result['weightedSum'];
}
foreach ($productsData as $guid => &$data) {
return $productsData;
}
+
+
+ /**
+ * Обрабатывает товар с историей, вычисляя для него:
+ * - месячные продажи,
+ * - взвешенные продажи (с учетом цены и заданного веса),
+ * - итоговую взвешенную сумму.
+ *
+ * @param int $storeId Идентификатор магазина.
+ * @param array $product Массив с данными товара, содержащий 'guid' и 'weekly_sales' с ключами "YYYY-MM".
+ * @param array $weightedPeriods Ассоциативный массив периодов, с ключами "YYYY-MM" и весами.
+ *
+ * @return array Массив с ключами:
+ * - monthlySales: [ 'YYYY-MM' => суммарные продажи за период, ... ]
+ * - monthlyWeighted: [ 'YYYY-MM' => продажи * цена * вес, ... ]
+ * - weightedSum: итоговая сумма по взвешенным продажам,
+ * - monthlyPrice: [ 'YYYY-MM' => цена, ... ]
+ */
+ private static function processProductWithHistory($storeId, $product, $weightedPeriods)
+ {
+ $monthlySales = [];
+ $monthlyWeighted = [];
+ $monthlyPrice = [];
+ $weightedSum = 0;
+ $guid = $product['guid'];
+
+ foreach ($weightedPeriods as $periodKey => $periodInfo) {
+ $sales = isset($product['weekly_sales'][$periodKey])
+ ? array_sum($product['weekly_sales'][$periodKey])
+ : 0;
+ $price = self::getPriceForProductAndMonth($guid, $periodInfo['year'], $periodInfo['month'], $storeId);
+
+ $monthlySales[$periodKey] = $sales;
+ $weightedValue = $sales * $price * $periodInfo['weight'];
+ $monthlyWeighted[$periodKey] = $weightedValue;
+ $monthlyPrice[$periodKey] = $price;
+ $weightedSum += $weightedValue;
+ }
+
+ return [
+ 'monthlySales' => $monthlySales,
+ 'monthlyWeighted' => $monthlyWeighted,
+ 'weightedSum' => $weightedSum,
+ 'monthlyPrice' => $monthlyPrice,
+ ];
+ }
+
}