249 lines
9.4 KiB
PHP
249 lines
9.4 KiB
PHP
<?php
|
|
|
|
namespace Magezon\QuickOrder\Controller\Index;
|
|
|
|
use Magento\Catalog\Api\ProductRepositoryInterface;
|
|
use Magento\Checkout\Model\Cart as CustomerCart;
|
|
use Magento\Framework\App\Action\Context;
|
|
use Magento\Framework\App\Action\HttpPostActionInterface;
|
|
use Magento\Framework\App\Filesystem\DirectoryList;
|
|
use Magento\Framework\Exception\LocalizedException;
|
|
use Magento\Framework\Filesystem;
|
|
use Magento\Framework\Filesystem\Directory\WriteInterface;
|
|
use Magento\MediaStorage\Model\File\Uploader;
|
|
use Magento\MediaStorage\Model\File\UploaderFactory;
|
|
use Magezon\QuickOrder\Model\ProductManagement;
|
|
use PhpOffice\PhpSpreadsheet\IOFactory;
|
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
|
use Psr\Log\LoggerInterface;
|
|
use Stemcell\Customer\Model\LabRepository;
|
|
|
|
class BatchImport extends \Magento\Framework\App\Action\Action implements HttpPostActionInterface
|
|
{
|
|
private const UPLOAD_DIRECTORY = 'import/quickorder';
|
|
private const MAX_UPLOAD_SIZE = 10485760;
|
|
private const ALLOWED_MIME_TYPES = [
|
|
'application/vnd.ms-excel',
|
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
'application/zip',
|
|
'application/x-zip-compressed',
|
|
'application/x-ole-storage',
|
|
'application/octet-stream',
|
|
];
|
|
|
|
private WriteInterface $mediaDirectory;
|
|
|
|
public function __construct(
|
|
Context $context,
|
|
protected ProductRepositoryInterface $productRepository,
|
|
protected LabRepository $labRepository,
|
|
protected ProductManagement $productManagement,
|
|
protected LoggerInterface $logger,
|
|
protected CustomerCart $cart,
|
|
protected UploaderFactory $uploaderFactory,
|
|
Filesystem $filesystem
|
|
) {
|
|
parent::__construct($context);
|
|
$this->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;
|
|
}
|
|
}
|