Files
stemcell/app/code/Stemcell/Sales/Model/Order/Email/Attachment/Order.php
T
2026-09-15 10:26:34 +08:00

314 lines
12 KiB
PHP

<?php
namespace Stemcell\Sales\Model\Order\Email\Attachment;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Exception\FileSystemException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
use Magento\Framework\UrlInterface;
use \PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\Exception;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Filesystem;
use Magento\Sales\Model\ResourceModel\Order\Item;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use Psr\Log\LoggerInterface;
use Stemcell\Customer\Api\Data\SalespersonInterface;
use Stemcell\Sales\Model\Order\Email\Sender\OrderSender;
class Order
{
private Item\Collection $itemCollection;
private Filesystem\DirectoryList $directoryList;
private Filesystem\Directory\WriteInterface $directory;
private \Magento\Store\Model\StoreManagerInterface $storeManager;
protected SalespersonInterface $salesperson;
protected OrderSender $orderSender;
protected \Magento\Sales\Model\Order $order;
/**
* @var \Magento\Sales\Model\Order\Item[]
*/
protected array $orderItems;
/**
* @throws FileSystemException
*/
public function __construct(
Filesystem $filesystem,
Item\Collection $itemCollection,
Filesystem\DirectoryList $directoryList,
\Magento\Store\Model\StoreManagerInterface $storeManager,
protected LoggerInterface $logger,
protected TimezoneInterface $timezone
) {
$this->itemCollection = $itemCollection;
$this->directoryList = $directoryList;
$this->storeManager = $storeManager;
$this->directory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA);
}
/**
* @return string[]
*/
protected function getHeaders() {
return [
'订单编号',
'订单金额',
'经销商',
'销售',
'下单时间',
'订单状态',
'货号',
'商品名称',
'经销商价格(¥)',
'数量',
'CD号',
'Quote号',
'折扣',
'总金额(¥)',
'订货账户',
'账户名称',
'PI SAP ID',
// '最终用户单位',
// 'PI',
// '最终使用人',
// '联系电话',
// '邮箱地址',
'终端类型',
'备注',
'订单备注',
];
}
protected function getOrderStatusLabel(\Magento\Sales\Model\Order $order)
{
try {
return $order->getStatusLabel();
} catch (LocalizedException $e) {
$this->logger->critical(
sprintf(
'获取订单:: %s 的status: %s label失败, 原因:%s',
$order->getIncrementId(),
$order->getStatus(),
$e->getMessage()
)
);
}
return '';
}
public function getCurrentTimezoneTime(string $time)
{
try {
$time = $this->timezone->date(new \DateTime($time))->format('Y-m-d H:i:s');
} catch (\Exception $e) {
$this->logger->critical('发给销售的邮件附件在做数据转换时异常: ' . $e->getMessage());
}
return $time;
}
/**
* 同一笔订单,可能因为用户在购物车给不同商品选择的账户(lab)不一样,这时对应的销售(salesperson)可能不一样,
* 因此同一个订单需要根据销售来拆分,这就导致同一个订单可能发多个邮件给不同的销售。因此这个的order_items并不是订单的全部items。
* 此数据来源于\Stemcell\Sales\Observer\SalespersonNotify。
* 故此,grand_total的不能用order的grand total
* @param \Magento\Sales\Model\Order\Item $orderItem
* @param array $fields
* @return array
*/
public function getRowData(\Magento\Sales\Model\Order\Item $orderItem, array $fields): array
{
$row = [];
foreach ($fields as $column) {
$value = match ($column) {
'booking_account' => $orderItem->getData('booking_account'),
'user_type' => $orderItem->getData('user_type') == 0 ? '终端' : '二级经销商',
'customer_discount_percent' => $this->getCustomerDiscountPercent($orderItem),
'grand_total' => $this->getGrandTotal(),
'price' => number_format($orderItem->getData('price'), 2),
'row_total' => $this->getRowTotal($orderItem),
'status' => $this->getOrderStatusLabel($orderItem->getOrder()),
'salesperson_name' => $orderItem->getData('salesperson_name'),
'created_at' => $this->getCurrentTimezoneTime($orderItem->getData('created_at')),
'name' => $this->getProductName($orderItem),
default => $orderItem->getData($column),
};
if ($value!=null && trim($value)=='-') $value = null;
$row[] = $value;
}
return $row;
}
protected function getProductName(\Magento\Sales\Model\Order\Item $orderItem): string
{
return $orderItem->getProductOptionByCode('simple_name')?? $orderItem->getName();
}
protected function getCustomerDiscountPercent(\Magento\Sales\Model\Order\Item $orderItem): string
{
$discountPercent = $orderItem->getData('customer_discount_percent');
return $discountPercent == 0 ? '' : number_format($discountPercent, 2).'%';
}
protected function getRowTotal(\Magento\Sales\Model\Order\Item $orderItem): string
{
return number_format($orderItem->getRowTotal(), 2);
}
/**
* @return int[]
*/
protected function getOrderItemsId(): array
{
return array_map(function (\Magento\Sales\Model\Order\Item $item){
return $item->getItemId();
}, $this->order->getAllVisibleItems());
}
protected function getGrandTotal(): string
{
return '¥'.number_format($this->order->getGrandTotal(), 2);
}
/**
* @return Item\Collection
*/
protected function getCollection(array $ordersId) {
$this->itemCollection->addFieldToSelect([
'sku', 'name', 'price', 'qty_ordered', 'cd', 'quote', 'customer_discount_percent', 'row_total', 'lab_code',
// 'company', 'user',
'pi_sap_id',
// 'user_tel', 'user_email',
'note', 'user_type', 'order_id', 'product_options'
])
->addFieldToFilter('main_table.item_id', ['in'=>$this->getOrderItemsId()])
->addFieldToFilter('main_table.parent_item_id', ['null' => true])
->getSelect()
->join(
'sales_order',
'main_table.order_id=sales_order.entity_id',
[
'increment_id', 'grand_total', 'customer_firstname', 'created_at', 'status', 'sales_order.salesperson_id',
'customer_note'
]
)
->joinLeft(
'salesperson',
'salesperson.salesperson_id=sales_order.salesperson_id',
[
'salesperson_name' => 'salesperson.name'
]
)->joinLeft(
'lab',
'lab.lab_id=main_table.lab_id',
[
'lab_code' => 'lab.lab_code',
'booking_account' => 'lab.booking_account',
'pi_sap_id' => 'lab.pi_sap_id',
]
);
$this->logger->debug('create order attachment sql: '.$this->itemCollection->getSelectSql(true));
return $this->itemCollection;
}
protected function getFields() {
return [
'increment_id', 'grand_total', 'customer_firstname', 'salesperson_name', 'created_at', 'status', 'sku',
'name', 'price', 'qty_ordered', 'cd', 'quote', 'customer_discount_percent',
'row_total', 'lab_code', 'booking_account', 'pi_sap_id',
// 'company', 'pi', 'user', 'user_tel', 'user_email',
'user_type', 'note', 'customer_note'
];
}
/**
* @param \Magento\Sales\Model\Order $order
* @return string
*/
protected function getShippingAddress(\Magento\Sales\Model\Order $order)
{
$address = $order->getShippingAddress();
return '收货地址: '.$address->getRegion() . ' ' . $address->getCity() . ' '
. implode(' ', $address->getStreet());
}
/**
* @param \Magento\Sales\Model\Order $order
* @param OrderSender $orderSender
* @return string
* @throws FileSystemException
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
*/
public function getFile(\Magento\Sales\Model\Order $order, OrderSender $orderSender)
{
$this->order = $order;
$this->orderSender = $orderSender;
$name = md5(microtime());
$file = 'attachment/'. $name . '.xlsx';
$fields = $this->getFields();
$this->directory->create('attachment');
$filePath = $this->directoryList->getPath(UrlInterface::URL_TYPE_MEDIA).'/'.$file;
$ordersId = [$order->getId()];
$collection = $this->getCollection($ordersId);
$dataGroupByOrderId = [];
foreach ($collection as $item) {
/* @var $item \Magento\Sales\Model\Order\Item */
$dataGroupByOrderId[$item->getData('salesperson_id')][] = $this->getRowData($item, $fields);
}
$styles = [
'alignment' => [
'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER,
'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
],
];
$rowIndex = 2;
$spreadSheet = new Spreadsheet();
$writer = IOFactory::createWriter($spreadSheet, IOFactory::WRITER_XLSX);
$worksheet = $spreadSheet->getActiveSheet();
$columnIndex = 'A';
foreach ($this->getHeaders() as $row) {
$cell = $worksheet->getCell($columnIndex.'1');
$cell->getAppliedStyle()->applyFromArray($styles);
$cell->setValue($row);
$columnIndex++;
}
$worksheet->getRowDimension(1)->setRowHeight(20);
foreach ($dataGroupByOrderId as $rows) {
$rowCount = count($rows);
$mergeColumnsIndex = ['A', 'B', 'C', 'D', 'E', 'F', 'T'];
foreach ($mergeColumnsIndex as $index) {
$worksheet->mergeCells($index.$rowIndex.':'.$index.$rowIndex+$rowCount-1);
}
foreach ($rows as $row) {
$columnIndex = 'A';
foreach ($row as $value) {
$worksheet->getColumnDimension($columnIndex)->setWidth(15);
$worksheet->getRowDimension($rowIndex)->setRowHeight(20);
$cell = $worksheet->getCell($columnIndex.$rowIndex);
$cell->getAppliedStyle()->applyFromArray($styles);
$cell->setValue($value);
$columnIndex++;
}
$rowIndex++;
}
}
$worksheet->mergeCells("A{$rowIndex}:$columnIndex{$rowIndex}");
$worksheet->setCellValue("A{$rowIndex}", $this->getShippingAddress($order));
$writer->save($filePath);
$content = $this->directory->readFile($filePath);
$this->directory->delete($filePath);
return $content;
}
}