Initial commit: Vendor Sales Report Magento 2 module

This commit is contained in:
shopkeeperdev
2025-11-03 17:20:07 -05:00
commit fc2838d68a
25 changed files with 1839 additions and 0 deletions

201
Model/ReportGenerator.php Normal file
View 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';
}
}