Export Product IDs With Magento Dataflow Advanced Profiles
Magento Export/Import and Dataflow features are using product SKU as unique product identifier. Usually, and for catalog management inside Magento, that is perfectly enough. But what if you need to export your products catalog CSV file and you need that file to contain product id’s from your Magento store. You may want to use that CSV file to import into your ERP application, or your stock management software, or anything else. By default you won’t be able to do that in Magento.
Sure, you can connect your external application with Magento API, but sometimes simple CSV export is most cost effective solution at the time. From my experience this is common clients request.
I will show you how to do that without changing Magento core files. We will make changes that will add additional column with product id’s to any Dataflow export Profile. We will use Advanced Dataflow profiles and custom product parser and mapper classes for this.
Let us first create our custom product parser and mapper classes. If we examine Actions XML of any default products export profile, we will notice these two declarations.
<action type="catalog/convert_parser_product" method="unparse">
<action type="dataflow/convert_mapper_column" method="map">
First class is used to prepare products info from Magento database for export in CSV file. Second one is used to prepare mapped fields only. In our advanced export profiles we will use our custom classes instead these two.
Create file app/code/local/Mage/Catalog/Model/Convert/Parser/Productforerp.php with content
<?php
class Mage_Catalog_Model_Convert_Parser_Productforerp extends Mage_Catalog_Model_Convert_Parser_Product{
public function unparse(){
$entityIds = $this->getData();
foreach ($entityIds as $i => $entityId) {
$product = $this->getProductModel()
->setStoreId($this->getStoreId())
->load($entityId);
$this->setProductTypeInstance($product);
/* @var $product Mage_Catalog_Model_Product */
$position = Mage::helper('catalog')->__('Line %d, SKU: %s', ($i+1), $product->getSku());
$this->setPosition($position);
$row = array(
'store' => $this->getStore()->getCode(),
'websites' => '',
'attribute_set' => $this->getAttributeSetName($product->getEntityTypeId(),
$product->getAttributeSetId()),
'type' => $product->getTypeId(),
'category_ids' => join(',', $product->getCategoryIds()),
'product_id' => $entityId
);
if ($this->getStore()->getCode() == Mage_Core_Model_Store::ADMIN_CODE) {
$websiteCodes = array();
foreach ($product->getWebsiteIds() as $websiteId) {
$websiteCode = Mage::app()->getWebsite($websiteId)->getCode();
$websiteCodes[$websiteCode] = $websiteCode;
}
$row['websites'] = join(',', $websiteCodes);
} else {
$row['websites'] = $this->getStore()->getWebsite()->getCode();
if ($this->getVar('url_field')) {
$row['url'] = $product->getProductUrl(false);
}
}
foreach ($product->getData() as $field => $value) {
if (in_array($field, $this->_systemFields) || is_object($value)) {
continue;
}
$attribute = $this->getAttribute($field);
if (!$attribute) {
continue;
}
if ($attribute->usesSource()) {
$option = $attribute->getSource()->getOptionText($value);
if ($value && empty($option) && $option != '0') {
$this->addException(
Mage::helper('catalog')->__('Invalid option ID specified for %s (%s), skipping the record.', $field, $value),
Mage_Dataflow_Model_Convert_Exception::ERROR
);
continue;
}
if (is_array($option)) {
$value = join(self::MULTI_DELIMITER, $option);
} else {
$value = $option;
}
unset($option);
} elseif (is_array($value)) {
continue;
}
$row[$field] = $value;
}
if ($stockItem = $product->getStockItem()) {
foreach ($stockItem->getData() as $field => $value) {
if (in_array($field, $this->_systemFields) || is_object($value)) {
continue;
}
$row[$field] = $value;
}
}
foreach ($this->_imageFields as $field) {
if (isset($row[$field]) && $row[$field] == 'no_selection') {
$row[$field] = null;
}
}
$batchExport = $this->getBatchExportModel()
->setId(null)
->setBatchId($this->getBatchModel()->getId())
->setBatchData($row)
->setStatus(1)
->save();
$product->reset();
}
return $this;
}
}
For mapper, create file app/code/local/Mage/Dataflow/Model/Convert/Mapper/Columnforerp.php with content
<?php
class Mage_Dataflow_Model_Convert_Mapper_Columnforerp extends Mage_Dataflow_Model_Convert_Mapper_Column{
public function map(){
$batchModel = $this->getBatchModel();
$batchExport = $this->getBatchExportModel();
$batchExportIds = $batchExport
->setBatchId($this->getBatchModel()->getId())
->getIdCollection();
$onlySpecified = (bool)$this->getVar('_only_specified') === true;
if (!$onlySpecified) {
foreach ($batchExportIds as $batchExportId) {
$batchExport->load($batchExportId);
$batchModel->parseFieldList($batchExport->getBatchData());
}
return $this;
}
if ($this->getVar('map') && is_array($this->getVar('map'))) {
$attributesToSelect = $this->getVar('map');
}
else {
$attributesToSelect = array();
}
if (!$attributesToSelect) {
$this->getBatchExportModel()
->setBatchId($this->getBatchModel()->getId())
->deleteCollection();
throw new Exception(Mage::helper('dataflow')->__('Error in field mapping: field list for mapping is not defined.'));
}
foreach ($batchExportIds as $batchExportId) {
$batchExport = $this->getBatchExportModel()->load($batchExportId);
$row = $batchExport->getBatchData();
$newRow = array('product_id' => $batchExportId);
foreach ($attributesToSelect as $field => $mapField) {
$newRow[$mapField] = isset($row[$field]) ? $row[$field] : null;
}
$batchExport->setBatchData($newRow)
->setStatus(2)
->save();
$this->getBatchModel()->parseFieldList($batchExport->getBatchData());
}
return $this;
}
}
Changes we’ve made to original extended classes are higlighted above.
- Open System->Import/Export->Dataflow Profiles.
- Edit some existing Magento export profile, like Export All Products, for example.
- Copy content of Profile Actions XML and paste it into Actions XML field of new Advanced Dataflow profile.
- Change parser and mapper definitions to use our custom classes.
.
.
<action type="catalog/convert_parser_productforerp" method="unparse">
.
.
<action type="dataflow/convert_mapper_columnforerp" method="map">
.
.
We can name our new advanced profile like this “Export All Products With IDs”. Save and continue edit you Advanced Profile. Now when you run the advanced profile you will get your products CSV file with additional product_id column. You Magento is safe for update, since we’ve used local code pool for our custom classes. You can simply leave those local pool classes there without ever using them, and they will not be used without advanced profile created and configured to use them.
Of course, we could create custom module that will hold our custom classes and even create our advanced export profiles, but this is just the fastest way that will do the trick without breaking your Magento store.
You can download source code and Actions XML profile example for Export All Products With ID’s Advances profile.
Cheers.