use PhpOffice\PhpSpreadsheet\IOFactory;
use Yii;
use yii\base\DynamicModel;
+use yii\data\ActiveDataProvider;
use yii\data\ArrayDataProvider;
use yii\db\Expression;
use yii\filters\AccessControl;
CityStore,
CityStoreParams,
Files,
+ MatrixBouquetForecast,
MatrixType,
PricesDynamic,
Products1c,
$model = new DynamicModel(['excelFile']);
$model->addRule('excelFile', 'file', ['extensions' => ['xls', 'xlsx'], 'skipOnEmpty' => false]);
- $data = [];
-
if (Yii::$app->request->isPost) {
$model->excelFile = UploadedFile::getInstance($model, 'excelFile');
$model->excelFile->saveAs($filePath);
$spreadsheet = IOFactory::load($filePath);
- $rows = $spreadsheet->getActiveSheet()->toArray();
-
- $names = array_filter(array_column($rows, 2));
-
- $products = Products1c::find()
- ->select(['id', 'name'])
- ->where(['name' => $names])
- ->asArray()
- ->all();
-
- $data = $products;
- //var_dump($products); die();
- Yii::$app->session->set('productExportData', $data);
+ $rows = $spreadsheet->getActiveSheet()->toArray(null, true, true, true);
+
+ $header = array_shift($rows);
+ foreach ($rows as $row) {
+ $group = trim($row['B']);
+ $name = trim($row['C']);
+ $month = strtolower(trim($row['D']));
+ $year = (int) date('Y');
+
+ $newValues = [
+ 's_store' => (int)$row['E'],
+ 'm_store' => (int)$row['F'],
+ 'l_store' => (int)$row['G'],
+ 'xl_store' => (int)$row['H'],
+ 'marketplace' => (int)$row['I'],
+ 'internet' => (int)$row['J'],
+ ];
+
+ $forecast = MatrixBouquetForecast::find()
+ ->where([
+ 'bouquet_name' => $name,
+ 'bouquet_group' => $group,
+ 'year' => $year,
+ 'month' => $month,
+ ])
+ ->one();
+
+ if ($forecast) {
+ $changed = false;
+ foreach ($newValues as $field => $value) {
+ if ((int)$forecast->$field !== $value) {
+ $forecast->$field = $value;
+ $changed = true;
+ }
+ }
+
+ if ($changed) {
+ $forecast->updated_at = date('Y-m-d H:i:s');
+ if (!$forecast->save()) {
+ Yii::error("Ошибка обновления прогноза: " . json_encode($forecast->getErrors()), __METHOD__);
+ }
+ }
+ } else {
+ $forecast = new MatrixBouquetForecast();
+ $forecast->bouquet_name = $name;
+ $forecast->bouquet_group = $group;
+ $forecast->year = $year;
+ $forecast->month = $month;
+ $forecast->created_at = date('Y-m-d H:i:s');
+ $forecast->updated_at = date('Y-m-d H:i:s');
+
+ $product = Products1c::find()->select(['id'])->where(['name' => $name])->one();
+ $forecast->bouquet_id = $product ? $product->id : null;
+
+ foreach ($newValues as $field => $value) {
+ $forecast->$field = $value;
+ }
+
+ if (!$forecast->save()) {
+ Yii::error("Ошибка создания прогноза: " . json_encode($forecast->getErrors()), __METHOD__);
+ }
+ }
+ }
+
+ Yii::$app->session->setFlash('success', 'Импорт завершён: записи добавлены или обновлены.');
}
}
- $provider = new ArrayDataProvider([
- 'allModels' => $data,
- 'pagination' => false,
+ $dataProvider = new ActiveDataProvider([
+ 'query' => MatrixBouquetForecast::find()->orderBy(['id' => SORT_ASC]),
+ 'pagination' => ['pageSize' => 200],
]);
return $this->render('get-guid-bouquet', [
'model' => $model,
- 'provider' => $provider,
+ 'dataProvider' => $dataProvider,
]);
}
if (!isset($tableSchema)) {
$this->createTable(self::TABLE_NAME, [
'id' => $this->primaryKey(),
- 'bouquet_id' => $this->integer()->comment('ИД букета'),
+ 'bouquet_id' => $this->string()->comment('ИД букета'),
'bouquet_name' => $this->string()->comment('Наименование букета'),
'bouquet_group' => $this->string()->comment('Матрица букета'),
'year' => $this->integer()->comment('Год'),
* This is the model class for table "matrix_bouquet_forecast".
*
* @property int $id
- * @property int|null $bouquet_id ИД букета
+ * @property string|null $bouquet_id ИД букета
* @property string|null $bouquet_name Наименование букета
* @property string|null $bouquet_group Матрица букета
* @property int|null $year Год
{
return [
[['bouquet_id', 'bouquet_name', 'bouquet_group', 'year', 'month', 's_store', 'm_store', 'l_store', 'xl_store', 'marketplace', 'internet', 'created_at', 'updated_at'], 'default', 'value' => null],
- [['bouquet_id', 'year', 'month', 's_store', 'm_store', 'l_store', 'xl_store', 'marketplace', 'internet'], 'default', 'value' => null],
- [['bouquet_id', 'year', 'month', 's_store', 'm_store', 'l_store', 'xl_store', 'marketplace', 'internet'], 'integer'],
+ [['year', 'month', 's_store', 'm_store', 'l_store', 'xl_store', 'marketplace', 'internet'], 'default', 'value' => null],
+ [['year', 'month', 's_store', 'm_store', 'l_store', 'xl_store', 'marketplace', 'internet'], 'integer'],
[['created_at', 'updated_at'], 'safe'],
- [['bouquet_name', 'bouquet_group'], 'string', 'max' => 255],
+ [['bouquet_id', 'bouquet_name', 'bouquet_group'], 'string', 'max' => 255],
];
}
use yii_app\records\BouquetForecast;
use yii_app\records\CityStore;
use yii_app\records\CityStoreParams;
+use yii_app\records\MatrixBouquetForecast;
use yii_app\records\Motivation;
use yii_app\records\PricesDynamic;
use yii_app\records\Products1cAdditionalCharacteristics;
}
+ public static function getBouquetSpiecesMonthGoalFromForecast($month, $year)
+ {
+ $stores = ArrayHelper::map(
+ CityStore::find()
+ ->select(['id'])
+ ->where(['visible' => CityStore::IS_VISIBLE])
+ ->asArray()
+ ->all(),
+ 'id',
+ 'id'
+ );
+
+ $storesParams = ArrayHelper::map(
+ CityStoreParams::find()
+ ->select(['store_id', 'address_region'])
+ ->where(['store_id' => array_keys($stores)])
+ ->andWhere(['not', ['address_region' => '']])
+ ->asArray()
+ ->indexBy('store_id')
+ ->all(),
+ 'store_id',
+ 'address_region'
+ );
+
+ // Все прогнозы на месяц
+ $forecasts = MatrixBouquetForecast::find()
+ ->where(['year' => $year, 'month' => $month])
+ ->andWhere(['not', ['bouquet_id' => null]])
+ ->asArray()
+ ->all();
+
+ $resultData = [];
+ $debugData = [];
+
+ foreach ($forecasts as $forecast) {
+ $products = [];
+
+ $product = Products1c::find()
+ ->select(['components'])
+ ->where(['id' => $forecast['bouquet_id']])
+ ->asArray()
+ ->one();
+
+ if ($product && !empty($product['components'])) {
+ $components = json_decode($product['components'], true);
+ if (is_array($components)) {
+ foreach ($components as $productId => $count) {
+ $products[] = [
+ 'product_guid' => $productId,
+ 'count' => (int)$count,
+ ];
+ }
+ }
+ }
+
+ $productGuids = array_filter(array_column($products, 'product_guid'));
+
+ $types = [
+ 's_store' => 'offline',
+ 'm_store' => 'offline',
+ 'l_store' => 'offline',
+ 'xl_store' => 'offline',
+ 'marketplace' => 'marketplace',
+ 'internet' => 'internet'
+ ];
+
+ foreach ($types as $field => $typeSales) {
+ $typeSalesValue = (int)$forecast[$field];
+ if ($typeSalesValue <= 0) {
+ continue;
+ }
+
+ foreach ($storesParams as $storeId => $regionId) {
+ $pricesData = ArrayHelper::map(
+ PricesDynamic::find()
+ ->where(['product_id' => $productGuids])
+ ->andWhere(['active' => 1])
+ ->andWhere(['region_id' => $regionId])
+ ->select(['price', 'product_id'])
+ ->asArray()
+ ->all(),
+ 'product_id',
+ 'price'
+ );
+
+ foreach ($products as $product) {
+ $productModel = Products1cNomenclature::findOne($product['product_guid']);
+ $species = $productModel?->species ?? 'Неизвестно';
+ $basePrice = $pricesData[$product['product_guid']] ?? 0;
+ $rawCalculation = $basePrice * $product['count'] * $typeSalesValue;
+ $productCost = round($rawCalculation * 1.15, 2);
+
+ if (!isset($resultData[$storeId][$species][$typeSales])) {
+ $resultData[$storeId][$species][$typeSales] = 0;
+ }
+ $resultData[$storeId][$species][$typeSales] += $productCost;
+
+ $debugData[$storeId][$species][$typeSales][] = [
+ 'product_guid' => $product['product_guid'],
+ 'price' => $basePrice,
+ 'count' => $product['count'],
+ 'forecast' => $typeSalesValue,
+ 'bouquet_id' => $forecast['bouquet_id'],
+ 'raw_calculation' => $rawCalculation,
+ 'rounded' => $productCost,
+ ];
+ }
+ }
+ }
+ }
+
+ $finalResult = [];
+ foreach ($resultData as $storeId => $speciesData) {
+ foreach ($speciesData as $species => $salesData) {
+ $finalResult[$storeId][$species] = round(array_sum($salesData), 2);
+ }
+ }
+
+ return [
+ 'detail' => $resultData,
+ 'final' => $finalResult,
+ 'debug' => $debugData
+ ];
+ }
+
+
}
use kartik\grid\GridView;
/** @var yii\web\View $this */
-/** @var yii\base\DynamicModel $model */
-/** @var yii\data\ArrayDataProvider $provider */
+/** @var yii\data\ActiveDataProvider $dataProvider */
+/** @var \yii\base\DynamicModel $model */
-$this->title = 'Импорт товаров из Excel';
+$this->title = 'Импорт прогноза по букетам';
?>
-
+<div class="get-bouquet-guid p-4">
<h1><?= Html::encode($this->title) ?></h1>
-<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
+<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); ?>
<?= $form->field($model, 'excelFile')->fileInput() ?>
<div class="form-group">
- <?= Html::submitButton('Загрузить', ['class' => 'btn btn-primary']) ?>
+ <?= Html::submitButton('Загрузить', ['class' => 'btn btn-success']) ?>
</div>
-<?php ActiveForm::end() ?>
+<?php ActiveForm::end(); ?>
-<?php if ($provider->getCount()): ?>
- <h2>Результаты поиска</h2>
+<?php if (!empty($dataProvider)): ?>
<?= GridView::widget([
- 'dataProvider' => $provider,
+ 'dataProvider' => $dataProvider,
'columns' => [
- ['class' => 'yii\grid\SerialColumn'],
'id',
- 'name',
+ 'bouquet_id',
+ [
+ 'attribute' => 'bouquet_group',
+ 'label' => 'Группа букета',
+ ],
+ [
+ 'attribute' => 'bouquet_name',
+ 'label' => 'Название букета',
+ ],
+ 'year',
+ 'month',
+ 's_store',
+ 'm_store',
+ 'l_store',
+ 'xl_store',
+ 'marketplace',
+ 'internet',
],
]) ?>
+<?php endif; ?>
- <?= Html::a('📥 Скачать найденные товары', ['download'], ['class' => 'btn btn-success']) ?>
-<?php endif; ?>
\ No newline at end of file
+</div>