Merge branch 'release/2019.09-03'
This commit is contained in:
@@ -0,0 +1,164 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace EP\EpProducts\Command;
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
*
|
||||||
|
* Copyright notice
|
||||||
|
*
|
||||||
|
* (c) 2019 Björn Fromme <[email protected]>, dreipunktnull
|
||||||
|
*
|
||||||
|
* All rights reserved
|
||||||
|
*
|
||||||
|
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||||
|
* free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The GNU General Public License can be found at
|
||||||
|
* http://www.gnu.org/copyleft/gpl.html.
|
||||||
|
*
|
||||||
|
* This script is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* This copyright notice MUST APPEAR in all copies of the script!
|
||||||
|
***************************************************************/
|
||||||
|
|
||||||
|
use EP\EpProducts\CsvFormatter\FacebookCatalogCsvFormatter;
|
||||||
|
use EP\EpProducts\CsvFormatter\GoogleBusinessFeedCsvFormatter;
|
||||||
|
use EP\EpProducts\Domain\Model\Reseller;
|
||||||
|
use EP\EpProducts\Domain\Repository\ResellerRepository;
|
||||||
|
use EP\EpProducts\Service\ResellerDataService;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Serializer\Encoder\XmlEncoder;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
||||||
|
use Symfony\Component\Serializer\Serializer;
|
||||||
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
use TYPO3\CMS\Extbase\Object\ObjectManager;
|
||||||
|
|
||||||
|
class ExportCommandController extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected static $imageDimensions = [
|
||||||
|
'facebook' => [
|
||||||
|
'width' => '1080',
|
||||||
|
'maxHeight' => '1080',
|
||||||
|
'cropVariant' => 'facebook',
|
||||||
|
],
|
||||||
|
'google' => [
|
||||||
|
'width' => '1200',
|
||||||
|
'maxHeight' => '1200',
|
||||||
|
'cropVariant' => 'google',
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ResellerRepository
|
||||||
|
*/
|
||||||
|
protected $resellerRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ResellerDataService
|
||||||
|
*/
|
||||||
|
protected $resellerDataService;
|
||||||
|
|
||||||
|
public function __construct(string $name = null)
|
||||||
|
{
|
||||||
|
parent::__construct($name);
|
||||||
|
|
||||||
|
/** @var ObjectManager $objectManager */
|
||||||
|
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
|
||||||
|
$this->resellerRepository = $objectManager->get(ResellerRepository::class);
|
||||||
|
$this->resellerDataService = $objectManager->get(ResellerDataService::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param InputInterface $input
|
||||||
|
* @param OutputInterface $output
|
||||||
|
* @throws \Doctrine\DBAL\DBALException
|
||||||
|
*/
|
||||||
|
public function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$resellers = $this->resellerRepository->findAll();
|
||||||
|
$destinationFolder = sprintf(
|
||||||
|
'%s/fileadmin/reseller',
|
||||||
|
\TYPO3\CMS\Core\Core\Environment::getPublicPath()
|
||||||
|
);
|
||||||
|
if (!mkdir($destinationFolder, 0755) && !is_dir($destinationFolder)) {
|
||||||
|
throw new \RuntimeException(sprintf('Directory "%s" was not created', $destinationFolder));
|
||||||
|
}
|
||||||
|
foreach ($resellers as $reseller) {
|
||||||
|
/** @var Reseller $reseller */
|
||||||
|
$output->writeln('Exporting XML for ' . $reseller->getName());
|
||||||
|
$this->exportXml($reseller, $destinationFolder);
|
||||||
|
$output->writeln('Exporting CSV (Facebook) for ' . $reseller->getName());
|
||||||
|
$this->exportCsv($reseller, 'facebook', $destinationFolder);
|
||||||
|
$output->writeln('Exporting CSV (Google) for ' . $reseller->getName());
|
||||||
|
$this->exportCsv($reseller, 'google', $destinationFolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Reseller $reseller
|
||||||
|
* @param string $destinationFolder
|
||||||
|
* @throws \Doctrine\DBAL\DBALException
|
||||||
|
*/
|
||||||
|
protected function exportXml(Reseller $reseller, $destinationFolder)
|
||||||
|
{
|
||||||
|
$data = $this->resellerDataService->preprocessAll($reseller);
|
||||||
|
$encoders = [new XmlEncoder('products')];
|
||||||
|
$normalizers = [new ObjectNormalizer()];
|
||||||
|
$serializer = new Serializer($normalizers, $encoders);
|
||||||
|
$xml = $serializer->serialize(
|
||||||
|
$data,
|
||||||
|
'xml',
|
||||||
|
[ 'xml_encoding' => 'utf-8', 'xml_format_output' => false ]
|
||||||
|
);
|
||||||
|
$filename = sprintf(
|
||||||
|
'%s/export_%s.xml',
|
||||||
|
$destinationFolder,
|
||||||
|
$reseller->getCode()
|
||||||
|
);
|
||||||
|
@unlink($filename);
|
||||||
|
file_put_contents($filename, $xml);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Reseller $reseller
|
||||||
|
* @param string $type
|
||||||
|
* @param string $destinationFolder
|
||||||
|
* @throws \Doctrine\DBAL\DBALException
|
||||||
|
*/
|
||||||
|
protected function exportCsv(Reseller $reseller, $type, $destinationFolder)
|
||||||
|
{
|
||||||
|
$data = $this->resellerDataService->preprocessAll(
|
||||||
|
$reseller,
|
||||||
|
static::$imageDimensions[$type],
|
||||||
|
$type
|
||||||
|
);
|
||||||
|
if ($type === 'google') {
|
||||||
|
$csv = GoogleBusinessFeedCsvFormatter::format($data);
|
||||||
|
} else {
|
||||||
|
$csv = FacebookCatalogCsvFormatter::format($data);
|
||||||
|
}
|
||||||
|
$filename = sprintf(
|
||||||
|
'%s/export_%s_%s.csv',
|
||||||
|
$destinationFolder,
|
||||||
|
$reseller->getCode(),
|
||||||
|
$type
|
||||||
|
);
|
||||||
|
@unlink($filename);
|
||||||
|
$fileHandle = fopen($filename, 'wb');
|
||||||
|
foreach ($csv as $row) {
|
||||||
|
fputcsv($fileHandle, $row);
|
||||||
|
}
|
||||||
|
fclose($fileHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,59 +27,26 @@ namespace EP\EpProducts\Controller;
|
|||||||
* This copyright notice MUST APPEAR in all copies of the script!
|
* This copyright notice MUST APPEAR in all copies of the script!
|
||||||
***************************************************************/
|
***************************************************************/
|
||||||
|
|
||||||
use EP\EpProducts\CsvFormatter\FacebookCatalogCsvFormatter;
|
|
||||||
use EP\EpProducts\CsvFormatter\GoogleBusinessFeedCsvFormatter;
|
|
||||||
use EP\EpProducts\Domain\Model\Product;
|
use EP\EpProducts\Domain\Model\Product;
|
||||||
use EP\EpProducts\Domain\Model\Reseller;
|
use EP\EpProducts\Domain\Model\Reseller;
|
||||||
use EP\EpProducts\Service\ResellerDataService;
|
use EP\EpProducts\Service\ResellerDataService;
|
||||||
use Symfony\Component\Serializer\Encoder\XmlEncoder;
|
|
||||||
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
|
||||||
use Symfony\Component\Serializer\Serializer;
|
|
||||||
use TYPO3\CMS\Core\Cache\CacheManager;
|
|
||||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
|
||||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||||
use TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentValueException;
|
|
||||||
|
|
||||||
class ResellerController extends ActionController
|
class ResellerController extends ActionController
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected static $imageDimensions = [
|
|
||||||
'facebook' => [
|
|
||||||
'width' => '1080',
|
|
||||||
'maxHeight' => '1080',
|
|
||||||
'cropVariant' => 'facebook',
|
|
||||||
],
|
|
||||||
'google' => [
|
|
||||||
'width' => '1200',
|
|
||||||
'maxHeight' => '1200',
|
|
||||||
'cropVariant' => 'google',
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var ResellerDataService
|
* @var ResellerDataService
|
||||||
*/
|
*/
|
||||||
protected $resellerDataService;
|
protected $resellerDataService;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var \TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
|
|
||||||
*/
|
|
||||||
protected $cache;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ResellerDataService $resellerDataService
|
* @param ResellerDataService $resellerDataService
|
||||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
|
||||||
*/
|
*/
|
||||||
public function __construct(ResellerDataService $resellerDataService)
|
public function __construct(ResellerDataService $resellerDataService)
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
|
||||||
$this->resellerDataService = $resellerDataService;
|
$this->resellerDataService = $resellerDataService;
|
||||||
/** @var CacheManager $cacheManager */
|
|
||||||
$cacheManager = GeneralUtility::makeInstance(CacheManager::class);
|
|
||||||
$this->cache = $cacheManager->getCache('ep_products_reseller');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,7 +67,7 @@ class ResellerController extends ActionController
|
|||||||
/**
|
/**
|
||||||
* @param Reseller $reseller
|
* @param Reseller $reseller
|
||||||
* @param Product $product
|
* @param Product $product
|
||||||
|
* @throws \Doctrine\DBAL\DBALException
|
||||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException
|
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException
|
||||||
*/
|
*/
|
||||||
@@ -115,97 +82,9 @@ class ResellerController extends ActionController
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$cacheKey = sprintf('reseller_export_cp_%d_%d', $product->getUid(), $reseller->getUid());
|
|
||||||
if (($productData = $this->cache->get($cacheKey)) === false) {
|
|
||||||
$productData = $this->resellerDataService->preprocessSingle($product, $reseller);
|
$productData = $this->resellerDataService->preprocessSingle($product, $reseller);
|
||||||
$this->cache->set($cacheKey, $productData, [], 3600);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->view->assign('reseller', $reseller);
|
$this->view->assign('reseller', $reseller);
|
||||||
$this->view->assign('productData', $productData);
|
$this->view->assign('productData', $productData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Reseller $reseller
|
|
||||||
* @return void
|
|
||||||
* @throws \Doctrine\DBAL\DBALException
|
|
||||||
*/
|
|
||||||
public function xmlAction(Reseller $reseller)
|
|
||||||
{
|
|
||||||
$cacheKey = sprintf('reseller_export_xml_full_%d', $reseller->getUid());
|
|
||||||
if (($xml = $this->cache->get($cacheKey)) === false) {
|
|
||||||
$data = $this->resellerDataService->preprocessAll($reseller);
|
|
||||||
$encoders = [new XmlEncoder('products')];
|
|
||||||
$normalizers = [new ObjectNormalizer()];
|
|
||||||
$serializer = new Serializer($normalizers, $encoders);
|
|
||||||
$xml = $serializer->serialize(
|
|
||||||
$data,
|
|
||||||
'xml',
|
|
||||||
[ 'xml_encoding' => 'utf-8', 'xml_format_output' => false ]
|
|
||||||
);
|
|
||||||
$this->cache->set($cacheKey, $xml, [], 3600);
|
|
||||||
}
|
|
||||||
|
|
||||||
$filename = sprintf('export_%s_%s.xml', $reseller->getCode(), date('Y-m-d'));
|
|
||||||
|
|
||||||
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
|
|
||||||
header('Content-Description: File Transfer');
|
|
||||||
header('Content-type: text/xml');
|
|
||||||
header('Content-Disposition: attachment; filename=' . $filename);
|
|
||||||
header('Expires: 0');
|
|
||||||
header('Pragma: public');
|
|
||||||
|
|
||||||
echo $xml;
|
|
||||||
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Reseller $reseller
|
|
||||||
* @param string $type
|
|
||||||
* @throws \Doctrine\DBAL\DBALException
|
|
||||||
* @throws InvalidArgumentValueException
|
|
||||||
*/
|
|
||||||
public function csvAction(Reseller $reseller, $type = 'facebook')
|
|
||||||
{
|
|
||||||
if (!array_key_exists($type, static::$imageDimensions)) {
|
|
||||||
throw new InvalidArgumentValueException();
|
|
||||||
}
|
|
||||||
|
|
||||||
$cacheKey = sprintf('reseller_export_csv_%s_%d', $type, $reseller->getUid());
|
|
||||||
|
|
||||||
if (($csv = $this->cache->get($cacheKey)) === false) {
|
|
||||||
$data = $this->resellerDataService->preprocessAll(
|
|
||||||
$reseller,
|
|
||||||
static::$imageDimensions[$type],
|
|
||||||
$type
|
|
||||||
);
|
|
||||||
if ($type === 'google') {
|
|
||||||
$csv = GoogleBusinessFeedCsvFormatter::format($data);
|
|
||||||
} else {
|
|
||||||
$csv = FacebookCatalogCsvFormatter::format($data);
|
|
||||||
}
|
|
||||||
$this->cache->set($cacheKey, $csv, [], 3600);
|
|
||||||
}
|
|
||||||
|
|
||||||
$filename = sprintf('export_%s_%s.csv', $reseller->getCode(), date('Y-m-d'));
|
|
||||||
|
|
||||||
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
|
|
||||||
header('Content-Description: File Transfer');
|
|
||||||
header('Content-type: text/csv');
|
|
||||||
header('Content-Disposition: attachment; filename=' . $filename);
|
|
||||||
header('Expires: 0');
|
|
||||||
header('Pragma: public');
|
|
||||||
|
|
||||||
$fileHandle = fopen('php://output', 'wb');
|
|
||||||
|
|
||||||
foreach ($csv as $row) {
|
|
||||||
fputcsv($fileHandle, $row);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose($fileHandle);
|
|
||||||
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace EP\EpProducts\Domain\Model;
|
namespace EP\EpProducts\Domain\Model;
|
||||||
|
|
||||||
|
use TYPO3\CMS\Extbase\Annotation\ORM\Lazy;
|
||||||
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
|
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
|
||||||
|
|
||||||
/***************************************************************
|
/***************************************************************
|
||||||
@@ -49,6 +50,7 @@ class Reseller extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Product>
|
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Product>
|
||||||
|
* @Lazy()
|
||||||
*/
|
*/
|
||||||
protected $products;
|
protected $products;
|
||||||
|
|
||||||
|
|||||||
@@ -68,10 +68,13 @@ class SerializationUtility
|
|||||||
foreach ($images as $file)
|
foreach ($images as $file)
|
||||||
{
|
{
|
||||||
$image = $file->getOriginalResource();
|
$image = $file->getOriginalResource();
|
||||||
if (!\is_array($processingInstructions)) {
|
if (TYPO3_MODE === 'BE') {
|
||||||
|
$hostname = 'www.ep-reisen.de';
|
||||||
|
} else {
|
||||||
$hostname = GeneralUtility::getIndpEnv('HTTP_HOST');
|
$hostname = GeneralUtility::getIndpEnv('HTTP_HOST');
|
||||||
|
}
|
||||||
$data[] = 'https://' . $hostname . '/' . $image->getOriginalFile()->getPublicUrl();
|
if (!\is_array($processingInstructions)) {
|
||||||
|
$imageUrl = $image->getOriginalFile()->getPublicUrl();
|
||||||
} else {
|
} else {
|
||||||
$imageService = static::getImageService();
|
$imageService = static::getImageService();
|
||||||
$cropString = $image->getProperty('crop');
|
$cropString = $image->getProperty('crop');
|
||||||
@@ -80,8 +83,9 @@ class SerializationUtility
|
|||||||
$cropArea = $cropVariantCollection->getCropArea($cropVariant);
|
$cropArea = $cropVariantCollection->getCropArea($cropVariant);
|
||||||
$processingInstructions['crop'] = $cropArea->isEmpty() ? null : $cropArea->makeAbsoluteBasedOnFile($image);
|
$processingInstructions['crop'] = $cropArea->isEmpty() ? null : $cropArea->makeAbsoluteBasedOnFile($image);
|
||||||
$processedImage = $imageService->applyProcessingInstructions($image, $processingInstructions);
|
$processedImage = $imageService->applyProcessingInstructions($image, $processingInstructions);
|
||||||
$data[] = $imageService->getImageUri($processedImage, true);
|
$imageUrl = $processedImage->getPublicUrl();
|
||||||
}
|
}
|
||||||
|
$data[] = sprintf('https://%s/%s', $hostname, $imageUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'ep:export' => [
|
||||||
|
'class' => \EP\EpProducts\Command\ExportCommandController::class,
|
||||||
|
],
|
||||||
|
];
|
||||||
@@ -293,10 +293,10 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\EP\EpProducts\T
|
|||||||
'EP.' . $_EXTKEY,
|
'EP.' . $_EXTKEY,
|
||||||
'reseller',
|
'reseller',
|
||||||
[
|
[
|
||||||
'Reseller' => 'list,xml,copypaste,csv',
|
'Reseller' => 'list,copypaste',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'Reseller' => 'list,xml,copypaste,csv',
|
'Reseller' => 'list,copypaste',
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -370,11 +370,3 @@ $GLOBALS['TYPO3_CONF_VARS']['LOG']['EP']['EpProducts']['Controller']['writerConf
|
|||||||
];
|
];
|
||||||
|
|
||||||
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['teamSlug'] = \EP\EpProducts\Updates\TeamSlugUpdater::class;
|
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['teamSlug'] = \EP\EpProducts\Updates\TeamSlugUpdater::class;
|
||||||
|
|
||||||
if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['ep_products_reseller'])) {
|
|
||||||
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['ep_products_reseller'] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['ep_products_reseller']['backend'])) {
|
|
||||||
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['ep_products_reseller']['backend'] = \TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend::class;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -11,11 +11,17 @@
|
|||||||
<f:if condition="{reseller}">
|
<f:if condition="{reseller}">
|
||||||
<h1>{reseller.name}</h1>
|
<h1>{reseller.name}</h1>
|
||||||
<h2>Gesamtexport XML</h2>
|
<h2>Gesamtexport XML</h2>
|
||||||
<f:link.action action="xml" arguments="{reseller: reseller}" target="_blank">Export XML</f:link.action>
|
<f:link.typolink parameter="fileadmin/reseller/export_{reseller.code}.xml" target="_blank">
|
||||||
|
Export XML
|
||||||
|
</f:link.typolink>
|
||||||
<h2>Gesamtexport CSV (Facebook)</h2>
|
<h2>Gesamtexport CSV (Facebook)</h2>
|
||||||
<f:link.action action="csv" arguments="{reseller: reseller, type: 'facebook'}" target="_blank">Export CSV</f:link.action>
|
<f:link.typolink parameter="fileadmin/reseller/export_{reseller.code}_google.csv" target="_blank">
|
||||||
|
Export CSV (Google)
|
||||||
|
</f:link.typolink>
|
||||||
<h2>Gesamtexport CSV (Google)</h2>
|
<h2>Gesamtexport CSV (Google)</h2>
|
||||||
<f:link.action action="csv" arguments="{reseller: reseller, type: 'google'}" target="_blank">Export CSV</f:link.action>
|
<f:link.typolink parameter="fileadmin/reseller/export_{reseller.code}_facebook.csv" target="_blank">
|
||||||
|
Export CSV (Facebook)
|
||||||
|
</f:link.typolink>
|
||||||
<h2>Einzelexport für Copy&Paste</h2>
|
<h2>Einzelexport für Copy&Paste</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<f:for each="{products}" as="product">
|
<f:for each="{products}" as="product">
|
||||||
|
|||||||
Reference in New Issue
Block a user