From 760fd315843c74517f865316984a822e0cb5904f Mon Sep 17 00:00:00 2001 From: marina Date: Thu, 13 Feb 2025 15:20:58 +0300 Subject: [PATCH] =?utf8?q?ERP-302=20=D0=A0=D0=B5=D0=B4=D0=B0=D0=BA=D1=82?= =?utf8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B1=D1=83?= =?utf8?q?=D0=BA=D0=B5=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- erp24/controllers/BouquetController.php | 82 ++++++ ...12_drop_columns_on_bouquet_composition.php | 30 ++ ...eate_bouquet_matrix_type_history_table.php | 36 +++ erp24/records/BouquetComposition.php | 15 +- .../BouquetCompositionMatrixTypeHistory.php | 91 +++++++ erp24/views/bouquet/_form.php | 256 ++++++++++++++++++ erp24/views/bouquet/create.php | 33 +++ erp24/views/bouquet/view.php | 238 +--------------- 8 files changed, 547 insertions(+), 234 deletions(-) create mode 100644 erp24/migrations/m250213_094412_drop_columns_on_bouquet_composition.php create mode 100644 erp24/migrations/m250213_095313_create_bouquet_matrix_type_history_table.php create mode 100644 erp24/records/BouquetCompositionMatrixTypeHistory.php create mode 100644 erp24/views/bouquet/create.php diff --git a/erp24/controllers/BouquetController.php b/erp24/controllers/BouquetController.php index a53c4bcd..d9922bc7 100644 --- a/erp24/controllers/BouquetController.php +++ b/erp24/controllers/BouquetController.php @@ -10,7 +10,9 @@ use yii\helpers\Url; use yii\web\Controller; use yii\web\NotFoundHttpException; use yii\web\UploadedFile; +use yii_app\helpers\DataHelper; use yii_app\records\BouquetComposition; +use yii_app\records\BouquetCompositionMatrixTypeHistory; use yii_app\records\BouquetCompositionProducts; use yii_app\records\BouquetForecast; use yii_app\records\CityStore; @@ -30,6 +32,82 @@ class BouquetController extends Controller return $this->render('index'); } + public function actionCreate() { + $model = new BouquetComposition(); + + if (Yii::$app->request->isPost) { + $data = Yii::$app->request->post(); + $model->guid = DataHelper::createGuidMy('07'); + $model->load($data); + if ($data['matrix_type_id']) { + BouquetCompositionMatrixTypeHistory::setData($data['matrix_type_id'], $model->id); + } + if ($model->save()) { +// return $this->redirect('view', [ +// 'model' => $model, +// 'onlineStoresList' => $onlineStoresList, +// 'bouquetCompositionProducts' => $bouquetCompositionProducts, +// 'marketplaceList' => $marketplaceList, +// 'storesTypeList' => $storesTypeList, +// 'photoUrls' => $photoUrls, +// 'photoFiles' => $photoFiles, +// 'videoUrls' => $videoUrls, +// 'processUrls' => $processUrls, +// ]); + } + $month = $data['month']; + $year = $data['year']; + + $model->photo_bouquet = UploadedFile::getInstances($model, 'photo_bouquet'); + if ($model->photo_bouquet) { + Files::deleteAll(['file_type' => 'image', 'entity_id' => $model->id, 'entity' => BouquetComposition::PHOTO_BOUQUET]); + foreach ($model->photo_bouquet as $photo) { + FileService::saveUploadedFile($photo, BouquetComposition::PHOTO_BOUQUET, $model->id); + } + } + + $model->video_presentation = UploadedFile::getInstances($model, 'video_presentation'); + if ($model->video_presentation) { + Files::deleteAll(['file_type' => 'video', 'entity_id' => $model->id, 'entity' => BouquetComposition::VIDEO_PRESENTATION]); + FileService::saveUploadedFile($model->video_presentation, BouquetComposition::VIDEO_PRESENTATION, $model->id); + } + + $model->video_build_process = UploadedFile::getInstances($model, 'video_build_process'); + if ($model->video_build_process) { + Files::deleteAll(['file_type' => 'video', 'entity_id' => $model->id, 'entity' => BouquetComposition::VIDEO_BUILD_PROCESS]); + FileService::saveUploadedFile($model->video_build_process, BouquetComposition::VIDEO_BUILD_PROCESS, $model->id); + } + + + if (!empty($data['BouquetForecast']['type_sales_value'])) { + $salesData = $data['BouquetForecast']['type_sales_value']; + + if (!empty($salesData['offline'])) { + BouquetForecast::processSalesData($model->id, $year, $month, $salesData['offline'], BouquetForecast::OFFLINE_STORES); + } + + if (!empty($salesData['online'])) { + BouquetForecast::processSalesData($model->id, $year, $month, $salesData['online'], BouquetForecast::ONLINE_STORES); + } + + if (!empty($salesData['marketplace'])) { + BouquetForecast::processSalesData($model->id, $year, $month, $salesData['marketplace'], BouquetForecast::MARKETPLACE); + } + } + + } + + $storesTypeList = BouquetForecast::getStoresList(null, BouquetForecast::OFFLINE_STORES, StoreType::class, []); + $marketplaceList = BouquetForecast::getStoresList(null, BouquetForecast::MARKETPLACE, CityStore::class, ['visible' => CityStore::IS_VISIBLE]); + $onlineStoresList = BouquetForecast::getStoresList(null, BouquetForecast::ONLINE_STORES, CityStore::class, ['visible' => CityStore::IS_VISIBLE]); + + return $this->render('create', [ + 'onlineStoresList' => $onlineStoresList, + 'marketplaceList' => $marketplaceList, + 'storesTypeList' => $storesTypeList, + ]); + } + public function actionView($id) { $model = BouquetComposition::findOne($id); @@ -39,6 +117,10 @@ class BouquetController extends Controller $month = $data['month']; $year = $data['year']; + if ($data['matrix_type_id']) { + BouquetCompositionMatrixTypeHistory::setData($data['matrix_type_id'], $model->id); + } + $model->photo_bouquet = UploadedFile::getInstances($model, 'photo_bouquet'); if ($model->photo_bouquet) { Files::deleteAll(['file_type' => 'image', 'entity_id' => $id, 'entity' => BouquetComposition::PHOTO_BOUQUET]); diff --git a/erp24/migrations/m250213_094412_drop_columns_on_bouquet_composition.php b/erp24/migrations/m250213_094412_drop_columns_on_bouquet_composition.php new file mode 100644 index 00000000..2d5cb75e --- /dev/null +++ b/erp24/migrations/m250213_094412_drop_columns_on_bouquet_composition.php @@ -0,0 +1,30 @@ +dropColumn('bouquet_composition', 'photo_id'); + $this->dropColumn('bouquet_composition', 'video_id'); + $this->dropColumn('bouquet_composition', 'matrix_type_id'); + + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + $this->addColumn('bouquet_composition', 'matrix_type_id', $this->integer()->comment('ИД типа матрицы')); + $this->addColumn('bouquet_composition', 'photo_id', $this->integer()->comment('ИД фото')); + $this->addColumn('bouquet_composition', 'video_id', $this->integer()->comment('ИД видео')); + } +} diff --git a/erp24/migrations/m250213_095313_create_bouquet_matrix_type_history_table.php b/erp24/migrations/m250213_095313_create_bouquet_matrix_type_history_table.php new file mode 100644 index 00000000..e7b157bd --- /dev/null +++ b/erp24/migrations/m250213_095313_create_bouquet_matrix_type_history_table.php @@ -0,0 +1,36 @@ +createTable('{{%erp24.bouquet_composition_matrix_type_history}}', [ + 'id' => $this->primaryKey(), + 'bouquet_id' => $this->integer()->comment('Букет ИД'), + 'matrix_type_id' => $this->integer()->comment('Тип матрицы ИД'), + 'date_from' => $this->integer()->comment('Дата установки'), + 'date_to' => $this->integer()->comment('Дата изменения'), + 'is_active' => $this->boolean()->defaultValue(true)->comment('Активна ли запись'), + 'created_at' => $this->dateTime()->comment('Дата создания'), + 'updated_at' => $this->dateTime()->comment('Дата обновления'), + 'created_by' => $this->integer()->comment('ID создателя записи'), + 'updated_by' => $this->integer()->comment('ID обновителя записи'), + ]); + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + $this->dropTable('{{%erp24.bouquet_composition_matrix_type_history}}'); + } +} diff --git a/erp24/records/BouquetComposition.php b/erp24/records/BouquetComposition.php index 6f3f1672..ef0bd49a 100644 --- a/erp24/records/BouquetComposition.php +++ b/erp24/records/BouquetComposition.php @@ -15,9 +15,6 @@ use yii_app\records\BouquetCompositionProducts; * @property int $id * @property string|null $guid * @property string $name - * @property int|null $matrix_type_id - * @property int|null $photo_id - * @property int|null $video_id * @property string|null $created_at * @property string|null $updated_at * @property int|null $created_by @@ -62,7 +59,7 @@ class BouquetComposition extends ActiveRecord { return [ [['name'], 'required'], - [['matrix_type_id', 'video_id', 'created_by', 'updated_by'], 'integer'], + [['created_by', 'updated_by'], 'integer'], [['created_at', 'updated_at'], 'safe'], [['guid', 'name'], 'string', 'max' => 255], [['photo_bouquet'], 'file', 'extensions' => 'jpg, jpeg, png, gif', 'maxFiles' => 10], @@ -76,9 +73,6 @@ class BouquetComposition extends ActiveRecord 'id' => 'ID', 'guid' => 'GUID букета', 'name' => 'Название букета', - 'matrix_type_id' => 'ИД типа матрицы', - 'photo_id' => 'ИД фото', - 'video_id' => 'ИД видео', 'created_at' => 'Дата создания', 'updated_at' => 'Дата обновления', 'created_by' => 'ID создателя записи', @@ -90,4 +84,11 @@ class BouquetComposition extends ActiveRecord { return $this->hasMany(BouquetCompositionProducts::class, ['bouquet_id' => 'id']); } + + public function getMatrixType() + { + return $this->hasMany(BouquetCompositionMatrixTypeHistory::class, ['bouquet_id' => 'id']) + ->andWhere(['is_active' => BouquetCompositionMatrixTypeHistory::IS_ACTIVE]); + } + } diff --git a/erp24/records/BouquetCompositionMatrixTypeHistory.php b/erp24/records/BouquetCompositionMatrixTypeHistory.php new file mode 100644 index 00000000..9d8e492d --- /dev/null +++ b/erp24/records/BouquetCompositionMatrixTypeHistory.php @@ -0,0 +1,91 @@ + 'ID', + 'bouquet_id' => 'Букет ИД', + 'matrix_type_id' => 'Тип матрицы ИД', + 'date_from' => 'Дата установки', + 'date_to' => 'Дата изменения', + 'is_active' => 'Активна ли запись', + 'created_at' => 'Дата создания', + 'updated_at' => 'Дата обновления', + 'created_by' => 'ID создателя записи', + 'updated_by' => 'ID обновителя записи', + ]; + } + + public static function setData($value, $bouquetId) { + if (self::findOne(['bouquet_id' => $bouquetId])) { + BouquetCompositionMatrixTypeHistory::updateAll(['date_to' => date('Y-m-d H:i:s'), 'bouquet_id' => $bouquetId, 'date_from' => null, 'is_active' => self::IS_ACTIVE]); + } + $matrixHistoryType = new BouquetCompositionMatrixTypeHistory([ + 'bouquet_id' => $bouquetId, + 'matrix_type_id' => $value, + 'date_from' => date('Y-m-d H:i:s'), + ]); + $matrixHistoryType->save(); + } + + /** + * Отношение к букету + */ + public function getBouquet() + { + return $this->hasOne(BouquetComposition::class, ['id' => 'bouquet_id']); + } + + /** + * Отношение к типу матрицы + */ + public function getMatrixType() + { + return $this->hasOne(MatrixType::class, ['id' => 'matrix_type_id']); + } +} diff --git a/erp24/views/bouquet/_form.php b/erp24/views/bouquet/_form.php index b3d9bbc7..cd0b26fd 100644 --- a/erp24/views/bouquet/_form.php +++ b/erp24/views/bouquet/_form.php @@ -1 +1,257 @@ registerCss(" + .file-caption { + max-width: 62% !important; + } + "); + +$photoConfig = array_map(fn($file) => [ + 'caption' => $file->url, + 'key' => $file->id, + 'url' => Url::to(['file/delete', 'id' => $file->id], true), +], $photoFiles); + +$form = ActiveForm::begin([ + 'options' => ['enctype' => 'multipart/form-data'], +]); +?> +
+
+
+

+
+
+ +

title) ?>

+ 'form-control', 'placeholder' => 'Введите название']); + } ?> +
+
+ +
+
+
+ 'h5 mt-2 mb-0']) ?> +
+
+ matrixType ? $model->matrixType->matrix_type_id : null, + ArrayHelper::map(MatrixType::find()->all(), 'id', 'name'), + ['class' => 'form-control', 'prompt' => 'Тип матрицы']) + ?> +
+
+ + +
+
+
+
+
+
Название
+
Кол-во
+
% списания
+
мрж-ть
+
% в сборке
+
ср.шт. в сборке
+
+ +
+ +
+
product->name ?>
+
count ?>
+
10%
+
30%
+
10%
+
3.2%
+
+ +
+
+
+
+ id") : Url::to("#"), ['class' => $model ? 'btn btn-warning w-100' : 'btn btn-warning w-100 disabled']) ?> +
+
+
+
+
+ +
'text-center font-weight-bold pt-5 h5']) ?>
+ field($model, 'photo_bouquet[]')->widget(FileInput::class, [ + 'options' => [ + 'id' => 'bouquet-file-upload', + 'multiple' => true, // Поддержка выбора нескольких файлов + 'accept' => 'image/png, image/jpeg, image/jpg', + ], + 'language' => 'ru', + 'pluginOptions' => [ + 'initialPreview' => $photoUrls, + 'initialPreviewConfig' => $photoConfig, + 'initialPreviewAsData' => true, + 'showPreview' => true, + 'showUpload' => false, + 'showCancel' => false, + 'mainClass' => 'input-group-lg', + 'maxFileSize' => 2800, // Максимальный размер файла (в килобайтах) + 'dropZoneTitle' => 'Выберите изображение', // Текст на зоне для перетаскивания + 'browseOnZoneClick' => true, // Разрешить клик по зоне перетаскивания + 'fileActionSettings' => [ + 'showZoom' => false, // Убираем иконку для увеличения + ], + ], + ])->label(false) ?> +
+
+
+
'text-center font-weight-bold pt-5 h5']) ?>
+ field($model, 'video_presentation')->widget(FileInput::class, [ + 'options' => [ + 'id' => 'video-file-upload', + 'multiple' => false, + 'accept' => 'video/mp4, video/avi, video/mov, video/mkv', + ], + 'language' => 'ru', + 'pluginOptions' => [ + 'showPreview' => true, + 'showUpload' => false, + 'showCancel' => false, + 'mainClass' => 'input-group-lg', + 'initialPreview' => $videoUrls, + 'maxFileSize' => 100000, // Максимальный размер файла (в килобайтах) + 'dropZoneTitle' => 'Выберите видеофайл', // Текст на зоне для перетаскивания + 'browseOnZoneClick' => true, // Разрешить клик по зоне перетаскивания + 'fileActionSettings' => [ + 'showZoom' => false, + ], + ], + ])->label(false) ?> +
+
+
'text-center font-weight-bold pt-5 h5']) ?>
+ field($model, 'video_build_process')->widget(FileInput::class, [ + 'options' => [ + 'id' => 'presentation-file-upload', + 'multiple' => false, + 'accept' => 'video/mp4, video/avi, video/mov, video/mkv', + ], + 'language' => 'ru', + 'pluginOptions' => [ + 'showPreview' => true, + 'showUpload' => false, + 'showCancel' => false, + 'mainClass' => 'input-group-lg', + 'initialPreview' => $processUrls, + 'maxFileSize' => 100000, // Максимальный размер файла (в килобайтах) + 'dropZoneTitle' => 'Выберите видеофайл', + 'browseOnZoneClick' => true, // Разрешить клик по зоне перетаскивания + 'fileActionSettings' => [ + 'showZoom' => false, // Убираем иконку для увеличения + ], + ], + ])->label(false) ?> +
+
+ +
+ +
+
'text-center font-weight-bold pt-5 h5']) ?>
+
+
+
'font-weight-bold pt-3 h6']) ?>
+
2024, 2025 => 2025], ['class' => 'form-control']) ?>
+
+
+
'font-weight-bold pt-3 h6']) ?>
+
'form-control']) ?>
+
+
+
+ 'text-center font-weight-bold pt-4 h6']) ?> +
+
+
+ +
+
+ "col-form-label"]); ?> +
+
+ 'form-control']) ?> +
+
+ +
+
+ +
+ 'text-center font-weight-bold pt-3 h6']) ?> +
+
+
+ +
+
+ "col-form-label"]); ?> +
+
+ 'form-control']) ?> +
+
+ +
+
+ +
+ 'text-center font-weight-bold pt-3 h6']) ?> +
+
+
+ +
+
+ "col-form-label"]); ?> +
+
+ 'form-control']) ?> +
+
+ +
+
+
+
+
+
+
+ 'btn btn-success w-100']) ?> +
+
+ \ No newline at end of file diff --git a/erp24/views/bouquet/create.php b/erp24/views/bouquet/create.php new file mode 100644 index 00000000..604584f8 --- /dev/null +++ b/erp24/views/bouquet/create.php @@ -0,0 +1,33 @@ +title = 'Состав букета'; +$this->params['breadcrumbs'][] = ['label' => 'Букеты', 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +?> + +
+ render('_form', [ + 'onlineStoresList' => $onlineStoresList, + 'bouquetCompositionProducts' => [], + 'marketplaceList' => $marketplaceList, + 'storesTypeList' => $storesTypeList, + 'photoUrls' => [], + 'photoFiles' => [], + 'videoUrls' => [], + 'processUrls' => [], + 'model' => null + ]); ?> +
+ diff --git a/erp24/views/bouquet/view.php b/erp24/views/bouquet/view.php index 8a373fc5..2b49b726 100644 --- a/erp24/views/bouquet/view.php +++ b/erp24/views/bouquet/view.php @@ -1,12 +1,6 @@ title = $model->name; $this->params['breadcrumbs'][] = ['label' => 'Букеты', 'url' => ['index']]; $this->params['breadcrumbs'][] = $this->title; ?> - [ - 'caption' => $file->url, - 'key' => $file->id, - 'url' => Url::to(['file/delete', 'id' => $file->id], true), -], $photoFiles); -?> -registerCss(" - .file-caption { - max-width: 62% !important; - } - "); -?>
- ['enctype' => 'multipart/form-data'], - ]); - ?> -
-
-

-

title) ?>

-
- -
- -
- all(), 'id', 'name'), ['class' => 'form-control', 'prompt' => 'Тип матрицы']) ?> -
-
-
-
-
-
-
Название
-
Кол-во
-
% списания
-
мрж-ть
-
% в сборке
-
ср.шт. в сборке
-
- -
- -
-
product->name ?>
-
count ?>
-
10%
-
30%
-
10%
-
3.2%
-
- -
-
-
-
- id"), ['class' => 'btn btn-warning w-100']) ?> -
-
-
-
-
- -
'text-center font-weight-bold pt-5 h5']) ?>
- field($model, 'photo_bouquet[]')->widget(FileInput::class, [ - 'options' => [ - 'id' => 'bouquet-file-upload', - 'multiple' => true, // Поддержка выбора нескольких файлов - 'accept' => 'image/png, image/jpeg, image/jpg', - ], - 'language' => 'ru', - 'pluginOptions' => [ - 'initialPreview' => $photoUrls, - 'initialPreviewConfig' => $photoConfig, - 'initialPreviewAsData' => true, - 'showPreview' => true, - 'showUpload' => false, - 'showCancel' => false, - 'mainClass' => 'input-group-lg', -// 'initialPreview' => [], // Задайте начальный список для предварительного просмотра (если есть) - 'maxFileSize' => 2800, // Максимальный размер файла (в килобайтах) - 'dropZoneTitle' => 'Выберите изображение', // Текст на зоне для перетаскивания - 'browseOnZoneClick' => true, // Разрешить клик по зоне перетаскивания - 'fileActionSettings' => [ - 'showZoom' => false, // Убираем иконку для увеличения - ], - ], - ])->label(false) ?> -
-
-
-
'text-center font-weight-bold pt-5 h5']) ?>
- field($model, 'video_presentation')->widget(FileInput::class, [ - 'options' => [ - 'id' => 'video-file-upload', - 'multiple' => false, - 'accept' => 'video/mp4, video/avi, video/mov, video/mkv', - ], - 'language' => 'ru', - 'pluginOptions' => [ - 'showPreview' => true, - 'showUpload' => false, - 'showCancel' => false, - 'mainClass' => 'input-group-lg', - 'initialPreview' => $videoUrls, - 'maxFileSize' => 100000, // Максимальный размер файла (в килобайтах) - 'dropZoneTitle' => 'Выберите видеофайл', // Текст на зоне для перетаскивания - 'browseOnZoneClick' => true, // Разрешить клик по зоне перетаскивания - 'fileActionSettings' => [ - 'showZoom' => false, - ], - ], - ])->label(false) ?> -
-
-
'text-center font-weight-bold pt-5 h5']) ?>
- field($model, 'video_build_process')->widget(FileInput::class, [ - 'options' => [ - 'id' => 'presentation-file-upload', - 'multiple' => false, - 'accept' => 'video/mp4, video/avi, video/mov, video/mkv', - ], - 'language' => 'ru', - 'pluginOptions' => [ - 'showPreview' => true, - 'showUpload' => false, - 'showCancel' => false, - 'mainClass' => 'input-group-lg', - 'initialPreview' => $processUrls, - 'maxFileSize' => 100000, // Максимальный размер файла (в килобайтах) - 'dropZoneTitle' => 'Выберите видеофайл', - 'browseOnZoneClick' => true, // Разрешить клик по зоне перетаскивания - 'fileActionSettings' => [ - 'showZoom' => false, // Убираем иконку для увеличения - ], - ], - ])->label(false) ?> -
-
- -
- -
-
'text-center font-weight-bold pt-5 h5']) ?>
-
-
-
'font-weight-bold pt-3 h6']) ?>
-
2024, 2025 => 2025], ['class' => 'form-control']) ?>
-
-
-
'font-weight-bold pt-3 h6']) ?>
-
'form-control']) ?>
-
-
-
- 'text-center font-weight-bold pt-4 h6']) ?> -
-
-
- -
-
- "col-form-label"]); ?> -
-
- 'form-control']) ?> -
-
- -
-
- -
- 'text-center font-weight-bold pt-3 h6']) ?> -
-
-
- -
-
- "col-form-label"]); ?> -
-
- 'form-control']) ?> -
-
- -
-
- -
- 'text-center font-weight-bold pt-3 h6']) ?> -
-
-
- -
-
- "col-form-label"]); ?> -
-
- 'form-control']) ?> -
-
- -
-
-
-
-
-
-
- 'btn btn-success w-100']) ?> -
-
- + render('_form', [ + 'model' => $model, + 'onlineStoresList' => $onlineStoresList, + 'bouquetCompositionProducts' => $bouquetCompositionProducts, + 'marketplaceList' => $marketplaceList, + 'storesTypeList' => $storesTypeList, + 'photoUrls' => $photoUrls, + 'photoFiles' => $photoFiles, + 'videoUrls' => $videoUrls, + 'processUrls' => $processUrls + ]); ?>
-- 2.39.5