mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); } public function execute() { try { $uploader = $this->getValidatedUploader(); $uploadData = $uploader->validateFile(); $spreadSheet = IOFactory::load($uploadData['tmp_name']); $data = $spreadSheet->getActiveSheet()->toArray(''); $quote = $this->cart->getQuote(); if (!$quote->getId()) { // A persisted quote ID is required for the archive file name. $this->cart->save(); $quote = $this->cart->getQuote(); } if (!$quote->getId()) { throw new LocalizedException(__('Unable to create a cart for the uploaded file.')); } $this->saveUploadedFile( $spreadSheet, (int) $quote->getId(), strtolower($uploader->getFileExtension()) ); } catch (\Throwable $e) { $this->logger->error('货号直购保存上传的 Excel 失败:' . $e->getMessage(), ['exception' => $e]); $message = $e instanceof LocalizedException ? $e->getMessage() : __('The Excel file could not be uploaded. Please check the file and try again.'); $this->messageManager->addErrorMessage($message); $this->getResponse()->representJson(json_encode(['result' => false])); return; } array_shift($data); $salesperson = []; $firstLab = $canSave = false; $orderRemark = ''; $errors = []; foreach ($data as $index => $row) { if (!$row['0']) { continue; } try { $product = $this->productRepository->get($row['0'], false, null, true); $productData = $this->productManagement->getProductData($product); $params = []; if ($row[8] && $orderRemark == '') { $orderRemark = $row[8]; } if (!empty($productData['children'])) { parse_str($productData['options'], $params); } $qty = isset($row['1']) ? intval($row['1']) : 1; $other = ['qty' => $qty, 'cd' => $row[4], 'quote' => $row[5], 'customer_discount_percent' => $row[6], 'note' => $row[7]]; $params = array_merge($params, $other); $product = $this->productRepository->getById($productData['id'], false, null, true); if (isset($row['3'])) { try { $lab = $this->labRepository->getByLabCode($row['3']); if ($lab->getLabId()) { $params['lab_id'] = $lab->getLabId(); if ($lab->getSalespersonId()) { $firstLab = $lab; $salesperson[] = $lab->getSalespersonId(); } } } catch (LocalizedException $e) { $this->logger->warning( sprintf('货号直购设置lab时异常,lab_code: %s, 原因:%s', $row['3'], $e->getMessage()), $e->getTrace() ); } } $params['item_sort'] = $index+1; $this->cart->addProduct($product, $params); $canSave = true; } catch (\Exception $e) { $this->logger->critical( sprintf('货号直购通过上传excel加入购物车失败,原因是:%s请求数据:', $e->getMessage()), $row ); $fields = ['产品号'=>0, 'Lab Id'=>3, 'CD No.' => 4]; $string = ''; foreach ($fields as $label => $index) { $string .= $label . ':' . $row[$index] . ', '; } $errors[] = $string .' 加入购物车失败, 原因:'.$e->getMessage(); } } if (count(array_unique($salesperson)) > 1) { $errors[] = '请注意,您使用错误的销售信息,请检查您的数据'; } if ($firstLab && count(array_unique($salesperson)) == 1) { $this->cart->getQuote()->setData('salesperson_id', $firstLab->getSalespersonId()); } if ($orderRemark) { $this->cart->getQuote()->setData('customer_note', $orderRemark); } foreach ($errors as $error) { $this->messageManager->addError($error); } if ($canSave) { $this->cart->save(); $this->cart->getQuote()->setTotalsCollectedFlag(false)->collectTotals(); } $this->getResponse()->representJson( json_encode(['result' => $canSave]) ); } /** * Validate the upload before PhpSpreadsheet opens it. */ private function getValidatedUploader(): Uploader { $uploader = $this->uploaderFactory->create(['fileId' => 'file']); $uploader->setAllowedExtensions(['xls', 'xlsx']); $uploader->setAllowCreateFolders(true); $uploader->setAllowRenameFiles(false); $uploader->setFilesDispersion(false); $uploader->validateFile(); if ($uploader->getFileSize() > self::MAX_UPLOAD_SIZE) { throw new LocalizedException(__('The Excel file must not exceed 10 MB.')); } if (!$uploader->checkMimeType(self::ALLOWED_MIME_TYPES)) { throw new LocalizedException(__('The uploaded file is not a valid Excel file.')); } return $uploader; } /** * Save as {quote_id}.{extension}, then {quote_id}-{n}.{extension}. */ private function saveUploadedFile(Spreadsheet $spreadSheet, int $quoteId, string $extension): string { $this->mediaDirectory->create(self::UPLOAD_DIRECTORY); $lock = $this->mediaDirectory->openFile(self::UPLOAD_DIRECTORY . '/.upload.lock', 'a+'); if (!$lock->lock()) { $lock->close(); throw new LocalizedException(__('The uploaded Excel file could not be locked for saving.')); } try { $sequence = 0; do { $stem = (string) $quoteId . ($sequence ? '-' . $sequence : ''); $fileName = $stem . '.' . $extension; $sequence++; } while ($this->archiveNameExists($stem)); $spreadSheet->getProperties()->setCreated(time()); $writer = IOFactory::createWriter($spreadSheet, $extension === 'xlsx' ? 'Xlsx' : 'Xls'); $relativeFilePath = self::UPLOAD_DIRECTORY . '/' . $fileName; try { $writer->save($this->mediaDirectory->getAbsolutePath($relativeFilePath)); } catch (\Throwable $e) { if ($this->mediaDirectory->isExist($relativeFilePath)) { $this->mediaDirectory->delete($relativeFilePath); } throw $e; } $this->mediaDirectory->changePermissions( $relativeFilePath, 0640 ); } finally { $lock->unlock(); $lock->close(); } return $fileName; } /** * Treat .xls and .xlsx files with the same stem as the same upload sequence. */ private function archiveNameExists(string $stem): bool { foreach (['xls', 'xlsx'] as $extension) { if ($this->mediaDirectory->isExist(self::UPLOAD_DIRECTORY . '/' . $stem . '.' . $extension)) { return true; } } return false; } }