I adopted the example import script to write a custom snippet that’s used as a FormIt hook. The form contains a simple file upload field and I get the products to import correctly, BUT:
- the
sku
is not imported & - (maybe related to above) the info display of the linked product in the TV seems messed up:
Here is my snippet:
// load Commerce
$path = $modx->getOption('commerce.core_path', null, MODX_CORE_PATH . 'components/commerce/') . 'model/commerce/';
$params = ['mode' => $modx->getOption('commerce.mode')];
/** @var Commerce|null $commerce */
$commerce = $modx->getService('commerce', 'Commerce', $path, $params);
if (!($commerce instanceof Commerce)) {
$modx->log(modX::LOG_LEVEL_ERROR, 'Could not load Commerce service from {' . $path . '}.');
return false;
}
// get data from uploaded file
if (!empty($_FILES['importFile']['name']) ) {
// open submitted file
$csvFile = fopen($_FILES['importFile']['tmp_name'], 'r');
// write file data into array
$csvData = array();
while (!feof($csvFile) ) {
$csvData[] = fgetcsv($csvFile, 1000, ';');
}
// get header row
$header = array_shift($csvData);
// match headers to data in array
$data = array();
foreach ($csvData as $row) {
if (!empty($row)) {
$data[] = array_combine($header, $row);
}
}
// close file
fclose($csvFile);
} else {
$errorMsg = 'Error.';
$modx->log(modX::LOG_LEVEL_ERROR, $errorMsg);
$hook->addError('importFile', $errorMsg);
return false;
}
// get tax group
// this assumes all products have the same tax group and delivery type which is configured as the default
$taxGroup = $modx->getObject('comTaxGroup', ['id' => (int)$modx->getOption('commerce.default_tax_group')]);
if (!($taxGroup instanceof comTaxGroup)) {
$modx->log(modX::LOG_LEVEL_ERROR, 'Tax group not found - configure that first.');
return false;
}
// get delivery type
$deliveryType = $modx->getObject('comDeliveryType', ['id' => (int)$modx->getOption('commerce.default_delivery_type')]);
if (!($deliveryType instanceof comDeliveryType)) {
$modx->log(modX::LOG_LEVEL_ERROR, 'Delivery type not found - configure that first.');
return false;
}
// to use a specific non-default currency, use $commerce->getCurrency('KEY');
$currency = $commerce->currency;
// define resource settings
$resourceParent = 9;
$resourceTemplate = 22;
$tvName = 'products';
$tvType = 'list'; // list or matrix
foreach ($data as $sourceRow) {
/** @var comProduct $product */
$product = $modx->newObject('comProduct');
$product->fromArray($sourceRow); // This assumes the source data has the right keys
// set delivery type and tax group
$product->set('tax_group', $taxGroup->get('id'));
$product->set('delivery_type', $deliveryType->get('id'));
// set pricing - for detailed explanation see https://docs.modmore.com/en/Commerce/v1/Developer/Products/Pricing.html
$pricing = $product->getPricing($currency);
$pricing->setRegularPrice(new \modmore\Commerce\Pricing\Price($currency, $sourceRow['price']));
// have a sale price?
if (isset($sourceRow['sale_price']) && $sourceRow['sale_price'] > 0) {
$pricing->addPriceType(
new \modmore\Commerce\Pricing\PriceType\Sale(
new \modmore\Commerce\Pricing\Price(
$currency,
$sourceRow['sale_price']
),
new DateTime($sourceRow['sale_price_from']), // when the sale started
new DateTime($sourceRow['sale_price_until']) // when the sale ended
)
);
}
$product->savePricing($pricing);
$output = "Created product {" . $product->get('sku') . "} with ID #{" . $product->get('id') . "}";
$modx->log(modX::LOG_LEVEL_ERROR, $output);
// use the processor to create the resource - this does all sort of processing that we don't want to rewrite
/** @var modProcessorResponse $response */
$response = $modx->runProcessor('resource/create', [
'context_key' => 'web',
'parent' => $resourceParent,
'template' => $resourceTemplate,
'pagetitle' => $sourceRow['name'],
'alias' => $modx->filterPathSegment($sourceRow['name'] . '-' . rand(0,999999)), // can leave this out or set a specific alias
'published' => true,
]);
if ($response->isError()) {
$errors = implode(', ', $response->getAllErrors());
$modx->log(modX::LOG_LEVEL_ERROR, 'Could not create resource: ' . $errors);
} else {
$resourceId = $response->getObject()['id'];
$resource = $modx->getObject('modResource', ['id' => $resourceId]);
if (!($resource instanceof modResource)) {
$modx->log(modX::LOG_LEVEL_ERROR, 'Could not load created resource with ID: ' . $resourceId);
} else {
if ($tvType === 'list') {
$tvValue = $product->get('id'); // Multiple products per resource? Separate IDs with a comma.
} else { // matrix
$modx->log(modX::LOG_LEVEL_ERROR, 'Matrix portion of this example is not yet ready :(');
$tvValue = '';
}
$resource->setTVValue($tvName, $tvValue);
}
}
}
return true;
And here my test products.csv
file:
sku;barcode;name;description;price;pricing;stock;stock_infinite;weight;weight_unit;image;tax_group;delivery_type;target;removed;removed_on;removed_by
1000100101;4015700000000;Product A;Lorem ipsum A;20075;;3;0;;;;;;;;;
1000100201;4004390000000;Product B;Lorem ipsum B;15087;;5;0;;;;;;;;;
1000100301;4015700000000;Product C;Lorem ipsum C;51573;;;1;;;;;;;;;
Also I would like to add the functionality that existing products get updated (based on the sku
). How can I achieve this?