202 lines
6.5 KiB
PHP
202 lines
6.5 KiB
PHP
<?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';
|
|
}
|
|
}
|