Initial commit: Vendor Sales Report Magento 2 module
This commit is contained in:
116
Model/EmailSender.php
Normal file
116
Model/EmailSender.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
namespace Shopkeeper\VendorSalesReport\Model;
|
||||
|
||||
use Magento\Framework\Mail\Template\TransportBuilder;
|
||||
use Magento\Framework\Translate\Inline\StateInterface;
|
||||
use Magento\Store\Model\StoreManagerInterface;
|
||||
use Shopkeeper\VendorSalesReport\Helper\Data as ConfigHelper;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class EmailSender
|
||||
{
|
||||
/**
|
||||
* @var TransportBuilder
|
||||
*/
|
||||
protected $transportBuilder;
|
||||
|
||||
/**
|
||||
* @var StateInterface
|
||||
*/
|
||||
protected $inlineTranslation;
|
||||
|
||||
/**
|
||||
* @var StoreManagerInterface
|
||||
*/
|
||||
protected $storeManager;
|
||||
|
||||
/**
|
||||
* @var ConfigHelper
|
||||
*/
|
||||
protected $configHelper;
|
||||
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* @param TransportBuilder $transportBuilder
|
||||
* @param StateInterface $inlineTranslation
|
||||
* @param StoreManagerInterface $storeManager
|
||||
* @param ConfigHelper $configHelper
|
||||
* @param LoggerInterface $logger
|
||||
*/
|
||||
public function __construct(
|
||||
TransportBuilder $transportBuilder,
|
||||
StateInterface $inlineTranslation,
|
||||
StoreManagerInterface $storeManager,
|
||||
ConfigHelper $configHelper,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->transportBuilder = $transportBuilder;
|
||||
$this->inlineTranslation = $inlineTranslation;
|
||||
$this->storeManager = $storeManager;
|
||||
$this->configHelper = $configHelper;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send report email
|
||||
*
|
||||
* @param string $csvContent
|
||||
* @param string $filename
|
||||
* @param string $month
|
||||
* @param string $year
|
||||
* @return bool
|
||||
*/
|
||||
public function sendReport($csvContent, $filename, $month = null, $year = null)
|
||||
{
|
||||
if (!$this->configHelper->isEmailEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$recipients = $this->configHelper->getEmailRecipients();
|
||||
if (empty($recipients)) {
|
||||
$this->logger->warning('Vendor Sales Report: No email recipients configured');
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->inlineTranslation->suspend();
|
||||
|
||||
$sender = [
|
||||
'name' => $this->storeManager->getStore()->getName(),
|
||||
'email' => $this->storeManager->getStore()->getConfig('trans_email/' . $this->configHelper->getEmailSender() . '/email')
|
||||
];
|
||||
|
||||
$subject = $this->configHelper->getEmailSubject($month, $year);
|
||||
|
||||
$transport = $this->transportBuilder
|
||||
->setTemplateIdentifier('vendorsalesreport_email_template')
|
||||
->setTemplateOptions([
|
||||
'area' => \Magento\Framework\App\Area::AREA_ADMINHTML,
|
||||
'store' => \Magento\Store\Model\Store::DEFAULT_STORE_ID,
|
||||
])
|
||||
->setTemplateVars([
|
||||
'subject' => $subject,
|
||||
'month' => $month,
|
||||
'year' => $year
|
||||
])
|
||||
->setFromByScope($sender)
|
||||
->addTo($recipients)
|
||||
->addAttachment($csvContent, $filename, 'text/csv')
|
||||
->getTransport();
|
||||
|
||||
$transport->sendMessage();
|
||||
|
||||
$this->inlineTranslation->resume();
|
||||
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error('Vendor Sales Report Email Error: ' . $e->getMessage());
|
||||
$this->inlineTranslation->resume();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
201
Model/ReportGenerator.php
Normal file
201
Model/ReportGenerator.php
Normal file
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
namespace Shopkeeper\VendorSalesReport\Model;
|
||||
|
||||
use Magento\Framework\App\ResourceConnection;
|
||||
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
|
||||
|
||||
class ReportGenerator
|
||||
{
|
||||
/**
|
||||
* @var ResourceConnection
|
||||
*/
|
||||
protected $resourceConnection;
|
||||
|
||||
/**
|
||||
* @var TimezoneInterface
|
||||
*/
|
||||
protected $timezone;
|
||||
|
||||
/**
|
||||
* State abbreviation mapping
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $stateAbbreviations = [
|
||||
'Alabama' => 'AL', 'Alaska' => 'AK', 'Arizona' => 'AZ', 'Arkansas' => 'AR',
|
||||
'California' => 'CA', 'Colorado' => 'CO', 'Connecticut' => 'CT', 'Delaware' => 'DE',
|
||||
'Florida' => 'FL', 'Georgia' => 'GA', 'Hawaii' => 'HI', 'Idaho' => 'ID',
|
||||
'Illinois' => 'IL', 'Indiana' => 'IN', 'Iowa' => 'IA', 'Kansas' => 'KS',
|
||||
'Kentucky' => 'KY', 'Louisiana' => 'LA', 'Maine' => 'ME', 'Maryland' => 'MD',
|
||||
'Massachusetts' => 'MA', 'Michigan' => 'MI', 'Minnesota' => 'MN', 'Mississippi' => 'MS',
|
||||
'Missouri' => 'MO', 'Montana' => 'MT', 'Nebraska' => 'NE', 'Nevada' => 'NV',
|
||||
'New Hampshire' => 'NH', 'New Jersey' => 'NJ', 'New Mexico' => 'NM', 'New York' => 'NY',
|
||||
'North Carolina' => 'NC', 'North Dakota' => 'ND', 'Ohio' => 'OH', 'Oklahoma' => 'OK',
|
||||
'Oregon' => 'OR', 'Pennsylvania' => 'PA', 'Rhode Island' => 'RI', 'South Carolina' => 'SC',
|
||||
'South Dakota' => 'SD', 'Tennessee' => 'TN', 'Texas' => 'TX', 'Utah' => 'UT',
|
||||
'Vermont' => 'VT', 'Virginia' => 'VA', 'Washington' => 'WA', 'West Virginia' => 'WV',
|
||||
'Wisconsin' => 'WI', 'Wyoming' => 'WY', 'District of Columbia' => 'DC',
|
||||
'Puerto Rico' => 'PR', 'Guam' => 'GU', 'Virgin Islands' => 'VI'
|
||||
];
|
||||
|
||||
/**
|
||||
* @param ResourceConnection $resourceConnection
|
||||
* @param TimezoneInterface $timezone
|
||||
*/
|
||||
public function __construct(
|
||||
ResourceConnection $resourceConnection,
|
||||
TimezoneInterface $timezone
|
||||
) {
|
||||
$this->resourceConnection = $resourceConnection;
|
||||
$this->timezone = $timezone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate report data
|
||||
*
|
||||
* @param string $startDate
|
||||
* @param string $endDate
|
||||
* @param array $orderStatuses
|
||||
* @return array
|
||||
*/
|
||||
public function generateReportData($startDate, $endDate, $orderStatuses = ['complete'])
|
||||
{
|
||||
$connection = $this->resourceConnection->getConnection();
|
||||
|
||||
$salesOrderItemTable = $this->resourceConnection->getTableName('sales_order_item');
|
||||
$salesOrderTable = $this->resourceConnection->getTableName('sales_order');
|
||||
$salesOrderAddressTable = $this->resourceConnection->getTableName('sales_order_address');
|
||||
$catalogProductEntityTable = $this->resourceConnection->getTableName('catalog_product_entity');
|
||||
$catalogProductEntityDecimalTable = $this->resourceConnection->getTableName('catalog_product_entity_decimal');
|
||||
$eavAttributeTable = $this->resourceConnection->getTableName('eav_attribute');
|
||||
|
||||
// Build status filter
|
||||
$statusPlaceholders = implode(',', array_fill(0, count($orderStatuses), '?'));
|
||||
|
||||
$sql = "
|
||||
SELECT
|
||||
DATE_FORMAT(o.created_at, '%m/%d/%Y') AS 'Date',
|
||||
oi.sku AS 'Vendor Product number',
|
||||
oi.name AS 'Description',
|
||||
'' AS 'Vendor code',
|
||||
'' AS 'Vendor name',
|
||||
o.increment_id AS 'Dealer product number',
|
||||
CASE
|
||||
WHEN sa.country_id = 'US' THEN 'United States'
|
||||
ELSE sa.country_id
|
||||
END AS 'Country',
|
||||
sa.city AS 'City',
|
||||
sa.region AS 'State',
|
||||
sa.postcode AS 'Zip code',
|
||||
CAST(oi.qty_ordered AS UNSIGNED) AS 'Quantity',
|
||||
COALESCE(
|
||||
NULLIF(oi.base_cost, 0),
|
||||
current_cost.value,
|
||||
0
|
||||
) AS 'Cost',
|
||||
o.status AS 'Order Status'
|
||||
FROM
|
||||
{$salesOrderItemTable} oi
|
||||
INNER JOIN
|
||||
{$salesOrderTable} o ON oi.order_id = o.entity_id
|
||||
INNER JOIN
|
||||
{$salesOrderAddressTable} sa ON o.entity_id = sa.parent_id
|
||||
AND sa.address_type = 'shipping'
|
||||
LEFT JOIN
|
||||
{$catalogProductEntityTable} cpe ON oi.sku = cpe.sku
|
||||
LEFT JOIN
|
||||
{$eavAttributeTable} ea ON ea.attribute_code = 'cost'
|
||||
AND ea.entity_type_id = 4
|
||||
LEFT JOIN
|
||||
{$catalogProductEntityDecimalTable} current_cost ON current_cost.entity_id = cpe.entity_id
|
||||
AND current_cost.attribute_id = ea.attribute_id
|
||||
AND current_cost.store_id = 0
|
||||
WHERE
|
||||
o.created_at BETWEEN ? AND ?
|
||||
AND o.status IN ({$statusPlaceholders})
|
||||
AND oi.product_type != 'configurable'
|
||||
ORDER BY
|
||||
o.created_at DESC, o.entity_id, oi.item_id
|
||||
";
|
||||
|
||||
$bind = array_merge(
|
||||
[$startDate . ' 00:00:00', $endDate . ' 23:59:59'],
|
||||
$orderStatuses
|
||||
);
|
||||
|
||||
$results = $connection->fetchAll($sql, $bind);
|
||||
|
||||
// Convert state names to abbreviations
|
||||
foreach ($results as &$row) {
|
||||
$row['State'] = $this->abbreviateState($row['State']);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abbreviate state name
|
||||
*
|
||||
* @param string $stateName
|
||||
* @return string
|
||||
*/
|
||||
protected function abbreviateState($stateName)
|
||||
{
|
||||
// If already abbreviated (2 characters), return as-is
|
||||
if (strlen($stateName) == 2) {
|
||||
return $stateName;
|
||||
}
|
||||
|
||||
// Look up abbreviation
|
||||
if (isset($this->stateAbbreviations[$stateName])) {
|
||||
return $this->stateAbbreviations[$stateName];
|
||||
}
|
||||
|
||||
// Return original if not found
|
||||
return $stateName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate CSV content
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function generateCsv($data)
|
||||
{
|
||||
if (empty($data)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$output = fopen('php://temp', 'r+');
|
||||
|
||||
// Headers - exclude Order Status
|
||||
$headers = array_keys($data[0]);
|
||||
$headers = array_filter($headers, function($header) {
|
||||
return $header !== 'Order Status';
|
||||
});
|
||||
fputcsv($output, $headers);
|
||||
|
||||
// Data rows - exclude Order Status
|
||||
foreach ($data as $row) {
|
||||
unset($row['Order Status']);
|
||||
fputcsv($output, array_values($row));
|
||||
}
|
||||
|
||||
rewind($output);
|
||||
$csv = stream_get_contents($output);
|
||||
fclose($output);
|
||||
|
||||
return $csv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFilename()
|
||||
{
|
||||
return 'FF_SAC_730_MCQUEEN.csv';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user