Fixes
Some checks failed
Gitea Actions / Run-Tests-On-Amd64 (push) Failing after 35m44s
Gitea Actions / Merge (push) Successful in 7m48s
Gitea Actions / Run-Tests-On-Arm64 (push) Has been cancelled

This commit is contained in:
Thomas Peterson 2026-03-02 14:42:39 +01:00
parent 418e8fcded
commit a18f74b3df
11 changed files with 292 additions and 41 deletions

View File

@ -476,7 +476,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* datetime?: array{ * datetime?: array{
* default_format?: scalar|Param|null, // Default: "Y-m-d\\TH:i:sP" * default_format?: scalar|Param|null, // Default: "Y-m-d\\TH:i:sP"
* default_deserialization_formats?: list<scalar|Param|null>, * default_deserialization_formats?: list<scalar|Param|null>,
* default_timezone?: scalar|Param|null, // Default: "Europe/Berlin" * default_timezone?: scalar|Param|null, // Default: "UTC"
* cdata?: scalar|Param|null, // Default: true * cdata?: scalar|Param|null, // Default: true
* }, * },
* array_collection?: array{ * array_collection?: array{
@ -576,7 +576,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* datetime?: array{ * datetime?: array{
* default_format?: scalar|Param|null, // Default: "Y-m-d\\TH:i:sP" * default_format?: scalar|Param|null, // Default: "Y-m-d\\TH:i:sP"
* default_deserialization_formats?: list<scalar|Param|null>, * default_deserialization_formats?: list<scalar|Param|null>,
* default_timezone?: scalar|Param|null, // Default: "Europe/Berlin" * default_timezone?: scalar|Param|null, // Default: "UTC"
* cdata?: scalar|Param|null, // Default: true * cdata?: scalar|Param|null, // Default: true
* }, * },
* array_collection?: array{ * array_collection?: array{

View File

@ -3,25 +3,21 @@
namespace PSC\Shop\OrderBundle\Api\Order; namespace PSC\Shop\OrderBundle\Api\Order;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Nelmio\ApiDocBundle\Annotation\Model; use Nelmio\ApiDocBundle\Attribute\Model;
use Nelmio\ApiDocBundle\Annotation\Security; use Nelmio\ApiDocBundle\Attribute\Security;
use OpenApi\Attributes as OA;
use OpenApi\Attributes\Response;
use OpenApi\Attributes\Tag;
use OpenApi\Attributes\JsonContent; use OpenApi\Attributes\JsonContent;
use OpenApi\Attributes\RequestBody; use OpenApi\Attributes\RequestBody;
use OpenApi\Attributes\Response;
use OpenApi\Attributes\Tag;
use PSC\Component\ApiBundle\Dto\Error\NotFound; use PSC\Component\ApiBundle\Dto\Error\NotFound;
use PSC\Shop\OrderBundle\Dto\Order\GetOneByUuid\Input; use PSC\Shop\OrderBundle\Dto\Order\GetOneByUuid\Input;
use PSC\Shop\OrderBundle\Model\Order\Position\DummyProductTypeObject; use PSC\Shop\OrderBundle\Model\Order as PSCOrder;
use PSC\Shop\OrderBundle\Service\Order; use PSC\Shop\OrderBundle\Service\Order;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response as HttpResponse;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Yaml\Yaml;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload; use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class GetOneByUuid extends AbstractController class GetOneByUuid extends AbstractController
{ {
@ -34,35 +30,22 @@ class GetOneByUuid extends AbstractController
$this->orderService = $orderService; $this->orderService = $orderService;
} }
/** #[Response(response: 200, description: 'orders', content: new JsonContent(ref: new Model(type: PSCOrder::class)))]
* get order by uuid #[RequestBody(description: 'This is a request body', content: new Model(type: Input::class))]
* #[Tag('Order')]
#[Response( #[Security(name: 'ApiKeyAuth')]
* response: 200, #[Security(name: 'Bearer')]
* description: 'orders',
* content: new JsonContent(ref: new Model(type: PSC\Shop\OrderBundle\Model\Order::class))
* )]
#[RequestBody(
* description: 'This is a request body',
* content: new Model(type: PSC\Shop\OrderBundle\Dto\Order\GetOneByUuid\Input::class)
* )]
#[Tag(name: 'Order')]
* @IsGranted("ROLE_SHOP")
* @Security(name="ApiKeyAuth")
* @Security(name="Bearer")
*/
#[Route(path: '/order/getonebyuuid', methods: ['POST'])] #[Route(path: '/order/getonebyuuid', methods: ['POST'])]
#[IsGranted('ROLE_SHOP')]
public function getonebyuuid(#[MapRequestPayload] Input $data): JsonResponse public function getonebyuuid(#[MapRequestPayload] Input $data): JsonResponse
{ {
$row = $this->entityManager $row = $this->entityManager->getRepository('PSC\Shop\EntityBundle\Entity\Order')->findOneByUuid($data->uuid);
->getRepository('PSC\Shop\EntityBundle\Entity\Order')
->findOneByUuid($data->uuid);
if ($row) { if ($row) {
$order = $this->orderService->getOrderByUid($row->getUid()); $order = $this->orderService->getOrderByUid($row->getUid());
return $this->json($order); return $this->json($order);
} }
return $this->json(new NotFound("order not found")); return $this->json(new NotFound('order not found'));
} }
} }

View File

@ -0,0 +1,94 @@
<?php
namespace PSC\Shop\OrderBundle\Api\Upload;
use Doctrine\ORM\EntityManagerInterface;
use Nelmio\ApiDocBundle\Annotation\Model;
use Nelmio\ApiDocBundle\Annotation\Security;
use OpenApi\Attributes\JsonContent;
use OpenApi\Attributes\MediaType;
use OpenApi\Attributes\Property;
use OpenApi\Attributes\RequestBody;
use OpenApi\Attributes\Response;
use OpenApi\Attributes\Schema;
use OpenApi\Attributes\Tag;
use PSC\Component\ApiBundle\Dto\Error\NotFound;
use PSC\Shop\EntityBundle\Entity\Orderpos;
use PSC\Shop\EntityBundle\Entity\Upload;
use PSC\Shop\OrderBundle\Dto\Upload\Create\Output;
use Ramsey\Uuid\Uuid;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class Create extends AbstractController
{
public function __construct(
private EntityManagerInterface $entityManager,
) {}
#[RequestBody(description: 'File upload', content: [
new MediaType('multipart/form-data', new Schema(properties: [
new Property(property: 'file', format: 'binary', type: 'string', description: 'File to upload'),
new Property(property: 'position', type: 'string', description: 'Position UUID'),
], required: ['file', 'position'])),
])]
#[Response(
response: 200,
description: 'Upload created',
content: new JsonContent(ref: new Model(type: Output::class)),
)]
#[Response(response: 400, description: 'Bad request')]
#[Response(response: 404, description: 'Position not found')]
#[Route(path: '/upload/create', methods: ['POST'])]
#[Tag(name: 'Upload')]
#[IsGranted('ROLE_SHOP')]
#[Security(name: 'ApiKeyAuth')]
public function create(Request $req): JsonResponse
{
$file = $req->files->get('file');
$positionUuid = $req->request->get('position', '');
$typ = $req->request->get('typ', '');
if (!$file) {
return $this->json(['error' => 'file not provided'], JsonResponse::HTTP_BAD_REQUEST);
}
/** @var Orderpos $orderpos */
$orderpos = $this->entityManager->getRepository(Orderpos::class)->findOneBy(['uuid' => $positionUuid]);
if (!$orderpos) {
return $this->json(new NotFound('Position not found'), JsonResponse::HTTP_NOT_FOUND);
}
$shopUuid = $orderpos->getOrder()->getShop()->getUuid();
$uploadDir = $this->getParameter('kernel.project_dir') . '/web/uploads/' . $shopUuid . '/article/';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$originalName = $file->getClientOriginalName();
$file->move($uploadDir, $originalName);
$upload = new Upload();
$upload->setUuid(Uuid::uuid4()->toString());
$upload->setOrderPos($orderpos);
$upload->setName($originalName);
$upload->setPath($originalName);
$upload->setTyp($typ);
$upload->setExport(false);
$upload->setCreated(new \DateTime());
$upload->setUpdated(new \DateTime());
$this->entityManager->persist($upload);
$this->entityManager->flush();
$output = new Output();
$output->uuid = $upload->getUuid();
$output->name = $originalName;
return $this->json($output);
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace PSC\Shop\OrderBundle\Dto\Upload\Create;
use OpenApi\Attributes\Property;
class Output
{
#[Property(type: 'string')]
public string $uuid = '';
#[Property(type: 'string')]
public string $name = '';
}

View File

@ -2,6 +2,13 @@
namespace PSC\Shop\OrderBundle\Model\Order\Position\Upload; namespace PSC\Shop\OrderBundle\Model\Order\Position\Upload;
use OpenApi\Attributes\Property;
use OpenApi\Attributes\Schema;
#[Schema(properties: [
new Property(property: 'code', type: 'string'),
new Property(property: 'name', type: 'string'),
])]
interface IUploadTypeObject interface IUploadTypeObject
{ {
public function canPreview(): bool; public function canPreview(): bool;

View File

@ -17,6 +17,6 @@ class Center implements IUploadMode
public function getTransformer(): IUploadModeTransformer public function getTransformer(): IUploadModeTransformer
{ {
return PSCCenter(); return new PSCCenter();
} }
} }

View File

@ -0,0 +1,152 @@
<?php
namespace App\Tests\PSC\Shop\Order\Upload;
use PSC\Shop\EntityBundle\Entity\Shop;
use PSC\Shop\EntityBundle\Repository\JobRepository;
use PSC\Shop\EntityBundle\Repository\ShopRepository;
use PSC\Shop\PaymentBundle\Repository\PaymentRepository;
use PSC\Shop\ShippingBundle\Repository\ShippingRepository;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Tests\RefreshDatabaseTrait;
class CreateCenterTest extends WebTestCase
{
use RefreshDatabaseTrait;
public function testCreateOrderDefault(): void
{
$client = static::createClient();
$shopRepository = static::getContainer()->get(ShopRepository::class);
/** @var Shop $shop */
$shop = $shopRepository->findOneBy(['title' => 'Printchampion']);
$shippingRepository = static::getContainer()->get(ShippingRepository::class);
$paymentRepository = static::getContainer()->get(PaymentRepository::class);
$client->jsonRequest(
'POST',
'/api/order/create',
[
'shop' => [
'uuid' => (string) $shop->getUuid(),
],
'type' => 2,
'shipping' => [
'uid' => $shippingRepository->findOneBy(['title' => 'Deutschlandweit'])->getUid(),
],
'payment' => [
'uid' => $paymentRepository->findOneBy(['title' => 'per Rechnung'])->getUid(),
],
'draft' => false,
'deliveryAddress' => [
'firstname' => 'Thomas',
'lastname' => 'Peterson',
'street' => 'Chausseestr.',
'houseNumber' => '24',
'zip' => '17506',
'city' => 'Gribow',
],
'invoiceAddress' => [
'firstname' => 'Thomas',
'lastname' => 'Peterson',
'street' => 'Chausseestr.',
'houseNumber' => '24',
'zip' => '17400',
'city' => 'Berlin',
],
'positions' => [
[
'count' => 1,
'product' => [
'title' => 'test XML',
'specialProductTypeObject' => [
'typ' => 6,
'taxClass' => 1900,
'xml' => '<?xml version="1.0" encoding="utf-8"?>
<kalkulation>
<artikel>
<name>Blocks A5 25blatt geleimt</name>
<kommentar>kein</kommentar>
<option id="auflage" name="Auflage" type="Input" width="3" require="true" default="1">
<auflage>
<grenze formel="(10*5)">1-</grenze>
</auflage>
</option>
</artikel>
</kalkulation>',
],
],
'uploadMode' => 'center',
],
],
],
['HTTP_apiKey' => $shop->getApiKey()],
);
self::assertSame(200, $client->getResponse()->getStatusCode());
$data = json_decode($client->getResponse()->getContent(), true);
$positionUuid = $data['positions'][0]['uuid'];
// Dateien hochladen
$tmpUmschlag = tempnam(sys_get_temp_dir(), 'umschlag_');
file_put_contents($tmpUmschlag, '%PDF-1.4 test umschlag');
$tmpInhalt = tempnam(sys_get_temp_dir(), 'inhalt_');
file_put_contents($tmpInhalt, '%PDF-1.4 test inhalt');
$client->request(
'POST',
'/api/upload/create',
['position' => $positionUuid, 'type' => 'umschlag'],
['file' => new UploadedFile($tmpUmschlag, 'umschlag.pdf', 'application/pdf', null, true)],
['HTTP_apiKey' => $shop->getApiKey()],
);
self::assertSame(200, $client->getResponse()->getStatusCode());
$client->request(
'POST',
'/api/upload/create',
['position' => $positionUuid, 'type' => 'inhalt'],
['file' => new UploadedFile($tmpInhalt, 'inhalt.pdf', 'application/pdf', null, true)],
['HTTP_apiKey' => $shop->getApiKey()],
);
self::assertSame(200, $client->getResponse()->getStatusCode());
unlink($tmpUmschlag);
unlink($tmpInhalt);
$client->jsonRequest(
'POST',
'/api/order/getonebyuuid',
[
'uuid' => $data['uuid'],
],
['HTTP_apiKey' => $shop->getApiKey()],
);
self::assertSame(200, $client->getResponse()->getStatusCode());
$data = json_decode($client->getResponse()->getContent(), true);
self::assertCount(2, $data['positions'][0]['uploads']);
self::assertSame('umschlag.pdf', $data['positions'][0]['uploadTypeObject']['files'][0]['fileName']);
self::assertSame('umschlag', $data['positions'][0]['uploadTypeObject']['files'][0]['typ']);
self::assertSame('inhalt.pdf', $data['positions'][0]['uploadTypeObject']['files'][1]['fileName']);
self::assertSame('inhalt', $data['positions'][0]['uploadTypeObject']['files'][1]['typ']);
/** @var JobRepository $jobs */
$jobs = static::getContainer()->get(JobRepository::class);
self::assertCount(0, $jobs->findBy(['data.order' => $data['uuid']]));
}
}

View File

@ -118,10 +118,11 @@ class CreateMailTest extends WebTestCase
); );
$data = json_decode($client->getResponse()->getContent(), true); $data = json_decode($client->getResponse()->getContent(), true);
var_dump($data['positions'][0]['uploadTypeObject']); self::assertFalse($data['positions'][0]['uploadTypeObject']['preview']);
self::assertSame('mail', $data['positions'][0]['uploadTypeObject']['code']);
self::assertSame(7647, $data['gross']); self::assertSame(7647, $data['gross']);
self::assertSame('SAN-' . date('Ym') . '-1', $data['alias']); self::assertSame('SAN-' . date('Ym') . '-1', $data['alias']);
self::assertNull($data['positions'][1]['uploadTypeObject']);
self::assertSame('Berlin', $data['invoiceAddress']['city']); self::assertSame('Berlin', $data['invoiceAddress']['city']);
self::assertSame('Gribow', $data['deliveryAddress']['city']); self::assertSame('Gribow', $data['deliveryAddress']['city']);

View File

@ -9,7 +9,7 @@ use PSC\Shop\ContactBundle\Model\Contact;
class Input class Input
{ {
#[Property(type: 'array')] #[Property(type: 'array', items: new \OpenApi\Attributes\Items(type: 'string'))]
private array $data = []; private array $data = [];
public function getData(): array public function getData(): array

View File

@ -8,7 +8,7 @@ use PSC\Shop\ContactBundle\Model\Contact;
class Input class Input
{ {
#[Property(type: 'array')] #[Property(type: 'array', items: new \OpenApi\Attributes\Items(type: 'string'))]
private array $data = []; private array $data = [];
private string $productUuid = ""; private string $productUuid = "";
private string $contactUuid = ""; private string $contactUuid = "";

View File

@ -7,7 +7,7 @@ use Plugin\Custom\PSC\CollectLayouter\Model\ElementType;
class Input class Input
{ {
#[Property(type: 'array')] #[Property(type: 'array', items: new \OpenApi\Attributes\Items(type: 'string'))]
private array $data = []; private array $data = [];
private string $contactUuid = ""; private string $contactUuid = "";