Adds a Customer Reward Points entity type to Magento's native export screen (System > Data Transfer > Export), so reward points balances can be pulled as a CSV without running SQL by hand.
One row per customer account:
| Column | Source |
|---|---|
customer_id |
customer_entity.entity_id |
email |
customer_entity.email |
customer_name |
customer_entity.firstname + lastname |
customer_group |
customer_group.customer_group_code |
website |
store_website.name |
account_created |
customer_entity.created_at |
points_balance |
SUM(magento_reward.points_balance) |
The query the collection builds is the report query it was written from:
SELECT
ce.entity_id AS customer_id,
ce.email,
TRIM(CONCAT(COALESCE(ce.firstname, ''), ' ', COALESCE(ce.lastname, ''))) AS customer_name,
cg.customer_group_code AS customer_group,
sw.name AS website,
ce.created_at AS account_created,
COALESCE(SUM(mr.points_balance), 0) AS points_balance
FROM customer_entity ce
LEFT JOIN magento_reward mr ON mr.customer_id = ce.entity_id
LEFT JOIN customer_group cg ON cg.customer_group_id = ce.group_id
LEFT JOIN store_website sw ON sw.website_id = ce.website_id
GROUP BY ce.entity_id, ce.email, ce.firstname, ce.lastname,
cg.customer_group_code, sw.name, ce.created_at
ORDER BY points_balance DESC, ce.entity_id;Notes on the data:
magento_rewardholds one row per customer per website, so the balance is summed to a single figure per account.- Accounts that never earned points have no
magento_rewardrow and report0. points_balanceis the live balance. Expired points have already been deducted by themagento_reward_expirecron, so no expiry handling is needed here.
The Entity Attributes grid on the export screen filters the report. Filter types follow the column's declared backend type:
email,customer_name,customer_group,website— partial text match (LIKE %value%). Filtering by email is the intended primary use.customer_id,points_balance— numeric from/to range.account_created— date from/to range.- The Exclude checkbox drops a column from the CSV.
points_balance is an aggregate, so its filter is applied as HAVING; the rest
filter in WHERE.
etc/export.xml registers the entity, which is all the native screen needs:
Model\Export\RewardPointsextendsMagento\ImportExport\Model\Export\AbstractEntity, so it works with the queued export in 2.4 (import_export.exportmessage →exportProcessorconsumer) as well as the file format adapters.Model\Export\RewardPoints\AttributeCollectiondescribes the columns as EAV attributes, which is what the filter grid andMagento\ImportExport\Model\Export::getAttributeFilterType()require.Model\ResourceModel\RewardPoints\Collectionbuilds the query above.getSelectCountSql()is overridden to count grouped rows rather than the rows inside the first group, which would otherwise cap a paged export at one page.
Rows per query default to 10,000 and are configurable at
export/reward_points_page_size/reward_points.
composer require deployecommerce/module-reward-order-export
bin/magento module:enable DeployEcommerce_RewardOrderExport
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flushRequires Adobe Commerce (the Magento_Reward module); it has nothing to read
on Magento Open Source.
The export runs through the message queue, so exportProcessor (or cron) must
be running for the file to appear on the export page.
Pest unit tests live in tests/, with their own Composer project so Pest's
PHPUnit 10 never meets the PHPUnit 9 that Magento vendors. Magento itself is
not installed here — point the harness at any Magento 2 checkout:
cd tests
composer install
MAGENTO_ROOT=/path/to/magento vendor/bin/pestWhen this package is installed in a project (vendor/deployecommerce/module-reward-order-export),
the harness finds that project's autoloader on its own and MAGENTO_ROOT can
be omitted.
Pest 2 is pinned deliberately: Pest 3 requires PHP 8.2 and this module targets PHP 8.1.
BSD 3-Clause — see LICENSE.md.