]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
[ERP-396] product replacement import from excel
authorAlexander Smirnov <fredeom@mail.ru>
Fri, 4 Apr 2025 11:36:59 +0000 (14:36 +0300)
committerAlexander Smirnov <fredeom@mail.ru>
Fri, 4 Apr 2025 11:36:59 +0000 (14:36 +0300)
erp24/controllers/crud/Product1cReplacementController.php
erp24/services/Product1cReplacementService.php [new file with mode: 0644]
erp24/views/crud/product1c-replacement/index.php
erp24/web/js/crud/product1cReplacement/index.js [new file with mode: 0644]

index 0d1d5663222baa93290cce60ce6855a792817a3e..e19e3514aa71edbe429455976086d554aa42ecf7 100644 (file)
@@ -5,6 +5,7 @@ namespace yii_app\controllers\crud;
 use Yii;
 use yii\behaviors\TimestampBehavior;
 use yii\data\ActiveDataProvider;
+use yii\web\UploadedFile;
 use yii_app\records\Admin;
 use yii_app\records\Prices;
 use yii_app\records\Product1cReplacement;
@@ -14,6 +15,7 @@ use yii\web\Controller;
 use yii\web\NotFoundHttpException;
 use yii\filters\VerbFilter;
 use yii_app\records\Products1c;
+use yii_app\services\Product1cReplacementService;
 
 /**
  * Product1CReplacementController implements the CRUD actions for Product1CReplacement model.
@@ -52,6 +54,21 @@ class Product1cReplacementController extends Controller
      */
     public function actionIndex()
     {
+        if (Yii::$app->request->isPost) {
+            $file = UploadedFile::getInstanceByName('myfile');
+            if ($file) {
+                $fileName = '/template_replacement_temp.xlsx';
+                $path1 = Yii::getAlias('@uploads') . $fileName;
+                $file->saveAs($path1);
+
+                $data = Product1cReplacementService::uploadTemplateReplacement($path1);
+
+                return implode('<br>', $data['errors']);
+            } else {
+                return 'not ok';
+            }
+        }
+
         $searchModel = new Product1cReplacementSearch();
         $dataProvider = $searchModel->search($this->request->queryParams);
 
diff --git a/erp24/services/Product1cReplacementService.php b/erp24/services/Product1cReplacementService.php
new file mode 100644 (file)
index 0000000..31dc13e
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+
+namespace yii_app\services;
+
+use Yii;
+use PhpOffice\PhpSpreadsheet\IOFactory;
+use yii\helpers\Json;
+use yii_app\records\Product1cReplacement;
+use yii_app\records\Products1c;
+
+class Product1cReplacementService {
+    public static function filterKeyWords($word) {
+        if (in_array($word, ['нет', 'Пересорт'])) {
+            return null;
+        }
+        return $word;
+    }
+
+    public static function getGuidFromName($name) {
+        $product1c = Products1c::find()->where(['like', 'name', $name, false])->one();
+        if ($product1c) {
+            return $product1c->id;
+        }
+        preg_match('/\(\d+\)/', $name, $m);
+        if ($m) {
+            $articule = trim($m[0], '()');
+            $product1c = Products1c::find()->where(['articule' => $articule])->one();
+            return $product1c ? $product1c->id : null;
+        }
+        return null;
+    }
+
+    public static function uploadTemplateReplacement($path) {
+        try {
+            $spreadsheets = IOFactory::load($path);
+        } catch (\Exception $ex) {
+            return ['errors' => ['Некорректный файл. Загрузите файл, заполненный по шаблону.']];
+        }
+        $errors = [];
+        $spreadSheet = $spreadsheets->getAllSheets()[0];
+        foreach ($spreadSheet->getRowIterator() as $ind => $spreadSheetRow) {
+            $row = [];
+            foreach ($spreadSheetRow->getCellIterator() as $indColumn => $spreadSheetRowCell) {
+                if ($indColumn == "C") {
+                    break;
+                }
+                $row[] = $spreadSheetRowCell->getValue();
+            }
+            if (!empty($row[0]) && mb_strlen($row[0]) > 3 && !empty($row[1]) && mb_strlen($row[1]) > 3) {
+                $name = trim($row[0]);
+                $replacementNames = array_filter(array_map('self::filterKeyWords', array_map('trim', explode(';', $row[1]))));
+                if (count($replacementNames) > 0) {
+                    $productGuid = self::getGuidFromName($name);
+                    $replacementGuids = [];
+                    if ($productGuid) {
+                        foreach ($replacementNames as $r) {
+                            $repGuid = self::getGuidFromName($r);
+                            if ($repGuid) {
+                                $replacementGuids []= $repGuid;
+                                $rep = Product1cReplacement::find()->where(['guid' => $productGuid, 'guid_replacement' => $repGuid])->one();
+                                if (!$rep) {
+                                    $rep = new Product1cReplacement;
+                                    $rep->guid = $productGuid;
+                                    $rep->guid_replacement = $repGuid;
+                                    $rep->created_at = date('Y-m-d H:i:s');
+                                    $rep->save();
+                                    if ($rep->getErrors()) {
+                                        $errors [] = Json::encode($rep->getErrors());
+                                    }
+                                }
+                            } else {
+                                $errors [] = "Не могу найти гуид для $r";
+                            }
+                        }
+                    } else {
+                        $errors [] = "Не могу найти гуид для $name";
+                    }
+                }
+            }
+        }
+        return compact('errors');
+    }
+}
\ No newline at end of file
index f298a46dfbee8d4721ae637cb4058715cf1575eb..967e11703faa1726cdf0c462b27b4b151d576332 100644 (file)
@@ -16,6 +16,7 @@ use yii_app\records\Products1c;
 $this->title = 'Возможные замены номенклатуры';
 $this->params['breadcrumbs'][] = $this->title;
 
+$this->registerJsFile('/js/crud/product1cReplacement/index.js', ['position' => \yii\web\View::POS_END]);
 
 ?>
 <div class="product1c-replacement-index p-4">
@@ -23,7 +24,8 @@ $this->params['breadcrumbs'][] = $this->title;
     <h1><?= Html::encode($this->title) ?></h1>
 
     <p>
-        <?= Html::a('Создать замену', ['create'], ['class' => 'btn btn-success']) ?>
+        <?= Html::a('Создать замену', ['create'], ['class' => 'btn btn-success']) ?>&nbsp;&nbsp;&nbsp;
+        <?= Html::button('Импорт из Excel', ['class' => 'btn btn-secondary btn-sm', 'onclick' => 'openUploadReplacement();']) ?>
     </p>
 
     <?php Pjax::begin(); ?>
diff --git a/erp24/web/js/crud/product1cReplacement/index.js b/erp24/web/js/crud/product1cReplacement/index.js
new file mode 100644 (file)
index 0000000..41bb5ad
--- /dev/null
@@ -0,0 +1,90 @@
+/* jshint esversion: 6 */
+
+const param32 = $("meta[name=csrf-param]").attr("content");
+const token32 = $("meta[name=csrf-token]").attr("content");
+
+function openUploadReplacement() {
+    const $mainModal = $('#mainModal');
+    const $modalBody = $mainModal.find('.modal-body');
+    const $modalTitle = $mainModal.find('.modal-title');
+
+    $mainModal.find('.close').on('click', () => { $mainModal.modal('hide'); });
+
+    let title = 'Загрузка замен';
+        let downloadLink = '/files/download?url=/uploads/template_product1cReplacement.xlsx';
+    let linkText = 'Шаблон. Загрузка замен';
+
+    $modalTitle.html(title);
+
+    $modalBody.html(`
+        <div class="row">
+            <div class="col-12">
+                <form class="d-flex justify-content-left align-items-center" enctype="multipart/form-data">
+                    <div class="d-none"><input type="file" name="myfile" accept=".xlsx"/></div>
+                    <div><input class="btn btn-success btn-sm" type="submit" value="Загрузить" /></div>
+                </form>
+            </div>
+        </div>
+        <div class="row mt-2">
+            <div class="col-12" id="infoModal"></div>
+        </div>
+        <div class="row mt-2">
+            <div class="col-12 border-2 bg-gray-200"></div>
+        </div>
+        <div class="row mt-5">
+            <div class="col-12" style="font-size: 1rem;">Скачать шаблон</div>
+        </div>
+        <div class="row mt-2">
+            <div class="col-12">
+                <a href="${downloadLink}" style="font-size: 1rem; color: #23389c; text-decoration: underline;" target="_blank">${linkText}</a>
+            </div>
+        </div>
+    `);
+
+    const browse = $modalBody.find('input[type=file]').get(0);
+    const btn = $modalBody.find('input[type=submit]').get(0);
+    const info = $modalBody.find('#infoModal').get(0);
+    const form = $modalBody.find('form').get(0);
+
+    async function UploadDict() {
+        info.innerHTML = 'загрузка...';
+        if (browse.files[0].size > 200000) {
+            info.innerHTML = '<span style="color:red">Некорректный файл. Слишком большой. Загрузите файл, заполненный по шаблону.</span>';
+            return;
+        }
+        const formData = new FormData(form);
+        formData.append(param32, token32);
+
+        try {
+            const response = await fetch("/crud/product1c-replacement/index", {
+                method: "POST",
+                body: formData,
+            });
+            const text = await response.text();
+            console.log(text)
+            if (text === 'not ok') {
+                info.innerHTML = '<span style="color:red">Не смог загрузить файл</span>';
+            } else if (text.replaceAll('<br>', '') === '') {
+                info.innerHTML = '<span style="color:green">Успешно загружен</span>';
+            } else {
+                info.innerHTML = '<span style="color:red">' + text + '</span>';
+            }
+        } catch (e) {
+            console.error(e);
+        }
+    }
+
+    browse.addEventListener('change', (event) => {
+        event.preventDefault();
+        event.stopPropagation();
+        UploadDict();
+    });
+
+    btn.addEventListener('click', (event) => {
+        event.preventDefault();
+        event.stopPropagation();
+        browse.click();
+    });
+
+    $mainModal.modal('show');
+}