Fixes
Some checks failed
Gitea Actions / Run-Tests-On-Amd64 (push) Failing after 40m13s
Gitea Actions / Merge (push) Successful in 6m14s
Gitea Actions / Run-Tests-On-Arm64 (push) Has been cancelled

This commit is contained in:
Thomas Peterson 2025-12-16 12:38:53 +01:00
parent 1cc2bc57ba
commit 7e7628bbd3
34 changed files with 512 additions and 239 deletions

View File

@ -2114,7 +2114,7 @@ CREATE TABLE `shop` (
`smtphostname` varchar(255) DEFAULT NULL,
`smtpusername` varchar(255) DEFAULT NULL,
`smtppassword` varchar(255) DEFAULT NULL,
`smtpusethis` int(1) NOT NULL,
`smtpusethis` int(1) NULL DEFAULT 0,
`useemailaslogin` int(1) NOT NULL,
`noverify` int(1) NOT NULL,
`keywords` longtext DEFAULT NULL,

View File

@ -5,7 +5,14 @@ declare(strict_types=1);
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->extension('doctrine', ['orm' => ['auto_generate_proxy_classes' => false, 'metadata_cache_driver' => ['type' => 'pool', 'pool' => 'doctrine.system_cache_pool'], 'query_cache_driver' => ['type' => 'pool', 'pool' => 'doctrine.system_cache_pool'], 'result_cache_driver' => ['type' => 'pool', 'pool' => 'doctrine.result_cache_pool']]]);
$containerConfigurator->extension('doctrine', ['orm' => [
'metadata_cache_driver' => ['type' => 'pool', 'pool' => 'doctrine.system_cache_pool'],
'query_cache_driver' => ['type' => 'pool', 'pool' => 'doctrine.system_cache_pool'],
'result_cache_driver' => ['type' => 'pool', 'pool' => 'doctrine.result_cache_pool'],
]]);
$containerConfigurator->extension('framework', ['cache' => ['pools' => ['doctrine.result_cache_pool' => ['adapter' => 'cache.app'], 'doctrine.system_cache_pool' => ['adapter' => 'cache.system']]]]);
$containerConfigurator->extension('framework', ['cache' => ['pools' => [
'doctrine.result_cache_pool' => ['adapter' => 'cache.app'],
'doctrine.system_cache_pool' => ['adapter' => 'cache.system'],
]]]);
};

View File

@ -2457,7 +2457,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
* length?: scalar|null, // Default: 5
* width?: scalar|null, // Default: 130
* height?: scalar|null, // Default: 50
* font?: scalar|null, // Default: "/data/www/new/vendor/gregwar/captcha-bundle/DependencyInjection/../Generator/Font/captcha.ttf"
* font?: scalar|null, // Default: "/application/src/new/vendor/gregwar/captcha-bundle/DependencyInjection/../Generator/Font/captcha.ttf"
* keep_value?: scalar|null, // Default: false
* charset?: scalar|null, // Default: "abcdefhjkmnprstuvwxyz23456789"
* as_file?: scalar|null, // Default: false

View File

@ -9,7 +9,7 @@ PSC\Shop\EntityBundle\Entity\Voucher:
code: 5f
mode: 1
fromDate: <(new DateTime("2023-12-12"))>
toDate: <(new DateTime("2025-12-12"))>
toDate: <(new DateTime("2026-12-12"))>
value: 5
shop: '@shop_1'
voucher_2:
@ -22,7 +22,7 @@ PSC\Shop\EntityBundle\Entity\Voucher:
code: 5p
mode: 1
fromDate: <(new DateTime("2023-12-12"))>
toDate: <(new DateTime("2025-12-12"))>
toDate: <(new DateTime("2026-12-12"))>
value: 5
shop: '@shop_1'
voucher_3:
@ -37,7 +37,7 @@ PSC\Shop\EntityBundle\Entity\Voucher:
zeroShipping: false
mode: 1
fromDate: <(new DateTime("2023-12-12"))>
toDate: <(new DateTime("2025-12-12"))>
toDate: <(new DateTime("2026-12-12"))>
value: 0
shop: '@shop_1'
voucher_4:
@ -52,7 +52,7 @@ PSC\Shop\EntityBundle\Entity\Voucher:
zeroShipping: true
mode: 1
fromDate: <(new DateTime("2023-12-12"))>
toDate: <(new DateTime("2025-12-12"))>
toDate: <(new DateTime("2026-12-12"))>
value: 0
shop: '@shop_1'

View File

@ -1780,7 +1780,7 @@ CREATE TABLE `shop` (
`smtphostname` varchar(255) NOT NULL,
`smtpusername` varchar(255) NOT NULL,
`smtppassword` varchar(255) NOT NULL,
`smtpusethis` int(1) NOT NULL,
`smtpusethis` int(1) NULL DEFAULT 0,
`useemailaslogin` int(1) NOT NULL,
`noverify` int(1) NOT NULL,
`keywords` longtext,

View File

@ -19,17 +19,11 @@ use PSC\Shop\EntityBundle\Entity\Domain;
use PSC\System\SettingsBundle\Service\Shop;
use Symfony\Bridge\Twig\Attribute\Template;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
/**
* ShopController fürs ProductionBundle
*
* @package PSC\Backend\Production
* @subpackage Controller
*/
class ShopController extends AbstractController
{
#[IsGranted('ROLE_SHOP')]
@ -88,24 +82,10 @@ class ShopController extends AbstractController
];
}
/**
* Change Shop
*
*
* @param Request $request
* @param EntityManagerInterface $em
* @param \Symfony\Component\Security\Core\Security $security
* @param $shop_uuid
* @return RedirectResponse
*/
#[IsGranted('ROLE_SHOP')]
#[Route(path: '/shop/change/{shop_uuid}', name: 'psc_backend_dashboard_shop_change')]
public function changeShopAction(
Request $request,
EntityManagerInterface $em,
\Symfony\Component\Security\Core\Security $security,
$shop_uuid,
) {
public function changeShopAction(Request $request, EntityManagerInterface $em, Security $security, $shop_uuid)
{
$em->getRepository('PSC\Shop\EntityBundle\Entity\ShopContact')->changeSelectedShop(
$security->getUser(),
$shop_uuid,
@ -114,23 +94,12 @@ class ShopController extends AbstractController
return $this->redirect($this->generateUrl('psc_backend_dashboard_index'));
}
/**
* Change Shop
*
*
* @param Request $request
* @param EntityManagerInterface $em
* @param \Symfony\Component\Security\Core\Security $security
* @param Shop $shopService
* @return RedirectResponse
* @throws \Doctrine\ORM\ORMException
*/
#[IsGranted('ROLE_SHOP')]
#[Route(path: '/shop/deleted/toogle', name: 'psc_backend_dashboard_toogle_deleted_shop')]
public function toogleDisplayDeletedShopAction(
Request $request,
EntityManagerInterface $em,
\Symfony\Component\Security\Core\Security $security,
Security $security,
Shop $shopService,
) {
/** @var \PSC\Shop\EntityBundle\Entity\Shop $selectedShop */

View File

@ -5,6 +5,7 @@ namespace PSC\Shop\OrderBundle\Normalizer;
use BadMethodCallException;
use PSC\Shop\OrderBundle\Model\Order\Position\IProductTypeObject;
use PSC\System\PluginBundle\Service\ProductType;
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
@ -45,6 +46,6 @@ class SpecialProductDenormalizer implements DenormalizerInterface, DenormalizerA
public function getSupportedTypes(null|string $format): array
{
return [IProductTypeObject::class];
return [IProductTypeObject::class => true];
}
}

View File

@ -34,3 +34,7 @@ services:
PSC\Shop\OrderBundle\Api\Position\GetPluginListDisplay:
arguments:
- !tagged_iterator order.backend.list.position
PSC\Shop\OrderBundle\Normalizer\SpecialProductDenormalizer:
tags:
- { name: serializer.normalizer, priority: 1000 }

View File

@ -8,18 +8,18 @@ use PSC\Shop\VoucherBundle\Model\Voucher as PSCVoucher;
class Voucher
{
public function __construct(private VoucherRepository $voucherRepository)
{
}
public function __construct(
private VoucherRepository $voucherRepository,
) {}
public function getVoucherForCode(string $code, Shop $shop): ?PSCVoucher
public function getVoucherForCode(string $code, Shop $shop): null|PSCVoucher
{
$voucherEntity = $this->voucherRepository->findByCodeForActDate($code, $shop);
if($voucherEntity) {
if ($voucherEntity) {
$v = new PSCVoucher();
$v->setMore($voucherEntity->isMore());
$v->setCode($code);
if($voucherEntity->isPercent()) {
if ($voucherEntity->isPercent()) {
$v->setPercentValue($voucherEntity->getValue());
} else {
$v->setValueInCent($voucherEntity->getValue() * 100);

View File

@ -11,9 +11,9 @@ use OpenApi\Attributes\Response;
use OpenApi\Attributes\Tag;
use PSC\System\SettingsBundle\Model\Papercontainer;
use PSC\System\SettingsBundle\Service\Shop;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
@ -39,7 +39,7 @@ class Update extends AbstractController
#[Route(path: '/papercontainer', methods: ['PUT'])]
#[RequestBody(content: new JsonContent(ref: new Model(type: Papercontainer::class)))]
#[IsGranted('ROLE_USER')]
public function updatePapercontainer(Papercontainer $papercontainer): JsonResponse
public function updatePapercontainer(#[MapRequestPayload] Papercontainer $papercontainer): JsonResponse
{
$install = $this->shopService->getShopByDomain()->getInstall();
$install->setPaperContainer($papercontainer->getContent());

View File

@ -2,10 +2,10 @@
namespace Tests\PSC\Shop\Contact\Api;
use Tests\RefreshDatabaseTrait;
use PSC\Shop\ContactBundle\Repository\ContactRepository;
use PSC\Shop\EntityBundle\Repository\ShopRepository;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Tests\RefreshDatabaseTrait;
class AllTest extends WebTestCase
{
@ -26,9 +26,8 @@ class AllTest extends WebTestCase
$data = json_decode($client->getResponse()->getContent(), true);
self::assertSame(3, count($data['data']));
self::assertSame("test3@shop.de", $data['data'][0]['email']);
self::assertSame("test@shop.de", $data['data'][1]['email']);
self::assertSame("admin@shop.de", $data['data'][2]['email']);
self::assertSame('test3@shop.de', $data['data'][1]['email']);
self::assertSame('test@shop.de', $data['data'][0]['email']);
self::assertSame('admin@shop.de', $data['data'][2]['email']);
}
}

View File

@ -1,10 +1,11 @@
<?php
namespace Tests\PSC\Shop\Payment\Controller;
use Tests\RefreshDatabaseTrait;
use PSC\Shop\ContactBundle\Repository\ContactRepository;
use PSC\Shop\EntityBundle\Repository\ShopRepository;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Tests\RefreshDatabaseTrait;
class ListTest extends WebTestCase
{
@ -27,7 +28,7 @@ class ListTest extends WebTestCase
$crawler = $client->request('GET', '/backend/payment/list/index');
$this->assertResponseIsSuccessful();
$crawler = $crawler->filter('.table > tbody > tr');
$crawler = $crawler->filter('table > tbody > tr');
$this->assertSame(4, $crawler->count());
}
}

View File

@ -20,11 +20,7 @@ class ListTest extends PantherTestCase
$chromeOptions->addArguments(['--window-size=1200,1100', '--disable-gpu']);
$capabilities = DesiredCapabilities::chrome();
$capabilities->setCapability(ChromeOptions::CAPABILITY, $chromeOptions);
$this->client = Client::createSeleniumClient(
'http://chrome:4444',
$capabilities,
'http://application:9001'
);
$this->client = Client::createSeleniumClient('http://chrome:4444', $capabilities, 'http://application:9001');
static::startWebServer(['hostname' => 'application']);
}
@ -40,9 +36,20 @@ class ListTest extends PantherTestCase
$this->client->get('/backend/login');
$crawler = $this->client->submitForm('login', ['username' => 'admin@shop.de', 'password' => 'shop2014']);
$crawler = $this->client->get('/backend/dashboard');
self::assertSame('Dashboard', $this->client->getCrawler()->filter('h1')->text());
self::assertSame(
'Dashboard',
$this->client
->getCrawler()
->filter('h1')
->text(),
);
$crawler = $this->client->clickLink('Zahlarten');
self::assertStringContainsString('Zahlarten', $this->client->getCrawler()->filter('h3')->text());
self::assertStringContainsString(
'Zahlarten',
$this->client
->getCrawler()
->filter('h1')
->text(),
);
}
}

View File

@ -1,10 +1,11 @@
<?php
namespace App\Tests\PSC\Shop\Shipping\Controller;
use Tests\RefreshDatabaseTrait;
use PSC\Shop\ContactBundle\Repository\ContactRepository;
use PSC\Shop\EntityBundle\Repository\ShopRepository;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Tests\RefreshDatabaseTrait;
class ListTest extends WebTestCase
{
@ -27,7 +28,8 @@ class ListTest extends WebTestCase
$crawler = $client->request('GET', '/backend/shipping/list/index');
$this->assertResponseIsSuccessful();
$crawler = $crawler->filter('.table > tbody > tr');
$crawler = $crawler->filter('table > tbody > tr');
$this->assertSame(4, $crawler->count());
}
}

View File

@ -2114,7 +2114,7 @@ CREATE TABLE `shop` (
`smtphostname` varchar(255) DEFAULT NULL,
`smtpusername` varchar(255) DEFAULT NULL,
`smtppassword` varchar(255) DEFAULT NULL,
`smtpusethis` int(1) NOT NULL,
`smtpusethis` int(1) DEFAULT 0,
`useemailaslogin` int(1) NOT NULL,
`noverify` int(1) NOT NULL,
`keywords` longtext DEFAULT NULL,

View File

@ -2110,7 +2110,7 @@ CREATE TABLE `shop` (
`smtphostname` varchar(255) DEFAULT NULL,
`smtpusername` varchar(255) DEFAULT NULL,
`smtppassword` varchar(255) DEFAULT NULL,
`smtpusethis` int(1) NOT NULL,
`smtpusethis` int(1) NULL DEFAULT 0,
`useemailaslogin` int(1) NOT NULL,
`noverify` int(1) NOT NULL,
`keywords` longtext DEFAULT NULL,

View File

@ -5,15 +5,14 @@ namespace Plugin\Custom\PSC\FormBuilder\Api\Layout;
use Doctrine\ODM\MongoDB\DocumentManager;
use Nelmio\ApiDocBundle\Attribute\Model;
use Nelmio\ApiDocBundle\Attribute\Security;
use OpenApi\Attributes\JsonContent;
use OpenApi\Attributes\RequestBody;
use OpenApi\Attributes\Response;
use OpenApi\Attributes\Tag;
use Plugin\Custom\PSC\FormBuilder\Document\Layout as PSCLayout;
use Plugin\Custom\PSC\FormBuilder\Dto\Layout\Input;
use Plugin\Custom\PSC\FormBuilder\Model\Layout;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
@ -27,10 +26,9 @@ class Add extends AbstractController
#[Route(path: '/layouts/add', methods: ['POST'])]
#[Tag('FormBuilder')]
#[RequestBody(content: new Model(type: Input::class))]
#[ParamConverter('data', class: Input::class, converter: 'psc_rest.request_body')]
#[IsGranted('ROLE_ADMIN')]
#[Security(name: 'Security')]
public function add(Input $data)
public function add(#[MapRequestPayload] Input $data)
{
$layout = new PSCLayout();
$layout->setTitle($data->title);

View File

@ -0,0 +1,64 @@
<?php
namespace Plugin\Custom\PSC\LaufkartenLayouter\Api;
use Doctrine\ODM\MongoDB\DocumentManager;
use Doctrine\ORM\EntityManagerInterface;
use MongoDB\BSON\ObjectId;
use OpenApi\Attributes\Parameter;
use OpenApi\Attributes\Response;
use OpenApi\Attributes\Tag;
use PSC\Shop\EntityBundle\Entity\Layoutdesigndata;
use PSC\Shop\MediaBundle\Document\Media;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Attribute\Route;
class Load
{
#[Response(response: 200, description: 'loaded successfully')]
#[Response(response: 404, description: 'Layouter session not found')]
#[Route('/load/{layouterUUId}', name: 'plugin_custom_psc_laufkartenlayouter_load', methods: ['GET'])]
#[Tag(name: 'Plugin/Custom/PSC/LaufkartenLayouter')]
#[Parameter(name: 'layouterUUId', in: 'path', required: true, description: 'Layouter UUID')]
public function loadAction(
string $layouterUUId,
EntityManagerInterface $entityManager,
DocumentManager $documentManager,
): JsonResponse {
/** @var Layoutdesigndata|null $layoutDesignData */
$layoutDesignData = $entityManager
->getRepository(Layoutdesigndata::class)
->findOneBy(['uuid' => $layouterUUId]);
if (!$layoutDesignData) {
return new JsonResponse(['error' => 'Layouter session not found'], JsonResponse::HTTP_NOT_FOUND);
}
$design = $layoutDesignData->getDesign();
$files = $design['files'] ?? [];
// Enrich files with media URLs
$enrichedFiles = [];
foreach ($files as $fileData) {
$mediaUuid = $fileData['uuid'] ?? null;
if ($mediaUuid) {
/** @var Media|null $media */
$media = $documentManager
->getRepository(Media::class)
->findOneBy(['_id' => new ObjectId($mediaUuid['$oid'])]);
if ($media) {
$fileData['url'] = $media->getUrl();
}
}
$enrichedFiles[] = $fileData;
}
return new JsonResponse([
'success' => true,
'layouterUUId' => $layoutDesignData->getUuid(),
'productUUId' => $layoutDesignData->getArticleUuid(),
'files' => $enrichedFiles,
]);
}
}

View File

@ -19,17 +19,25 @@ class Save
#[Tag(name: 'Plugin/Custom/PSC/LaufkartenLayouter')]
public function saveAction(#[MapRequestPayload] Input $data, EntityManagerInterface $entityManager): JsonResponse
{
// Check if layouter session already exists (edit mode)
$layoutDesignData = $entityManager
->getRepository(Layoutdesigndata::class)
->findOneBy(['uuid' => $data->layouterUUId]);
if ($layoutDesignData) {
// Update existing session
$layoutDesignData->setDesign(['files' => $data->files]);
} else {
// Create new session
$layoutDesignData = new Layoutdesigndata();
$layoutDesignData->setUuid($data->layouterUUId);
$layoutDesignData->setArticleUuid($data->productUUId);
$layoutDesignData->setDesign(['files' => $data->files]);
$entityManager->persist($layoutDesignData);
}
$entityManager->flush();
$json = new JsonResponse();
$json->setContent(json_encode(['success' => true]));
return $json;
return new JsonResponse(['success' => true]);
}
}

View File

@ -212,10 +212,96 @@
let pdfData = [];
let thumbnails = {};
let ocrPreviews = {};
const layouterUUId = '{{ layouterUUId }}';
const isEditMode = layouterUUId && layouterUUId !== '';
// Initialize PDF.js
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
// Load existing layouter session if in edit mode
async function loadLayouterSession() {
if (!isEditMode) {
return;
}
try {
const response = await fetch(`/apps/api/plugin/custom/psc/laufkartenlayouter/load/${layouterUUId}`);
if (!response.ok) {
throw new Error(`Failed to load layouter session: ${response.status}`);
}
const data = await response.json();
console.log('Loaded layouter session:', data);
if (data.files && data.files.length > 0) {
// Convert loaded files to uploadedFiles format
// We need to fetch the actual PDF files from the media URLs
const loadingPromises = data.files.map(async (fileData) => {
try {
// Fetch the PDF file from the URL
const pdfResponse = await fetch(fileData.url || '');
const pdfBlob = await pdfResponse.blob();
const pdfFile = new File([pdfBlob], fileData.fileName, { type: 'application/pdf' });
return {
file: pdfFile,
uuid: fileData.uuid,
fileName: fileData.fileName,
ocrNumber: fileData.ocrNumber || '',
inRed: fileData.inRed || false,
numPages: fileData.numPages || 0,
isDuplex: fileData.isDuplex || false
};
} catch (error) {
console.error(`Failed to load file ${fileData.fileName}:`, error);
return null;
}
});
const loadedFiles = (await Promise.all(loadingPromises)).filter(f => f !== null);
if (loadedFiles.length > 0) {
// Populate uploadedFiles and enable next button
uploadedFiles = loadedFiles.map(f => f.file);
displayUploadedFiles();
document.getElementById('nextToStep2').disabled = false;
// Pre-populate pdfData with loaded metadata
pdfData = loadedFiles.map((fileData, index) => ({
index: index,
file: fileData.file,
fileName: fileData.fileName,
numPages: fileData.numPages,
isDuplex: fileData.isDuplex,
ocrNumber: fileData.ocrNumber,
inRed: fileData.inRed,
processed: fileData.ocrNumber ? true : false,
uploadedUuid: fileData.uuid,
isAlreadyUploaded: true // Mark as already uploaded
}));
// Initialize placeholder thumbnails for loaded files
pdfData.forEach((pdf, index) => {
thumbnails[index] = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjAiIGhlaWdodD0iODAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHJlY3Qgd2lkdGg9IjYwIiBoZWlnaHQ9IjgwIiBmaWxsPSIjZTVlN2ViIi8+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZvbnQtc2l6ZT0iMTQiIGZpbGw9IiM5Y2EzYWYiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGRvbWluYW50LWJhc2VsaW5lPSJtaWRkbGUiPlBERjwvdGV4dD48L3N2Zz4=';
});
console.log(`Loaded ${loadedFiles.length} files from saved session`);
}
}
} catch (error) {
console.error('Error loading layouter session:', error);
alert('Fehler beim Laden der gespeicherten Session: ' + error.message);
}
}
// Initialize on page load
document.addEventListener('DOMContentLoaded', () => {
if (isEditMode) {
loadLayouterSession();
}
});
// Save current form values
function saveCurrentFormValues() {
if (currentStep === 2 && pdfData.length > 0) {
@ -233,7 +319,7 @@
}
// Step navigation
function goToStep(step) {
async function goToStep(step) {
// Save current values before switching
saveCurrentFormValues();
@ -262,19 +348,174 @@
currentStep = step;
if (step === 2) {
// Check if we have more uploadedFiles than pdfData (new files added)
const hasNewFiles = uploadedFiles.length > pdfData.length;
if (uploadedFiles.length > 0 && pdfData.length === 0) {
// First time going to step 2
initializePDFData();
// First time going to step 2 - initialize PDFs
await initializePDFData();
} else if (hasNewFiles) {
// New files were added - initialize only the new ones
await initializeNewPDFData();
} else if (pdfData.length > 0) {
// Returning to step 2, refresh table with saved values
// Already have pdfData (from loading or previous visit)
// Check if we need to generate real thumbnails (not just placeholders)
const needsThumbnails = pdfData.some((pdf, index) => {
const thumb = thumbnails[index];
return !thumb || thumb.includes('data:image/svg+xml');
});
if (needsThumbnails) {
await generateThumbnailsForLoadedData();
} else {
// Just refresh table with existing data
updatePDFTable();
}
}
}
if (step === 3) {
generateFinalSummary();
}
}
// Initialize only newly added PDF files (when files are added in edit mode)
async function initializeNewPDFData() {
const startIndex = pdfData.length;
const newFiles = uploadedFiles.slice(startIndex);
if (newFiles.length === 0) {
return;
}
const initialLoading = document.getElementById('initialLoading');
const initialProgressBar = document.getElementById('initial-progress-bar');
const initialProgressText = document.getElementById('initial-progress-text');
const pdfTableContainer = document.getElementById('pdfTableContainer');
const progressBar = document.getElementById('loading-progress-bar');
const progressText = document.getElementById('loading-progress-text');
const progressContainer = document.getElementById('loading-progress');
// Show loading
initialLoading.classList.remove('hidden');
pdfTableContainer.classList.add('hidden');
// Phase 1: Quick metadata loading for new files
for (let i = 0; i < newFiles.length; i++) {
const file = newFiles[i];
const fileReader = new FileReader();
const globalIndex = startIndex + i;
const progress1 = Math.round(((i + 1) / newFiles.length) * 100);
initialProgressBar.style.width = `${progress1}%`;
initialProgressText.textContent = `${i + 1} / ${newFiles.length}`;
await new Promise((resolve) => {
fileReader.onload = async function() {
const typedArray = new Uint8Array(this.result);
const pdf = await pdfjsLib.getDocument(typedArray).promise;
const numPages = pdf.numPages;
pdfData.push({
index: globalIndex,
file: file,
fileName: file.name,
numPages: numPages,
isDuplex: numPages % 2 === 0 && numPages > 1,
ocrNumber: '',
inRed: false,
processed: false,
isAlreadyUploaded: false // Mark as NOT uploaded yet
});
thumbnails[globalIndex] = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjAiIGhlaWdodD0iODAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHJlY3Qgd2lkdGg9IjYwIiBoZWlnaHQ9IjgwIiBmaWxsPSIjZTVlN2ViIi8+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZvbnQtc2l6ZT0iMTQiIGZpbGw9IiM5Y2EzYWYiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGRvbWluYW50LWJhc2VsaW5lPSJtaWRkbGUiPlBERjwvdGV4dD48L3N2Zz4=';
resolve();
};
fileReader.readAsArrayBuffer(file);
});
}
// Hide initial loading, show table
initialLoading.classList.add('hidden');
pdfTableContainer.classList.remove('hidden');
updatePDFTable();
// Show Phase 2 progress
progressContainer.classList.remove('hidden');
// Phase 2: Generate thumbnails for ALL files (old placeholders + new files)
const filesToProcess = [];
// Add old files that still have placeholders
for (let i = 0; i < startIndex; i++) {
const thumb = thumbnails[i];
if (!thumb || thumb.includes('data:image/svg+xml')) {
filesToProcess.push(i);
}
}
// Add all new files
for (let i = 0; i < newFiles.length; i++) {
filesToProcess.push(startIndex + i);
}
// Generate thumbnails
for (let i = 0; i < filesToProcess.length; i++) {
const fileIndex = filesToProcess[i];
const progress = Math.round(((i + 1) / filesToProcess.length) * 100);
progressBar.style.width = `${progress}%`;
progressText.textContent = `Lade Vorschau ${i + 1}/${filesToProcess.length}`;
await generateThumbnail(fileIndex);
updatePDFTable();
await new Promise(resolve => setTimeout(resolve, 10));
}
progressContainer.classList.add('hidden');
}
// Generate thumbnails for already loaded data (from session)
async function generateThumbnailsForLoadedData() {
const initialLoading = document.getElementById('initialLoading');
const pdfTableContainer = document.getElementById('pdfTableContainer');
const progressBar = document.getElementById('loading-progress-bar');
const progressText = document.getElementById('loading-progress-text');
const progressContainer = document.getElementById('loading-progress');
// Show loading
initialLoading.classList.remove('hidden');
pdfTableContainer.classList.add('hidden');
// Initialize with placeholders
pdfData.forEach((pdf, index) => {
thumbnails[index] = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjAiIGhlaWdodD0iODAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHJlY3Qgd2lkdGg9IjYwIiBoZWlnaHQ9IjgwIiBmaWxsPSIjZTVlN2ViIi8+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZvbnQtc2l6ZT0iMTQiIGZpbGw9IiM5Y2EzYWYiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGRvbWluYW50LWJhc2VsaW5lPSJtaWRkbGUiPlBERjwvdGV4dD48L3N2Zz4=';
});
// Show table immediately
initialLoading.classList.add('hidden');
pdfTableContainer.classList.remove('hidden');
updatePDFTable();
if (pdfData.length > 0) {
loadPDFInfo(0);
}
// Generate thumbnails in background
progressContainer.classList.remove('hidden');
for (let i = 0; i < pdfData.length; i++) {
const progress = Math.round(((i + 1) / pdfData.length) * 100);
progressBar.style.width = `${progress}%`;
progressText.textContent = `Lade Vorschau ${i + 1}/${pdfData.length}`;
await generateThumbnail(i);
updatePDFTable();
await new Promise(resolve => setTimeout(resolve, 10));
}
progressContainer.classList.add('hidden');
}
// Initialize PDF data and table
async function initializePDFData() {
pdfData = [];
@ -316,7 +557,8 @@
isDuplex: numPages % 2 === 0 && numPages > 1,
ocrNumber: '',
inRed: false,
processed: false
processed: false,
isAlreadyUploaded: false // New files need to be uploaded
});
// Use placeholder thumbnail initially
@ -844,21 +1086,30 @@
const uploadedUUIDs = [];
for (let i = 0; i < pdfData.length; i++) {
let uploadUuid;
// Check if this file was already uploaded (from loaded session or previous upload)
if (pdfData[i].isAlreadyUploaded && pdfData[i].uploadedUuid) {
console.log(`Skipping upload for ${pdfData[i].fileName} - already uploaded (UUID: ${pdfData[i].uploadedUuid})`);
uploadUuid = pdfData[i].uploadedUuid;
} else {
// Upload new file
finishBtn.textContent = `Uploading PDFs... (${i + 1}/${pdfData.length})`;
const uploadResult = await uploadSinglePDF(pdfData[i], i);
uploadUuid = uploadResult.uuid;
pdfData[i].uploadedUuid = uploadUuid;
pdfData[i].isAlreadyUploaded = true; // Mark as uploaded now
console.log(`Uploaded ${pdfData[i].fileName}: ${uploadUuid}`);
}
// Store UUID in pdfData
pdfData[i].uploadedUuid = uploadResult.uuid;
uploadedUUIDs.push({
uuid: uploadResult.uuid,
uuid: uploadUuid,
fileName: pdfData[i].fileName,
ocrNumber: pdfData[i].ocrNumber,
inRed: pdfData[i].inRed,
numPages: pdfData[i].numPages,
isDuplex: pdfData[i].isDuplex
});
console.log(`Uploaded ${pdfData[i].fileName}: ${uploadResult.uuid}`);
}
// Step 2: Call layouter/save with all UUIDs

View File

@ -2,7 +2,6 @@
namespace Plugin\System\PSC\CaptchaFox\Api;
use Nelmio\ApiDocBundle\Annotation\Model;
use OpenApi\Attributes\JsonContent;
use OpenApi\Attributes\RequestBody;
@ -10,30 +9,30 @@ use OpenApi\Attributes\Response;
use OpenApi\Attributes\Tag;
use phpDocumentor\Reflection\Types\Boolean;
use Plugin\System\PSC\FriendlyCaptcha\Dto\Input;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpClient\Exception\ClientException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\HttpClient\HttpClientInterface;
class Validate extends AbstractController
{
public function __construct(
private readonly \PSC\System\SettingsBundle\Service\Shop $shopService,
private readonly HttpClientInterface $client,
) {}
public function __construct(private readonly \PSC\System\SettingsBundle\Service\Shop $shopService, private readonly HttpClientInterface $client)
{
}
#[RequestBody(description: 'contact',content: new JsonContent(ref: new Model(type: Input::class)))]
#[Response(response: 200, description: 'validate token', content: new JsonContent(ref: new Model(type: Boolean::class)))]
#[ParamConverter('data', class: Input::class, converter: 'psc_rest.request_body')]
#[RequestBody(description: 'contact', content: new JsonContent(ref: new Model(type: Input::class)))]
#[Response(
response: 200,
description: 'validate token',
content: new JsonContent(ref: new Model(type: Boolean::class)),
)]
#[Tag('Plugin/System/PSC/CaptchaFox')]
#[Route(path: '/validate', methods: ['POST'])]
public function validate(Input $data): JsonResponse
public function validate(#[MapRequestPayload] Input $data): JsonResponse
{
$shop = $this->shopService->getMongoShopByUid($this->shopService->getShopByUid($data->shop_uuid)->getUID());
try {
@ -41,16 +40,15 @@ class Validate extends AbstractController
'body' => [
'solution' => $data->token,
'sitekey' => $shop->getPluginSettingModule('captchafox', 'sitekey'),
'secret' => $shop->getPluginSettingModule('captchafox', 'secret')
'secret' => $shop->getPluginSettingModule('captchafox', 'secret'),
],
]);
}catch(ClientException $e) {
if($e->getCode() == 400) {
} catch (ClientException $e) {
if ($e->getCode() == 400) {
return new JsonResponse(['success' => false]);
}
}
return new JsonResponse(json_decode($response->getContent(), true));
}
}

View File

@ -2,7 +2,6 @@
namespace Plugin\System\PSC\FriendlyCaptcha\Api;
use Nelmio\ApiDocBundle\Annotation\Model;
use OpenApi\Attributes\JsonContent;
use OpenApi\Attributes\RequestBody;
@ -10,30 +9,30 @@ use OpenApi\Attributes\Response;
use OpenApi\Attributes\Tag;
use phpDocumentor\Reflection\Types\Boolean;
use Plugin\System\PSC\FriendlyCaptcha\Dto\Input;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpClient\Exception\ClientException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\HttpClient\HttpClientInterface;
class Validate extends AbstractController
{
public function __construct(
private readonly \PSC\System\SettingsBundle\Service\Shop $shopService,
private readonly HttpClientInterface $client,
) {}
public function __construct(private readonly \PSC\System\SettingsBundle\Service\Shop $shopService, private readonly HttpClientInterface $client)
{
}
#[RequestBody(description: 'contact',content: new JsonContent(ref: new Model(type: Input::class)))]
#[Response(response: 200, description: 'validate token', content: new JsonContent(ref: new Model(type: Boolean::class)))]
#[ParamConverter('data', class: Input::class, converter: 'psc_rest.request_body')]
#[RequestBody(description: 'contact', content: new JsonContent(ref: new Model(type: Input::class)))]
#[Response(
response: 200,
description: 'validate token',
content: new JsonContent(ref: new Model(type: Boolean::class)),
)]
#[Tag('Plugin/System/PSC/FriendlyCaptcha')]
#[Route(path: '/validate', methods: ['POST'])]
public function validate(Input $data): JsonResponse
public function validate(#[MapRequestPayload] Input $data): JsonResponse
{
$shop = $this->shopService->getMongoShopByUid($this->shopService->getShopByUid($data->shop_uuid)->getUID());
try {
@ -41,16 +40,15 @@ class Validate extends AbstractController
'body' => [
'solution' => $data->token,
'sitekey' => $shop->getPluginSettingModule('friendlycaptcha', 'sitekey'),
'secret' => $shop->getPluginSettingModule('friendlycaptcha', 'secret')
'secret' => $shop->getPluginSettingModule('friendlycaptcha', 'secret'),
],
]);
}catch(ClientException $e) {
if($e->getCode() == 400) {
} catch (ClientException $e) {
if ($e->getCode() == 400) {
return new JsonResponse(['success' => false]);
}
}
return new JsonResponse(json_decode($response->getContent(), true));
}
}

View File

@ -16,8 +16,8 @@ use PSC\Library\Calc\PaperContainer;
use PSC\Shop\ContactBundle\Model\Contact;
use PSC\Shop\ContactBundle\Transformer\Model\Contact as ContactTransformer;
use PSC\System\SettingsBundle\Service\PaperDB;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
@ -40,12 +40,7 @@ class Config extends AbstractController
#[RequestBody(content: new JsonContent(ref: new Model(type: PriceInput::class)))]
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Product')]
#[Route(path: '/product/config', methods: ['POST'])]
#[ParamConverter(
'data',
class: '\Plugin\System\PSC\XmlCalc\Dto\Input\PriceInput',
converter: 'psc_rest.request_body',
)]
public function config(PriceInput $data)
public function config(#[MapRequestPayload] PriceInput $data)
{
$product = $this->entityManager
->getRepository('PSC\Shop\EntityBundle\Entity\Product')

View File

@ -11,16 +11,13 @@ use OpenApi\Attributes\Response;
use OpenApi\Attributes\Tag;
use Plugin\System\PSC\XmlCalc\Dto\Input\DesignInput;
use Plugin\System\PSC\XmlCalc\Model\Product as PluginProduct;
use PSC\Component\ApiBundle\Dto\Error\NotFound;
use PSC\Library\Calc\Engine;
use PSC\Library\Calc\PaperContainer;
use PSC\Shop\ContactBundle\Model\Contact;
use PSC\Shop\ContactBundle\Transformer\Model\Contact as ContactTransformer;
use PSC\Shop\EntityBundle\Entity\Product;
use PSC\System\SettingsBundle\Service\PaperDB;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
@ -43,12 +40,7 @@ class Design extends AbstractController
#[RequestBody(content: new JsonContent(ref: new Model(type: DesignInput::class)))]
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Product')]
#[Route(path: '/product/design', methods: ['POST'])]
#[ParamConverter(
'data',
class: '\Plugin\System\PSC\XmlCalc\Dto\Input\DesignInput',
converter: 'psc_rest.request_body',
)]
public function config(DesignInput $data)
public function config(#[MapRequestPayload] DesignInput $data)
{
$product = $this->entityManager
->getRepository('PSC\Shop\EntityBundle\Entity\Product')

View File

@ -11,16 +11,13 @@ use OpenApi\Attributes\Response;
use OpenApi\Attributes\Tag;
use Plugin\System\PSC\XmlCalc\Dto\Input\JsonInput;
use Plugin\System\PSC\XmlCalc\Model\Product as PluginProduct;
use PSC\Component\ApiBundle\Dto\Error\NotFound;
use PSC\Library\Calc\Engine;
use PSC\Library\Calc\PaperContainer;
use PSC\Shop\ContactBundle\Model\Contact;
use PSC\Shop\ContactBundle\Transformer\Model\Contact as ContactTransformer;
use PSC\Shop\EntityBundle\Entity\Product;
use PSC\System\SettingsBundle\Service\PaperDB;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
@ -43,12 +40,7 @@ class Json extends AbstractController
#[RequestBody(content: new JsonContent(ref: new Model(type: JsonInput::class)))]
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Product')]
#[Route(path: '/product/json', methods: ['POST'])]
#[ParamConverter(
'data',
class: '\Plugin\System\PSC\XmlCalc\Dto\Input\JsonInput',
converter: 'psc_rest.request_body',
)]
public function jsonApi(JsonInput $data)
public function jsonApi(#[MapRequestPayload] JsonInput $data)
{
$product = $this->entityManager
->getRepository('PSC\Shop\EntityBundle\Entity\Product')

View File

@ -3,25 +3,27 @@
namespace Plugin\System\PSC\XmlCalc\Api\Product;
use Doctrine\ORM\EntityManagerInterface;
use Nelmio\ApiDocBundle\Annotation\Model;
use Nelmio\ApiDocBundle\Annotation\Security;
use OpenApi\Annotations as OA;
use Plugin\System\PSC\XmlCalc\Model\Product as PluginProduct;
use PSC\Component\ApiBundle\Dto\Error\NotFound;
use PSC\Shop\EntityBundle\Entity\Product;
use PSC\System\SettingsBundle\Service\Shop;
use Plugin\System\PSC\XmlCalc\Model\Product as PluginProduct;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
use OpenApi\Annotations as OA;
use Nelmio\ApiDocBundle\Annotation\Model;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Nelmio\ApiDocBundle\Annotation\Security;
class One extends AbstractController {
class One extends AbstractController
{
private EntityManagerInterface $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
/**
* get special product
*
@ -38,11 +40,11 @@ class One extends AbstractController {
public function one(string $uuid): JsonResponse
{
$product = $this->entityManager->getRepository(Product::class)->findOneBy(['uuid' => $uuid]);
if($product) {
if ($product) {
$output = new PluginProduct();
$output->calcXml = $product->getCalcXml();
}else{
$output = new NotFound("product not found");
} else {
$output = new NotFound('product not found');
}
return $this->json($output);
}

View File

@ -34,6 +34,7 @@ use PSC\System\SettingsBundle\Service\Help;
use PSC\System\SettingsBundle\Service\PaperDB;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
@ -84,12 +85,7 @@ class Preview extends AbstractController
#[RequestBody(content: new JsonContent(ref: new Model(type: PriceInput::class)))]
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Price')]
#[Route(path: '/product/preview', methods: ['POST'])]
#[ParamConverter(
'data',
class: '\Plugin\System\PSC\XmlCalc\Dto\Input\PriceInput',
converter: 'psc_rest.request_body',
)]
public function preview(PriceInput $data)
public function preview(#[MapRequestPayload] PriceInput $data)
{
$output = new \Plugin\System\PSC\XmlCalc\Dto\Output\PriceOutput();
$output->product = $data->product;

View File

@ -29,6 +29,7 @@ use PSC\System\SettingsBundle\Service\Help;
use PSC\System\SettingsBundle\Service\PaperDB;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
@ -79,8 +80,7 @@ class PreviewDesigner extends AbstractController
)]
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Price')]
#[RequestBody(content: new JsonContent(ref: new Model(type: PDInput::class)))]
#[ParamConverter('data', class: '\Plugin\System\PSC\XmlCalc\Dto\Input\PDInput', converter: 'psc_rest.request_body')]
public function preview(PDInput $data)
public function preview(#[MapRequestPayload] PDInput $data)
{
$output = new \Plugin\System\PSC\XmlCalc\Dto\Output\Product\PDOutput();

View File

@ -12,11 +12,12 @@ use OpenApi\Attributes\Tag;
use Plugin\System\PSC\XmlCalc\Model\Product;
use PSC\Component\ApiBundle\Dto\Error\NotFound;
use PSC\Shop\EntityBundle\Entity\Product as PSCProduct;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class Update extends AbstractController
{
@ -36,13 +37,8 @@ class Update extends AbstractController
#[RequestBody(content: new JsonContent(ref: new Model(type: Product::class)))]
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Product')]
#[Route(path: '/product/{uuid}', methods: ['PUT'])]
#[ParamConverter(
'productObj',
class: '\Plugin\System\PSC\XmlCalc\Model\Product',
converter: 'psc_rest.request_body',
)]
#[IsGranted('ROLE_USER')]
public function update(string $uuid, Product $productObj): JsonResponse
public function update(string $uuid, #[MapRequestPayload] Product $productObj): JsonResponse
{
$product = $this->entityManager->getRepository(PSCProduct::class)->findOneBy(['uuid' => $uuid]);

View File

@ -18,9 +18,9 @@ use PSC\Shop\ContactBundle\Model\Contact;
use PSC\Shop\ContactBundle\Transformer\Model\Contact as ContactTransformer;
use PSC\Shop\EntityBundle\Entity\Product;
use PSC\System\SettingsBundle\Service\PaperDB;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
@ -43,12 +43,7 @@ class XML extends AbstractController
#[RequestBody(content: new JsonContent(ref: new Model(type: XMLInput::class)))]
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Product')]
#[Route(path: '/product/xml', methods: ['POST'])]
#[ParamConverter(
'data',
class: '\Plugin\System\PSC\XmlCalc\Dto\Input\XMLInput',
converter: 'psc_rest.request_body',
)]
public function xml(XMLInput $data)
public function xml(#[MapRequestPayload] XMLInput $data)
{
$product = $this->entityManager
->getRepository('PSC\Shop\EntityBundle\Entity\Product')

View File

@ -2,22 +2,23 @@
namespace Plugin\System\PSC\XmlCalc\Api\Shop;
use PSC\Shop\EntityBundle\Entity\Shop as PSCShop;
use Plugin\System\PSC\XmlCalc\Model\Shop;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Doctrine\ORM\EntityManagerInterface;
use Nelmio\ApiDocBundle\Annotation\Model;
use Nelmio\ApiDocBundle\Annotation\Security;
use OpenApi\Annotations as OA;
use Plugin\System\PSC\XmlCalc\Model\Shop;
use PSC\Component\ApiBundle\Dto\Error\NotFound;
use PSC\Shop\EntityBundle\Entity\Shop as PSCShop;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Nelmio\ApiDocBundle\Annotation\Security;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use OpenApi\Annotations as OA;
use Nelmio\ApiDocBundle\Annotation\Model;
class Update extends AbstractController {
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class Update extends AbstractController
{
private EntityManagerInterface $entityManager;
public function __construct(EntityManagerInterface $entityManager)
@ -41,36 +42,33 @@ class Update extends AbstractController {
* @Security(name="Bearer")
*/
#[Route(path: '/shop/{uuid}', methods: ['PUT'])]
#[ParamConverter('shopObj', class: '\Plugin\System\PSC\XmlCalc\Model\Shop', converter: 'psc_rest.request_body')]
#[IsGranted('ROLE_USER')]
public function update(string $uuid, Shop $shopObj): JsonResponse
public function update(string $uuid, #[MapRequestPayload] Shop $shopObj): JsonResponse
{
$shop = $this->entityManager->getRepository(PSCShop::class)->findOneBy(['uuid' => $uuid]);
if(!$shop) {
if (!$shop) {
$shop = $this->entityManager->getRepository(PSCShop::class)->findOneBy(['uid' => $uuid]);
}
if(!$shop) {
if (!$shop) {
return $this->json(new NotFound('shop not found'));
}
if($shopObj->formel !== null) {
if ($shopObj->formel !== null) {
$shop->setFormel($shopObj->formel);
}
if($shopObj->formelTest !== null) {
if ($shopObj->formelTest !== null) {
$shop->setTestFormel($shopObj->formelTest);
}
if($shopObj->parameter !== null) {
if ($shopObj->parameter !== null) {
$shop->setParameter($shopObj->parameter);
}
if($shopObj->parameterTest !== null) {
if ($shopObj->parameterTest !== null) {
$shop->setTestParameter($shopObj->parameterTest);
}
$this->entityManager->persist($shop);
$this->entityManager->flush();
return $this->json($shopObj);
}
}

View File

@ -2,22 +2,24 @@
namespace Plugin\System\PSC\XmlCalc\Api\System;
use PSC\Shop\EntityBundle\Entity\Install;
use Plugin\System\PSC\XmlCalc\Model\System;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Doctrine\ORM\EntityManagerInterface;
use Nelmio\ApiDocBundle\Annotation\Model;
use Nelmio\ApiDocBundle\Annotation\Security;
use OpenApi\Annotations as OA;
use OpenApi\Attributes\Tag;
use Plugin\System\PSC\XmlCalc\Model\System;
use PSC\Component\ApiBundle\Dto\Error\NotFound;
use PSC\Shop\EntityBundle\Entity\Install;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Nelmio\ApiDocBundle\Annotation\Security;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use OpenApi\Annotations as OA;
use Nelmio\ApiDocBundle\Annotation\Model;
class Update extends AbstractController {
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class Update extends AbstractController
{
private EntityManagerInterface $entityManager;
public function __construct(EntityManagerInterface $entityManager)
@ -37,24 +39,23 @@ class Update extends AbstractController {
* description="This is a request body",
* @Model(type=\Plugin\System\PSC\XmlCalc\Model\System::class)
* )
* @OA\Tag(name="Plugin/System/psc/Xmlcalc/System")
* @Security(name="Bearer")
*/
#[Route(path: '/system', methods: ['PUT'])]
#[ParamConverter('systemObj', class: '\Plugin\System\PSC\XmlCalc\Model\System', converter: 'psc_rest.request_body')]
#[IsGranted('ROLE_USER')]
public function update(System $systemObj): JsonResponse
#[Tag('Plugin/System/psc/Xmlcalc/System')]
#[Security(name: 'Bearer')]
public function update(#[MapRequestPayload] System $systemObj): JsonResponse
{
$system = $this->entityManager->getRepository(Install::class)->findOneBy(['uid' => 1]);
if(!$system) {
if (!$system) {
return $this->json(new NotFound('system not found'));
}
if($systemObj->calcTemplates !== null) {
if ($systemObj->calcTemplates !== null) {
$system->setCalcTemplates($systemObj->calcTemplates);
}
if($systemObj->calcTemplatesTest !== null) {
if ($systemObj->calcTemplatesTest !== null) {
$system->setCalcTemplatesTest($systemObj->calcTemplatesTest);
}
@ -63,5 +64,4 @@ class Update extends AbstractController {
return $this->json($systemObj);
}
}

View File

@ -1,3 +1,3 @@
info:
datum: 21.06.2024
datum: 16.12.2025
release: 2.3

View File

@ -1434,7 +1434,7 @@ if ($teile[5] == '') {
<div style="background-color:#eeeced;margin-bottom: 10px;padding: 5px;border:1px solid rgba(0,0,0,.2)">
<?php if ($this->layouterPreviewId): /** Aufruf des Steplayouters (Steplayouter2) */ ?>
<a class="btn pop_over btn-success btn-large" rel="#overlaystep" href="/apps/plugin/custom/psc/laufkartenlayouter/frontend/designer/load/<?= $this->article->uuid ?>/<?= $this->layouterPreviewId ?>"><?php echo
<a class="btn pop_over btn-success btn-large" rel="#overlaystep" href="/apps/plugin/custom/psc/laufkartenlayouter/frontend/designer/start/<?= $this->article->uuid ?>/<?= $this->layouterPreviewId ?>"><?php echo
$this->translate('Zum Online-Designer')
?></a>
<?php else: ?>