backup
This commit is contained in:
parent
8d10f506d9
commit
bc35b70361
@ -3,7 +3,11 @@
|
|||||||
namespace PSC\Shop\PaymentBundle\Api;
|
namespace PSC\Shop\PaymentBundle\Api;
|
||||||
|
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Nelmio\ApiDocBundle\Attribute\Model;
|
||||||
use Nelmio\ApiDocBundle\Attribute\Security;
|
use Nelmio\ApiDocBundle\Attribute\Security;
|
||||||
|
use OpenApi\Attributes\JsonContent;
|
||||||
|
use OpenApi\Attributes\Response;
|
||||||
|
use OpenApi\Attributes\Tag;
|
||||||
use PSC\Shop\EntityBundle\Entity\Payment;
|
use PSC\Shop\EntityBundle\Entity\Payment;
|
||||||
use PSC\Shop\PaymentBundle\Dto\All\Output;
|
use PSC\Shop\PaymentBundle\Dto\All\Output;
|
||||||
use PSC\Shop\PaymentBundle\Model\Payment as PSCPayment;
|
use PSC\Shop\PaymentBundle\Model\Payment as PSCPayment;
|
||||||
@ -11,6 +15,7 @@ use PSC\System\SettingsBundle\Service\Shop;
|
|||||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
|
||||||
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\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||||
|
|
||||||
class All extends AbstractController
|
class All extends AbstractController
|
||||||
|
|||||||
@ -33,7 +33,7 @@ class Update extends AbstractController
|
|||||||
description: 'update paper',
|
description: 'update paper',
|
||||||
content: new JsonContent(ref: new Model(type: Paper::class)),
|
content: new JsonContent(ref: new Model(type: Paper::class)),
|
||||||
)]
|
)]
|
||||||
#[RequestBody(ref: new Model(type: Paper::class))]
|
#[RequestBody(content: new JsonContent(ref: new Model(type: Paper::class)))]
|
||||||
#[Tag(name: 'PaperDB')]
|
#[Tag(name: 'PaperDB')]
|
||||||
#[Security(name: 'ApiKeyAuth')]
|
#[Security(name: 'ApiKeyAuth')]
|
||||||
#[Route(path: '/paperdb/update/{artNr}', methods: ['PUT'])]
|
#[Route(path: '/paperdb/update/{artNr}', methods: ['PUT'])]
|
||||||
|
|||||||
@ -37,7 +37,7 @@ class Update extends AbstractController
|
|||||||
#[Tag(name: 'PaperDB')]
|
#[Tag(name: 'PaperDB')]
|
||||||
#[Security(name: 'Bearer')]
|
#[Security(name: 'Bearer')]
|
||||||
#[Route(path: '/papercontainer', methods: ['PUT'])]
|
#[Route(path: '/papercontainer', methods: ['PUT'])]
|
||||||
#[RequestBody(ref: new Model(type: Papercontainer::class))]
|
#[RequestBody(content: new JsonContent(ref: new Model(type: Papercontainer::class)))]
|
||||||
#[ParamConverter(
|
#[ParamConverter(
|
||||||
'papercontainer',
|
'papercontainer',
|
||||||
class: '\PSC\System\SettingsBundle\Model\Papercontainer',
|
class: '\PSC\System\SettingsBundle\Model\Papercontainer',
|
||||||
|
|||||||
@ -0,0 +1,141 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Plugin\Custom\Hug\Contact\Controller\Backend;
|
||||||
|
|
||||||
|
use Doctrine\ODM\MongoDB\DocumentManager;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Plugin\Custom\Hug\Contact\Form\UploadType;
|
||||||
|
use PSC\Shop\ContactBundle\Repository\AddressRepository;
|
||||||
|
use PSC\Shop\ContactBundle\Repository\ContactRepository;
|
||||||
|
use PSC\Shop\EntityBundle\Document\Contact as PSCContact;
|
||||||
|
use PSC\Shop\EntityBundle\Entity\Contact;
|
||||||
|
use PSC\Shop\EntityBundle\Entity\ContactAddress;
|
||||||
|
use PSC\System\PluginBundle\Form\Chain\Field;
|
||||||
|
use PSC\System\SettingsBundle\Service\Log;
|
||||||
|
use Role;
|
||||||
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
|
class StartController extends AbstractController
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly ContactRepository $contactRepository,
|
||||||
|
private readonly EntityManagerInterface $entityManager,
|
||||||
|
private readonly AddressRepository $contactAddressRepository,
|
||||||
|
private readonly DocumentManager $documentManager,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
#[Template]
|
||||||
|
#[Route('/start', name: 'plugin_custom_hug_contact_importer_start')]
|
||||||
|
public function start(
|
||||||
|
Request $request,
|
||||||
|
\PSC\System\SettingsBundle\Service\Shop $shopService,
|
||||||
|
DocumentManager $documentManager,
|
||||||
|
EntityManagerInterface $entityManager,
|
||||||
|
Field $fieldService,
|
||||||
|
SessionInterface $session,
|
||||||
|
Log $logService,
|
||||||
|
) {
|
||||||
|
$selectedShop = $shopService->getSelectedShop();
|
||||||
|
$data = [];
|
||||||
|
$form = $this->createForm(UploadType::class, $data);
|
||||||
|
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
$data = $form->getData();
|
||||||
|
|
||||||
|
/** @var Role $shop */
|
||||||
|
$role = $this->entityManager
|
||||||
|
->getRepository('PSC\Shop\EntityBundle\Entity\Role')
|
||||||
|
->findOneBy(['level' => 10]);
|
||||||
|
|
||||||
|
/** @var UploadedFile $file */
|
||||||
|
$file = $data['file'];
|
||||||
|
$import_start_row = $data['import_start_row'];
|
||||||
|
$import_stop_row = $data['import_stop_row'];
|
||||||
|
$testAgainstFormats = [
|
||||||
|
\PhpOffice\PhpSpreadsheet\IOFactory::READER_XLS,
|
||||||
|
\PhpOffice\PhpSpreadsheet\IOFactory::READER_XLSX,
|
||||||
|
];
|
||||||
|
|
||||||
|
/** Load $inputFileName to a Spreadsheet Object **/
|
||||||
|
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file->getRealPath(), 0, $testAgainstFormats);
|
||||||
|
$workSheet = $spreadsheet->getSheet(0);
|
||||||
|
foreach ($workSheet->getRowIterator($import_start_row, $import_stop_row) as $row) {
|
||||||
|
if ($workSheet->getCell([3, $row->getRowIndex()])->getValue() == '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$contactEntity = $this->contactRepository->getContactByEmailAndShop(
|
||||||
|
$workSheet->getCell([3, $row->getRowIndex()])->getValue(),
|
||||||
|
$selectedShop->getId(),
|
||||||
|
);
|
||||||
|
if (!$contactEntity) {
|
||||||
|
$contactEntity = new Contact();
|
||||||
|
$contactDoc = new \PSC\Shop\EntityBundle\Document\Contact();
|
||||||
|
$contactInvoiceAddress = new ContactAddress();
|
||||||
|
$contactDeliveryAddress = new ContactAddress();
|
||||||
|
} else {
|
||||||
|
$contactEntity = $contactEntity->getContact();
|
||||||
|
$contactInvoiceAddress = $this->contactAddressRepository->findOneBy([
|
||||||
|
'contact' => $contactEntity,
|
||||||
|
'type' => 1,
|
||||||
|
]);
|
||||||
|
$contactDeliveryAddress = $this->contactAddressRepository->findOneBy([
|
||||||
|
'contact' => $contactEntity,
|
||||||
|
'type' => 2,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$contactDoc = $this->documentManager
|
||||||
|
->getRepository(\PSC\Shop\EntityBundle\Document\Contact::class)
|
||||||
|
->findOneBy(['uid' => $contactEntity->getUid()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$contactEntity->setCollectingOrders(1);
|
||||||
|
$contactEntity->setEmail($workSheet->getCell([3, $row->getRowIndex()])->getValue());
|
||||||
|
$contactEntity->setEnable(true);
|
||||||
|
$contactEntity->setShops([$selectedShop]);
|
||||||
|
$contactEntity->setPassword(rand());
|
||||||
|
$contactEntity->setFirstname((string) $workSheet->getCell([6, $row->getRowIndex()])->getValue());
|
||||||
|
$contactEntity->setLastname((string) $workSheet->getCell([7, $row->getRowIndex()])->getValue());
|
||||||
|
$contactEntity->setRolesForm([$role]);
|
||||||
|
|
||||||
|
if (!$contactInvoiceAddress) {
|
||||||
|
$contactInvoiceAddress = new ContactAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
$contactInvoiceAddress->setSalutation(1);
|
||||||
|
$contactInvoiceAddress->setFirstname($contactEntity->getFirstname());
|
||||||
|
$contactInvoiceAddress->setLastname($contactEntity->getLastname());
|
||||||
|
$contactInvoiceAddress->setContact($contactEntity);
|
||||||
|
$contactInvoiceAddress->setType(1);
|
||||||
|
if (!$contactDeliveryAddress) {
|
||||||
|
$contactDeliveryAddress = new ContactAddress();
|
||||||
|
}
|
||||||
|
$contactDeliveryAddress->setSalutation(1);
|
||||||
|
$contactDeliveryAddress->setFirstname($contactEntity->getFirstname());
|
||||||
|
$contactDeliveryAddress->setLastname($contactEntity->getLastname());
|
||||||
|
$contactDeliveryAddress->setContact($contactEntity);
|
||||||
|
$contactDeliveryAddress->setType(2);
|
||||||
|
$this->entityManager->persist($contactEntity);
|
||||||
|
$this->entityManager->persist($contactDeliveryAddress);
|
||||||
|
$this->entityManager->persist($contactInvoiceAddress);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
$contactDoc = new PSCContact();
|
||||||
|
$contactDoc->setUid($contactEntity->getUid());
|
||||||
|
$docData = [];
|
||||||
|
$contactDoc->setLayouterSettings(['collectlayouter' => $docData]);
|
||||||
|
$this->documentManager->persist($contactDoc);
|
||||||
|
$this->documentManager->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['form' => $form->createView()];
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/new/var/plugins/Custom/Hug/Contact/Form/UploadType.php
Normal file
27
src/new/var/plugins/Custom/Hug/Contact/Form/UploadType.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Plugin\Custom\Hug\Contact\Form;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\FileType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
class UploadType extends AbstractType
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder->add('file', FileType::class, [
|
||||||
|
'label' => 'Datei',
|
||||||
|
'required' => true,
|
||||||
|
]);
|
||||||
|
$builder->add('import_start_row', TextType::class, [
|
||||||
|
'label' => 'Import Start Row',
|
||||||
|
'required' => true,
|
||||||
|
]);
|
||||||
|
$builder->add('import_stop_row', TextType::class, [
|
||||||
|
'label' => 'Import Stop Row',
|
||||||
|
'required' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/new/var/plugins/Custom/Hug/Contact/Plugin.php
Normal file
26
src/new/var/plugins/Custom/Hug/Contact/Plugin.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Plugin\Custom\Hug\Contact;
|
||||||
|
|
||||||
|
use PSC\System\PluginBundle\Plugin\Base;
|
||||||
|
|
||||||
|
class Plugin extends Base implements \PSC\System\PluginBundle\Interfaces\Plugin
|
||||||
|
{
|
||||||
|
protected $name = 'Contact Importer Hug';
|
||||||
|
|
||||||
|
public function getType()
|
||||||
|
{
|
||||||
|
return Plugin::Backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription()
|
||||||
|
{
|
||||||
|
return 'Contact Importer Hug';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getVersion()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
plugin_custom_hug_contact_backend:
|
||||||
|
resource: "@PluginCustomHugContact/Controller/Backend"
|
||||||
|
type: annotation
|
||||||
|
prefix: /backend/plugin/custom/hug/contact
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
services:
|
||||||
|
_defaults:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
|
||||||
|
Plugin\Custom\Hug\Contact\:
|
||||||
|
resource: '../../*/*'
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
{% extends 'backend_base.html.twig' %}
|
||||||
|
{% block body %}
|
||||||
|
<div class="panel">
|
||||||
|
<div class="header">
|
||||||
|
<h4>Import</h4>
|
||||||
|
</div>
|
||||||
|
<div class="body">
|
||||||
|
{{ form_start(form, { 'attr': {'class': 'smart-form'}}) }}
|
||||||
|
{{ form_errors(form) }}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
{{ form_label(form.file ) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="checkbox">
|
||||||
|
{{ form_widget(form.file , {attr: {'class': 'form-control'}}) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
{{ form_label(form.import_start_row ) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
{{ form_widget(form.import_start_row , {attr: {'class': 'form-control'}}) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
{{ form_label(form.import_stop_row ) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
{{ form_widget(form.import_stop_row , {attr: {'class': 'form-control'}}) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-sm btn-primary">Hochladen</button>
|
||||||
|
{{ form_end(form) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@ -1,14 +1,14 @@
|
|||||||
psc_plugin_custom_creativelayouter_backend:
|
psc_plugin_custom_creativelayouter_backend:
|
||||||
resource: "@PluginSystemPSCCreativeLayouter/Controller/Backend"
|
resource: "@PluginCustomPSCCreativeLayouter/Controller/Backend"
|
||||||
type: annotation
|
type: annotation
|
||||||
prefix: /backend/plugin/creativelayouter
|
prefix: /backend/plugin/creativelayouter
|
||||||
|
|
||||||
psc_shop_motiv_backend:
|
psc_shop_motiv_backend:
|
||||||
resource: "@PluginSystemPSCCreativeLayouter/Controller/Backend"
|
resource: "@PluginCustomPSCCreativeLayouter/Controller/Backend"
|
||||||
type: annotation
|
type: annotation
|
||||||
prefix: /backend/motiv
|
prefix: /backend/motiv
|
||||||
|
|
||||||
psc_shop_motiv_json:
|
psc_shop_motiv_json:
|
||||||
resource: "@PluginSystemPSCCreativeLayouter/Controller/Json"
|
resource: "@PluginCustomPSCCreativeLayouter/Controller/Json"
|
||||||
type: annotation
|
type: annotation
|
||||||
prefix: /
|
prefix: /
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Plugin\System\PSC\TemplateprintLayouter\Dto\Backend\AttachLayouterToOrderPosition;
|
namespace Plugin\Custom\PSC\TemplateprintLayouter\Dto\Backend\AttachLayouterToOrderPosition;
|
||||||
|
|
||||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||||
use OpenApi\Annotations as OA;
|
use OpenApi\Annotations as OA;
|
||||||
|
|
||||||
final class Output {
|
final class Output
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* @OA\Property(type="boolean")
|
* @OA\Property(type="boolean")
|
||||||
*/
|
*/
|
||||||
public bool $success;
|
public bool $success;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
||||||
71
src/new/var/plugins/System/PSC/Invoice/InvoiceTS/CLAUDE.md
Normal file
71
src/new/var/plugins/System/PSC/Invoice/InvoiceTS/CLAUDE.md
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
This is an invoice management frontend built with **Deno v2.0+**, **Vite**, **React 18**, and **TypeScript**. It's part of a larger PrintShopCreator system and builds into `../Resources/public/invoicets`.
|
||||||
|
|
||||||
|
The application creates and manages orders with contacts, positions, payments, and shipping information via a REST API backend.
|
||||||
|
|
||||||
|
## Build Commands
|
||||||
|
|
||||||
|
**Prerequisites**: Deno v2.0.0 or later must be installed.
|
||||||
|
|
||||||
|
- **Development server**: `deno task dev`
|
||||||
|
- **Production build**: `deno task build` (outputs to `../Resources/public/invoicets`)
|
||||||
|
- **Preview build**: `deno task preview`
|
||||||
|
- **Serve static files**: `deno task serve` (serves from `dist/`)
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Dependency Injection
|
||||||
|
Uses `tsyringe-neo` for dependency injection. Services and state are marked with decorators:
|
||||||
|
- `@singleton()` - single instance across app
|
||||||
|
- `@autoInjectable()` - auto-inject dependencies
|
||||||
|
- `@inject(Type)` - inject specific type
|
||||||
|
|
||||||
|
Services are resolved using `container.resolve(ServiceClass)`.
|
||||||
|
|
||||||
|
### State Management
|
||||||
|
- **OrderState** (`src/state/order.ts`): Centralized order state using RxJS `BehaviorSubject`
|
||||||
|
- **Observable Objects** (`src/lib/ob-ob.ts`): Custom reactive proxy pattern that emits RxJS observables on object changes
|
||||||
|
|
||||||
|
### API Communication
|
||||||
|
- All services use Axios with JWT token authentication
|
||||||
|
- **Token Service** (`src/services/token.ts`): Manages JWT token, auto-refreshes every 2 minutes
|
||||||
|
- API endpoints are at `/apps/api/*`
|
||||||
|
- Token is passed via `Authorization: Bearer {token}` header
|
||||||
|
|
||||||
|
### Routing
|
||||||
|
Uses React Router with hash routing (`HashRouter`):
|
||||||
|
- `/` - New order
|
||||||
|
- `/:uuid` - Load existing order by UUID
|
||||||
|
|
||||||
|
### Key Services
|
||||||
|
Located in `src/services/`:
|
||||||
|
- `order.ts` - CRUD operations for orders (get, save, calc)
|
||||||
|
- `token.ts` - JWT token management
|
||||||
|
- `contact.ts`, `product.ts`, `shop.ts`, etc. - Domain-specific API services
|
||||||
|
|
||||||
|
### Component Structure
|
||||||
|
Located in `src/modules/`:
|
||||||
|
- **BaseComponent** - Root component that coordinates all subcomponents
|
||||||
|
- Organized by domain: `contact/`, `positions/`, `payment/`, `shipping/`, `product/`, etc.
|
||||||
|
- Modal handling via `@ebay/nice-modal-react`
|
||||||
|
- Base components in `modules/base/` (Button, Currency, SelectLabel)
|
||||||
|
|
||||||
|
### Models
|
||||||
|
Located in `src/models/`: TypeScript classes for domain entities (Order, Contact, Product, Shop, etc.)
|
||||||
|
|
||||||
|
### Entry Point
|
||||||
|
1. `src/main.tsx` - Initializes app with JWT token from global `jwt_token` variable
|
||||||
|
2. `src/app/app.tsx` - Creates React root, sets up routing and modal provider
|
||||||
|
|
||||||
|
## Development Notes
|
||||||
|
|
||||||
|
- Uses Tailwind CSS + Flowbite React components
|
||||||
|
- Forms built with `@rjsf/core` (JSON Schema forms)
|
||||||
|
- Async select components with `react-select-async-paginate`
|
||||||
|
- SWC for fast React transpilation
|
||||||
|
- Build output uses fixed filenames (no hashes) for easier backend integration
|
||||||
@ -26,9 +26,11 @@
|
|||||||
"flowbite-react": "npm:flowbite-react@^0.10.2",
|
"flowbite-react": "npm:flowbite-react@^0.10.2",
|
||||||
"postcss": "npm:postcss@^8.4.49",
|
"postcss": "npm:postcss@^8.4.49",
|
||||||
"prop-types": "npm:prop-types@^15.8.1",
|
"prop-types": "npm:prop-types@^15.8.1",
|
||||||
"react": "https://esm.sh/react@18.2.0",
|
"react": "npm:react@^18.2.0",
|
||||||
"react-dom": "https://esm.sh/react-dom@18.2.0",
|
"react-dom": "npm:react-dom@^18.2.0",
|
||||||
|
"react-dom/client": "npm:react-dom@^18.2.0/client",
|
||||||
"react-router-dom": "npm:react-router-dom@^7.0.2",
|
"react-router-dom": "npm:react-router-dom@^7.0.2",
|
||||||
|
"react-select": "npm:react-select@^5.10.2",
|
||||||
"react-select-async-paginate": "npm:react-select-async-paginate@^0.7.7",
|
"react-select-async-paginate": "npm:react-select-async-paginate@^0.7.7",
|
||||||
"reflect-metadata": "npm:reflect-metadata@^0.2.2",
|
"reflect-metadata": "npm:reflect-metadata@^0.2.2",
|
||||||
"rxjs": "npm:rxjs@^7.8.1",
|
"rxjs": "npm:rxjs@^7.8.1",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,11 +1,11 @@
|
|||||||
import * as Eta from 'eta'
|
import * as Eta from 'eta'
|
||||||
import Token from '../services/token'
|
import Token from '../services/token'
|
||||||
import {container} from "tsyringe-neo"
|
import { container } from "tsyringe-neo"
|
||||||
import React from 'react'
|
import * as React from 'react'
|
||||||
import ReactDOM from 'react-dom/client'
|
import ReactDOM from 'react-dom/client'
|
||||||
import NiceModal from "@ebay/nice-modal-react"
|
import NiceModal from "@ebay/nice-modal-react"
|
||||||
import BaseComponent from '../modules/base/BaseComponent'
|
import BaseComponent from '../modules/base/BaseComponent'
|
||||||
import {Route, HashRouter as Router, Routes, useSearchParams} from "react-router-dom"
|
import { Route, HashRouter as Router, Routes, useSearchParams } from "react-router-dom"
|
||||||
|
|
||||||
export class App {
|
export class App {
|
||||||
private searchParams: any
|
private searchParams: any
|
||||||
@ -25,23 +25,29 @@ export class App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildUi() {
|
buildUi() {
|
||||||
const root = ReactDOM.createRoot(document.getElementById('root'))
|
const rootElement = document.getElementById('root')
|
||||||
|
if (!rootElement) {
|
||||||
|
console.error('Root element not found')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = ReactDOM.createRoot(rootElement)
|
||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
<NiceModal.Provider>
|
<Router>
|
||||||
<Router>
|
<NiceModal.Provider>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<BaseComponent />} />
|
<Route path="/" element={<BaseComponent />} />
|
||||||
<Route path="/:uuid" element={<BaseComponent />} />
|
<Route path="/:uuid" element={<BaseComponent />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Router>
|
</NiceModal.Provider>
|
||||||
</NiceModal.Provider>
|
</Router>
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
run(): void {
|
run(): void {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,4 +2,97 @@
|
|||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
/* Smooth scrolling */
|
||||||
|
html {
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Better font rendering */
|
||||||
|
body {
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
/* Card hover effects */
|
||||||
|
.card-hover {
|
||||||
|
@apply transition-all duration-200 hover:shadow-lg hover:-translate-y-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom scrollbar for webkit browsers */
|
||||||
|
.custom-scrollbar::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-scrollbar::-webkit-scrollbar-track {
|
||||||
|
@apply bg-gray-100 dark:bg-gray-800 rounded;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||||
|
@apply bg-gray-300 dark:bg-gray-600 rounded hover:bg-gray-400 dark:hover:bg-gray-500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Improved select styling */
|
||||||
|
.select-container {
|
||||||
|
@apply relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Focus ring improvements */
|
||||||
|
.focus-ring {
|
||||||
|
@apply focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900 focus:outline-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Status badges */
|
||||||
|
.badge {
|
||||||
|
@apply inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-success {
|
||||||
|
@apply bg-green-100 text-green-800 dark:bg-green-800 dark:text-green-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-warning {
|
||||||
|
@apply bg-yellow-100 text-yellow-800 dark:bg-yellow-800 dark:text-yellow-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-error {
|
||||||
|
@apply bg-red-100 text-red-800 dark:bg-red-800 dark:text-red-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-info {
|
||||||
|
@apply bg-blue-100 text-blue-800 dark:bg-blue-800 dark:text-blue-100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
/* Animation utilities */
|
||||||
|
.animate-fade-in {
|
||||||
|
animation: fadeIn 0.3s ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Glass morphism effect */
|
||||||
|
.glass {
|
||||||
|
@apply bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gradient text */
|
||||||
|
.gradient-text {
|
||||||
|
@apply bg-clip-text text-transparent bg-gradient-to-r from-blue-600 to-purple-600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import "reflect-metadata";
|
|||||||
import * as $ from "jquery";
|
import * as $ from "jquery";
|
||||||
import { App } from "./app/app";
|
import { App } from "./app/app";
|
||||||
|
|
||||||
declare var jwt_token: String;
|
let jwt_token: String = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE3NTk2NDkyNDMsImV4cCI6MTc1OTY1Mjg0Mywicm9sZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfU0hPUF9PUEVSQVRPUiIsIlJPTEVfVVNFUiIsIlJPTEVfVVNFUiIsIlJPTEVfUFNDX0NvbGxlY3RfQ29udGFjdF9FZGl0IiwiUk9MRV9QU0NfQ29sbGVjdF9Db250YWN0X0FkZCIsIlJPTEVfUFNDX0NvbGxlY3RfQ29udGFjdF9EZWxldGUiLCJST0xFX1BTQ19Db2xsZWN0X0NvbnRhY3RfTG9jayIsIlJPTEVfUFNDX1IyX1NlbmRjbG91ZF9TaG93Il0sInVpZCI6MX0.rTb0nAVWvWkdVhiXeqKaW2xGesOwmLswBD92Ryx1sJ9a1Jlq6EkH0NXyW4quSBV533InhyANeQFITs0mr2d5DDf04MpAd3OENBd3IVQE-_mlMVHNu42-eaxo2xR452hS4yAhKx746xGOnGhw_3gZl07aLgg4qFmb4OYo895XWIM-J-luqy5_3315xINb9Y8P3VTHt-IJ5XPWhpfB7z7QtPCUJuOyJp3nZw6V9bXPiHpcZNG3PELKMEhHyxmjtSOHMfwUhooYKxU21mctQyWTfdiLnKzG4J7nuC3Pgy33_KOoqZZXOO4SyUakFJGZevD25mOzeHCscbTBWMgjjbNK5g";
|
||||||
let app = new App(jwt_token);
|
let app = new App(jwt_token);
|
||||||
app.init();
|
app.init();
|
||||||
app.run();
|
app.run();
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import React from 'react'
|
|||||||
import OrderAliasComponent from '../order/OrderAliasComponent'
|
import OrderAliasComponent from '../order/OrderAliasComponent'
|
||||||
|
|
||||||
const BaseComponent = (props) => {
|
const BaseComponent = (props) => {
|
||||||
|
console.log('BaseComponent rendering')
|
||||||
|
|
||||||
const [shop, setShop] = useState<Shop>(new Shop())
|
const [shop, setShop] = useState<Shop>(new Shop())
|
||||||
const [order, setOrder] = useState<Order>(new Order())
|
const [order, setOrder] = useState<Order>(new Order())
|
||||||
@ -33,35 +34,55 @@ const BaseComponent = (props) => {
|
|||||||
let params = useParams()
|
let params = useParams()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
console.log('BaseComponent mounted', params)
|
||||||
if(params.uuid) {
|
if(params.uuid) {
|
||||||
loadOrder(params.uuid)
|
loadOrder(params.uuid)
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.StrictMode>
|
<div className="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 dark:from-gray-900 dark:to-gray-800 text-gray-900 dark:text-gray-100 antialiased">
|
||||||
<div className="min-h-screen bg-slate-100 text-gray-900 overflow-y-auto dark:text-gray-100 dark:bg-gray-900 antialiased">
|
<div className='container mx-auto px-4 py-6 max-w-7xl'>
|
||||||
<div className='ml-1 mt-1 mr-1'>
|
{/* Header Section */}
|
||||||
<div className="flex gap-1 mt-1 mb-1">
|
<div className="flex items-center justify-between gap-4 mb-6">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<OrderAliasComponent order={order} />
|
<OrderAliasComponent order={order} />
|
||||||
</div>
|
|
||||||
<div className="">
|
|
||||||
<ButtonComponent loadOrder={loadOrder}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
<TopBarComponent shop={shop} order={order} change={setShop} />
|
<ButtonComponent loadOrder={loadOrder}/>
|
||||||
<div className="mt-1 mb-1">{ shop.id != 0 && <ContactComponent shop={shop} order={order} /> }</div>
|
|
||||||
<div>{ shop.id != 0 && <PositionsComponent shop={shop} order={order} /> }</div>
|
|
||||||
<div className="mt-1 mb-1 flex gap-1">
|
|
||||||
<div className="flex-1">{ shop.id != 0 && <PaymentComponent shop={shop} order={order} /> }</div>
|
|
||||||
<div className="flex-1">{ shop.id != 0 && <ShippingComponent shop={shop} order={order} /> }</div>
|
|
||||||
</div>
|
</div>
|
||||||
{ shop.id != 0 && <InfoFieldComponent shop={shop} order={order} /> }
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Top Bar Section */}
|
||||||
|
<div className="mb-6">
|
||||||
|
<TopBarComponent shop={shop} order={order} change={setShop} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Main Content */}
|
||||||
|
{ shop.id != 0 && (
|
||||||
|
<>
|
||||||
|
{/* Contact Section */}
|
||||||
|
<div className="mb-6">
|
||||||
|
<ContactComponent shop={shop} order={order} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Positions Section */}
|
||||||
|
<div className="mb-6">
|
||||||
|
<PositionsComponent shop={shop} order={order} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Payment & Shipping Row */}
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
||||||
|
<PaymentComponent shop={shop} order={order} />
|
||||||
|
<ShippingComponent shop={shop} order={order} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Info Section */}
|
||||||
|
<InfoFieldComponent shop={shop} order={order} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</React.StrictMode>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,22 @@
|
|||||||
import styled from "styled-components"
|
import styled from "styled-components"
|
||||||
import { components } from "react-select"
|
import { components } from "react-select"
|
||||||
import React from 'react'
|
import * as React from 'react'
|
||||||
|
|
||||||
export const SelectLabel = (props: any) => {
|
export const SelectLabel = ({ children, ...props }: any) => {
|
||||||
|
const hasValue = props.hasValue || (props.getValue && props.getValue().length > 0 && props.getValue()[0]?.uuid !== "");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Wrapper>
|
||||||
<components.Control {...props} />
|
<components.Control {...props} children={children} />
|
||||||
<Label $isFloating={props.getValue().length == 0 || props.getValue()[0].uuid == ""}>{props.selectProps.name}</Label>
|
<Label $isFloating={!hasValue}>{props.selectProps.name}</Label>
|
||||||
</>
|
</Wrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
position: relative;
|
||||||
|
`;
|
||||||
|
|
||||||
const Label = styled.label<{ $isFloating?: boolean }>`
|
const Label = styled.label<{ $isFloating?: boolean }>`
|
||||||
left: 10px;
|
left: 10px;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|||||||
@ -51,16 +51,30 @@ class ButtonComponent extends Component<{loadOrder},{disabled: boolean}> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3 flex-wrap">
|
||||||
<Button size="xs" color="info" disabled={this.state.disabled} onClick={(e:any) => this.handleSave(e)}>
|
<Button
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon" fill="none" class="mr-2 h-5 w-5">
|
size="md"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 20.25h12A2.25 2.25 0 0 0 20.25 18V7.5L16.5 3.75H6A2.25 2.25 0 0 0 3.75 6v12A2.25 2.25 0 0 0 6 20.25zm9.75-16.5v5h-9.5v-5zM13 5.5V7m-6.75 4.25h11.5v6.5H6.25Z"></path>
|
color="blue"
|
||||||
</svg> Speichern
|
disabled={this.state.disabled}
|
||||||
|
onClick={(e:any) => this.handleSave(e)}
|
||||||
|
className="shadow-md hover:shadow-lg transition-shadow"
|
||||||
|
>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" strokeWidth="1.5" stroke="currentColor" fill="none" className="mr-2 h-5 w-5">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M6 20.25h12A2.25 2.25 0 0 0 20.25 18V7.5L16.5 3.75H6A2.25 2.25 0 0 0 3.75 6v12A2.25 2.25 0 0 0 6 20.25zm9.75-16.5v5h-9.5v-5zM13 5.5V7m-6.75 4.25h11.5v6.5H6.25Z"></path>
|
||||||
|
</svg>
|
||||||
|
Speichern
|
||||||
</Button>
|
</Button>
|
||||||
<Button size="xs" color="success" disabled={!this.orderState.getCurrentOrder().value.saved} onClick={(e:any) => this.handlePrint(e)}>
|
<Button
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon" class="mr-2 h-5 w-5">
|
size="md"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6.72 13.829c-.24.03-.48.062-.72.096m.72-.096a42.415 42.415 0 0 1 10.56 0m-10.56 0L6.34 18m10.94-4.171c.24.03.48.062.72.096m-.72-.096L17.66 18m0 0 .229 2.523a1.125 1.125 0 0 1-1.12 1.227H7.231c-.662 0-1.18-.568-1.12-1.227L6.34 18m11.318 0h1.091A2.25 2.25 0 0 0 21 15.75V9.456c0-1.081-.768-2.015-1.837-2.175a48.055 48.055 0 0 0-1.913-.247M6.34 18H5.25A2.25 2.25 0 0 1 3 15.75V9.456c0-1.081.768-2.015 1.837-2.175a48.041 48.041 0 0 1 1.913-.247m10.5 0a48.536 48.536 0 0 0-10.5 0m10.5 0V3.375c0-.621-.504-1.125-1.125-1.125h-8.25c-.621 0-1.125.504-1.125 1.125v3.659M18 10.5h.008v.008H18V10.5Zm-3 0h.008v.008H15V10.5Z"></path>
|
color="success"
|
||||||
</svg> Drucken
|
disabled={!this.orderState.getCurrentOrder().value.saved}
|
||||||
|
onClick={(e:any) => this.handlePrint(e)}
|
||||||
|
className="shadow-md hover:shadow-lg transition-shadow"
|
||||||
|
>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth="1.5" stroke="currentColor" className="mr-2 h-5 w-5">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M6.72 13.829c-.24.03-.48.062-.72.096m.72-.096a42.415 42.415 0 0 1 10.56 0m-10.56 0L6.34 18m10.94-4.171c.24.03.48.062.72.096m-.72-.096L17.66 18m0 0 .229 2.523a1.125 1.125 0 0 1-1.12 1.227H7.231c-.662 0-1.18-.568-1.12-1.227L6.34 18m11.318 0h1.091A2.25 2.25 0 0 0 21 15.75V9.456c0-1.081-.768-2.015-1.837-2.175a48.055 48.055 0 0 0-1.913-.247M6.34 18H5.25A2.25 2.25 0 0 1 3 15.75V9.456c0-1.081.768-2.015 1.837-2.175a48.041 48.041 0 0 1 1.913-.247m10.5 0a48.536 48.536 0 0 0-10.5 0m10.5 0V3.375c0-.621-.504-1.125-1.125-1.125h-8.25c-.621 0-1.125.504-1.125 1.125v3.659M18 10.5h.008v.008H18V10.5Zm-3 0h.008v.008H15V10.5Z"></path>
|
||||||
|
</svg>
|
||||||
|
Drucken
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import {container} from "tsyringe-neo"
|
|||||||
import AccountSelectComponent from '../account/AccountSelectComponent'
|
import AccountSelectComponent from '../account/AccountSelectComponent'
|
||||||
import Order from '../../model/order'
|
import Order from '../../model/order'
|
||||||
import { Shop } from '../../model/shop'
|
import { Shop } from '../../model/shop'
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
const ContactComponent = ({order, shop}) => {
|
const ContactComponent = ({order, shop}) => {
|
||||||
|
|
||||||
@ -34,54 +33,73 @@ const ContactComponent = ({order, shop}) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 animate-fade-in">
|
||||||
<div className="flex">
|
<h2 className="text-xl font-semibold mb-4 text-gray-800 dark:text-gray-100 flex items-center gap-2">
|
||||||
<div className="flex-1">
|
<svg className="w-6 h-6 text-blue-600 dark:text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<ContactSelect
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||||
order={order}
|
</svg>
|
||||||
shop={shop}
|
Kontakt & Konto
|
||||||
onChange={setContact}
|
</h2>
|
||||||
/>
|
|
||||||
</div>
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 mb-6">
|
||||||
<div className="flex-1">
|
<div>
|
||||||
<AccountSelectComponent
|
<ContactSelect
|
||||||
shop={shop} order={order}
|
order={order}
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex gap-1">
|
|
||||||
<div className="flex-1">
|
|
||||||
{ order.contact.uuid != "" && <AddressSelect
|
|
||||||
address={order.invoiceAddress}
|
|
||||||
contact={order.contact}
|
|
||||||
changeAddress={changeAddress}
|
|
||||||
name='Rechnungsadresse'
|
|
||||||
type={1}
|
|
||||||
shop={shop}
|
shop={shop}
|
||||||
/> }
|
onChange={setContact}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1">
|
<div>
|
||||||
{ order.contact.uuid != "" && <AddressSelect
|
<AccountSelectComponent
|
||||||
address={order.deliveryAddress}
|
shop={shop} order={order}
|
||||||
contact={order.contact}
|
/>
|
||||||
changeAddress={changeAddress}
|
|
||||||
name='Lieferadresse'
|
|
||||||
type={2}
|
|
||||||
shop={shop}
|
|
||||||
/> }
|
|
||||||
</div>
|
|
||||||
<div className="flex-1">
|
|
||||||
{ order.contact.uuid != "" && <AddressSelect
|
|
||||||
address={order.senderAddress}
|
|
||||||
changeAddress={changeAddress}
|
|
||||||
contact={order.contact}
|
|
||||||
name='Absenderadresse'
|
|
||||||
type={3}
|
|
||||||
shop={shop}
|
|
||||||
/> }
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
|
{ order.contact.uuid != "" && (
|
||||||
|
<>
|
||||||
|
<h3 className="text-lg font-medium mb-3 text-gray-700 dark:text-gray-200 flex items-center gap-2">
|
||||||
|
<svg className="w-5 h-5 text-green-600 dark:text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
Adressen
|
||||||
|
</h3>
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
||||||
|
<div>
|
||||||
|
<AddressSelect
|
||||||
|
address={order.invoiceAddress}
|
||||||
|
contact={order.contact}
|
||||||
|
changeAddress={changeAddress}
|
||||||
|
name='Rechnungsadresse'
|
||||||
|
type={1}
|
||||||
|
shop={shop}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<AddressSelect
|
||||||
|
address={order.deliveryAddress}
|
||||||
|
contact={order.contact}
|
||||||
|
changeAddress={changeAddress}
|
||||||
|
name='Lieferadresse'
|
||||||
|
type={2}
|
||||||
|
shop={shop}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<AddressSelect
|
||||||
|
address={order.senderAddress}
|
||||||
|
changeAddress={changeAddress}
|
||||||
|
contact={order.contact}
|
||||||
|
name='Absenderadresse'
|
||||||
|
type={3}
|
||||||
|
shop={shop}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -44,7 +44,13 @@ const PaymentComponent = ({ shop, order }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={"p-2"}>
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 animate-fade-in">
|
||||||
|
<h2 className="text-xl font-semibold mb-4 text-gray-800 dark:text-gray-100 flex items-center gap-2">
|
||||||
|
<svg className="w-6 h-6 text-emerald-600 dark:text-emerald-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" />
|
||||||
|
</svg>
|
||||||
|
Zahlart
|
||||||
|
</h2>
|
||||||
<AsyncPaginate
|
<AsyncPaginate
|
||||||
defaultOptions
|
defaultOptions
|
||||||
key={JSON.stringify(shopUuid)}
|
key={JSON.stringify(shopUuid)}
|
||||||
@ -57,7 +63,7 @@ const PaymentComponent = ({ shop, order }) => {
|
|||||||
getOptionLabel={(option) => option.title}
|
getOptionLabel={(option) => option.title}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
isSearchable={false}
|
isSearchable={false}
|
||||||
className={`${payment == 0 ? "border border-red-500" : ""}`}
|
className={`${payment == 0 ? "border-2 border-red-500 rounded" : ""}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import Order from "../../model/order"
|
|||||||
import { Pos } from '../../model/pos'
|
import { Pos } from '../../model/pos'
|
||||||
import Button from '../base/Button'
|
import Button from '../base/Button'
|
||||||
import { Modal } from "flowbite-react";
|
import { Modal } from "flowbite-react";
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
const AddPositionComponent = (props) => {
|
const AddPositionComponent = (props) => {
|
||||||
|
|
||||||
|
|||||||
@ -9,36 +9,42 @@ const ItemsComponent = ({positions, delPos, shop, changePos}) => {
|
|||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="overflow-x-auto">
|
||||||
<div className={'flex'}>
|
<table className="w-full border-collapse">
|
||||||
<div className={'flex-1'}>
|
<thead>
|
||||||
<h5>Pos</h5>
|
<tr className="border-b-2 border-gray-200 dark:border-gray-700">
|
||||||
</div>
|
<th className="text-left py-3 px-4 text-sm font-semibold text-gray-700 dark:text-gray-300">Pos</th>
|
||||||
<div className={'flex-1'}>
|
<th className="text-left py-3 px-4 text-sm font-semibold text-gray-700 dark:text-gray-300">Titel</th>
|
||||||
<h5>Title</h5>
|
<th className="text-left py-3 px-4 text-sm font-semibold text-gray-700 dark:text-gray-300">Anzahl</th>
|
||||||
</div>
|
<th className="text-right py-3 px-4 text-sm font-semibold text-gray-700 dark:text-gray-300">Netto</th>
|
||||||
<div className={'flex-1'}>
|
<th className="text-right py-3 px-4 text-sm font-semibold text-gray-700 dark:text-gray-300">MwSt</th>
|
||||||
<h5>Anzahl</h5>
|
<th className="text-right py-3 px-4 text-sm font-semibold text-gray-700 dark:text-gray-300">Brutto</th>
|
||||||
</div>
|
<th className="text-right py-3 px-4 text-sm font-semibold text-gray-700 dark:text-gray-300">Status</th>
|
||||||
<div className={'flex-1 text-end'}>
|
<th className="py-3 px-4 text-sm font-semibold text-gray-700 dark:text-gray-300"></th>
|
||||||
<h5>Netto</h5>
|
</tr>
|
||||||
</div>
|
</thead>
|
||||||
<div className={'flex-1 text-end'}>
|
<tbody className="divide-y divide-gray-200 dark:divide-gray-700">
|
||||||
<h5>Tax</h5>
|
{positions.map((object, i) => (
|
||||||
</div>
|
<PosComponent
|
||||||
<div className={'flex-1 text-end'}>
|
pos={object}
|
||||||
<h5>Gross</h5>
|
shop={shop}
|
||||||
</div>
|
delPos={delPos}
|
||||||
<div className={'flex-1 text-end'}>
|
changePos={changePos}
|
||||||
<h5>Status</h5>
|
key={i}
|
||||||
</div>
|
index={i}
|
||||||
<div className={'flex-1'}>
|
/>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{positions.length === 0 && (
|
||||||
|
<div className="text-center py-8 text-gray-500 dark:text-gray-400">
|
||||||
|
<svg className="w-16 h-16 mx-auto mb-4 opacity-50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
||||||
|
</svg>
|
||||||
|
<p className="text-lg">Keine Positionen vorhanden</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
<hr/>
|
|
||||||
{positions.map((object, i) => <PosComponent pos={object} shop={shop} delPos={delPos} changePos={changePos} key={i} index={i} />)}
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,24 +14,27 @@ const PosComponent = ({index, pos, delPos, changePos, shop}) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<tr className="hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
|
||||||
<div className={'flex'}>
|
<td className="py-3 px-4 text-sm text-gray-700 dark:text-gray-300">{index + 1}</td>
|
||||||
<div className={'flex-1'}>{index + 1}</div>
|
<td className="py-3 px-4 text-sm text-gray-700 dark:text-gray-300 font-medium">{pos.product.title}</td>
|
||||||
<div className={'flex-1'}>{pos.product.title}</div>
|
<td className="py-3 px-4 text-sm text-gray-700 dark:text-gray-300">{pos.count}</td>
|
||||||
<div className={'flex-1'}>{pos.count}</div>
|
<td className="py-3 px-4 text-sm text-right text-gray-700 dark:text-gray-300">
|
||||||
<div className={'flex-1 text-end'}><Currency price={ pos.price.allNet} /></div>
|
<Currency price={pos.price.allNet} />
|
||||||
<div className={'flex-1 text-end'}><Currency price={ pos.price.allVat} /></div>
|
</td>
|
||||||
<div className={'flex-1 text-end'}><Currency price={ pos.price.allGross} /></div>
|
<td className="py-3 px-4 text-sm text-right text-gray-700 dark:text-gray-300">
|
||||||
<div className={'flex-1 text-end'}></div>
|
<Currency price={pos.price.allVat} />
|
||||||
<div className={'flex-1 text-end'}>
|
</td>
|
||||||
<div className="flex gap-1">
|
<td className="py-3 px-4 text-sm text-right text-gray-700 dark:text-gray-300 font-semibold">
|
||||||
<EditPositionComponent shop={shop} position={pos} changePos={changePos} />
|
<Currency price={pos.price.allGross} />
|
||||||
<Button type={5} variant={'failure'} onClick={() => deletePos(pos.uuid)} />
|
</td>
|
||||||
</div>
|
<td className="py-3 px-4 text-sm text-right text-gray-700 dark:text-gray-300"></td>
|
||||||
|
<td className="py-3 px-4 text-sm text-right">
|
||||||
|
<div className="flex gap-2 justify-end">
|
||||||
|
<EditPositionComponent shop={shop} position={pos} changePos={changePos} />
|
||||||
|
<Button type={5} variant={'failure'} onClick={() => deletePos(pos.uuid)} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</td>
|
||||||
<hr/>
|
</tr>
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -43,9 +43,17 @@ const PositionsComponent = ({order, shop, updateOrder}) => {
|
|||||||
}, [positions])
|
}, [positions])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={"p-2"}>
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 animate-fade-in">
|
||||||
|
<h2 className="text-xl font-semibold mb-4 text-gray-800 dark:text-gray-100 flex items-center gap-2">
|
||||||
|
<svg className="w-6 h-6 text-purple-600 dark:text-purple-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01" />
|
||||||
|
</svg>
|
||||||
|
Positionen
|
||||||
|
</h2>
|
||||||
<ItemsComponent positions={positions} shop={shop} delPos={delPos} changePos={changePos}/>
|
<ItemsComponent positions={positions} shop={shop} delPos={delPos} changePos={changePos}/>
|
||||||
<AddPositionComponent shop={shop} addPos={addPos}/>
|
<div className="mt-4">
|
||||||
|
<AddPositionComponent shop={shop} addPos={addPos}/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import OrderState from "../../state/order"
|
|||||||
import Order from "../../model/order"
|
import Order from "../../model/order"
|
||||||
import {useEffect, useState} from "react"
|
import {useEffect, useState} from "react"
|
||||||
import { SelectLabel } from '../base/SelectLabel'
|
import { SelectLabel } from '../base/SelectLabel'
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
const ShippingComponent = ({shop, order}) => {
|
const ShippingComponent = ({shop, order}) => {
|
||||||
|
|
||||||
@ -43,7 +42,13 @@ const ShippingComponent = ({shop, order}) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={"p-2"}>
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 animate-fade-in">
|
||||||
|
<h2 className="text-xl font-semibold mb-4 text-gray-800 dark:text-gray-100 flex items-center gap-2">
|
||||||
|
<svg className="w-6 h-6 text-orange-600 dark:text-orange-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4" />
|
||||||
|
</svg>
|
||||||
|
Versandart
|
||||||
|
</h2>
|
||||||
<AsyncPaginate
|
<AsyncPaginate
|
||||||
defaultOptions
|
defaultOptions
|
||||||
key={JSON.stringify(shopUuid)}
|
key={JSON.stringify(shopUuid)}
|
||||||
@ -56,10 +61,10 @@ const ShippingComponent = ({shop, order}) => {
|
|||||||
getOptionLabel={(option) => option.title}
|
getOptionLabel={(option) => option.title}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
isSearchable={false}
|
isSearchable={false}
|
||||||
className={`${shipping == 0 ? "border border-red-500" : ""}`}
|
className={`${shipping == 0 ? "border-2 border-red-500 rounded" : ""}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ShippingComponent.propTypes = {
|
ShippingComponent.propTypes = {
|
||||||
|
|||||||
@ -10,19 +10,21 @@ import React from 'react'
|
|||||||
const TopBarComponent = ({shop, order, change}) => {
|
const TopBarComponent = ({shop, order, change}) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-3">
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 animate-fade-in">
|
||||||
<div>
|
<div className="flex flex-wrap items-center gap-4">
|
||||||
|
<div className="w-auto">
|
||||||
<DraftComponent order={order} />
|
<DraftComponent order={order} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-auto">
|
<div className="flex-1 min-w-[200px]">
|
||||||
<TypeSelectComponent order={order} />
|
<TypeSelectComponent order={order} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-auto">
|
<div className="flex-1 min-w-[200px]">
|
||||||
<ShopSelectComponent shop={shop} change={change} />
|
<ShopSelectComponent shop={shop} change={change} />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="w-auto">
|
||||||
<CalcComponent />
|
<CalcComponent />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": false,
|
||||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
@ -11,15 +11,15 @@
|
|||||||
/* Bundler mode */
|
/* Bundler mode */
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": false,
|
||||||
"moduleDetection": "force",
|
"moduleDetection": "force",
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
|
|
||||||
/* Linting */
|
/* Linting */
|
||||||
"strict": true,
|
"strict": false,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": false,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": false,
|
||||||
"noFallthroughCasesInSwitch": true
|
"noFallthroughCasesInSwitch": true
|
||||||
},
|
},
|
||||||
"include": ["src"]
|
"include": ["src"]
|
||||||
|
|||||||
@ -4,16 +4,47 @@ import react from '@vitejs/plugin-react-swc'
|
|||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [deno(), react()],
|
plugins: [
|
||||||
|
deno(),
|
||||||
|
react({
|
||||||
|
tsDecorators: true
|
||||||
|
})
|
||||||
|
],
|
||||||
|
server: {
|
||||||
|
proxy: {
|
||||||
|
'/apps': {
|
||||||
|
target: 'http://type-dev-tp.local',
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
dedupe: ['react', 'react-dom']
|
||||||
|
},
|
||||||
build: {
|
build: {
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: {
|
output: {
|
||||||
entryFileNames: `assets/[name].js`,
|
entryFileNames: `assets/[name].js`,
|
||||||
chunkFileNames: `assets/[name].js`,
|
chunkFileNames: `assets/[name].js`,
|
||||||
assetFileNames: `assets/[name].[ext]`
|
assetFileNames: `assets/[name].[ext]`,
|
||||||
|
format: 'iife',
|
||||||
|
inlineDynamicImports: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
outDir: '../Resources/public/invoicets',
|
outDir: '../Resources/public/invoicets',
|
||||||
emptyOutDir: true, // also necessary
|
emptyOutDir: true,
|
||||||
|
target: 'es2015'
|
||||||
|
},
|
||||||
|
esbuild: {
|
||||||
|
tsconfigRaw: {
|
||||||
|
compilerOptions: {
|
||||||
|
experimentalDecorators: true,
|
||||||
|
emitDecoratorMetadata: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
optimizeDeps: {
|
||||||
|
include: ['react', 'react-dom', 'react-dom/client']
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -6,7 +6,6 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Vite + React + TS</title>
|
<title>Vite + React + TS</title>
|
||||||
<script type="module" crossorigin src="/assets/index.js"></script>
|
<script type="module" crossorigin src="/assets/index.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index.css">
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@ -81,7 +81,7 @@ class GetPrice extends AbstractController
|
|||||||
description: 'get price',
|
description: 'get price',
|
||||||
content: new JsonContent(ref: new Model(type: PriceOutput::class)),
|
content: new JsonContent(ref: new Model(type: PriceOutput::class)),
|
||||||
)]
|
)]
|
||||||
#[RequestBody(ref: new Model(type: PriceInput::class))]
|
#[RequestBody(content: new JsonContent(ref: new Model(type: PriceInput::class)))]
|
||||||
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Price')]
|
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Price')]
|
||||||
#[Route(path: '/price', methods: ['POST'])]
|
#[Route(path: '/price', methods: ['POST'])]
|
||||||
#[ParamConverter(
|
#[ParamConverter(
|
||||||
|
|||||||
@ -37,7 +37,7 @@ class Config extends AbstractController
|
|||||||
description: 'get config for product',
|
description: 'get config for product',
|
||||||
content: new JsonContent(ref: new Model(type: PluginProduct::class)),
|
content: new JsonContent(ref: new Model(type: PluginProduct::class)),
|
||||||
)]
|
)]
|
||||||
#[RequestBody(ref: new Model(type: PriceInput::class))]
|
#[RequestBody(content: new JsonContent(ref: new Model(type: PriceInput::class)))]
|
||||||
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Product')]
|
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Product')]
|
||||||
#[Route(path: '/product/config', methods: ['POST'])]
|
#[Route(path: '/product/config', methods: ['POST'])]
|
||||||
#[ParamConverter(
|
#[ParamConverter(
|
||||||
|
|||||||
@ -40,7 +40,7 @@ class Design extends AbstractController
|
|||||||
description: 'get config for product',
|
description: 'get config for product',
|
||||||
content: new JsonContent(ref: new Model(type: PluginProduct::class)),
|
content: new JsonContent(ref: new Model(type: PluginProduct::class)),
|
||||||
)]
|
)]
|
||||||
#[RequestBody(ref: new Model(type: DesignInput::class))]
|
#[RequestBody(content: new JsonContent(ref: new Model(type: DesignInput::class)))]
|
||||||
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Product')]
|
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Product')]
|
||||||
#[Route(path: '/product/design', methods: ['POST'])]
|
#[Route(path: '/product/design', methods: ['POST'])]
|
||||||
#[ParamConverter(
|
#[ParamConverter(
|
||||||
|
|||||||
@ -40,7 +40,7 @@ class Json extends AbstractController
|
|||||||
description: 'get config for product',
|
description: 'get config for product',
|
||||||
content: new JsonContent(ref: new Model(type: PluginProduct::class)),
|
content: new JsonContent(ref: new Model(type: PluginProduct::class)),
|
||||||
)]
|
)]
|
||||||
#[RequestBody(ref: new Model(type: JsonInput::class))]
|
#[RequestBody(content: new JsonContent(ref: new Model(type: JsonInput::class)))]
|
||||||
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Product')]
|
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Product')]
|
||||||
#[Route(path: '/product/json', methods: ['POST'])]
|
#[Route(path: '/product/json', methods: ['POST'])]
|
||||||
#[ParamConverter(
|
#[ParamConverter(
|
||||||
|
|||||||
@ -81,7 +81,7 @@ class Preview extends AbstractController
|
|||||||
description: 'generate preview',
|
description: 'generate preview',
|
||||||
content: new JsonContent(ref: new Model(type: PriceOutput::class)),
|
content: new JsonContent(ref: new Model(type: PriceOutput::class)),
|
||||||
)]
|
)]
|
||||||
#[RequestBody(ref: new Model(type: PriceInput::class))]
|
#[RequestBody(content: new JsonContent(ref: new Model(type: PriceInput::class)))]
|
||||||
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Price')]
|
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Price')]
|
||||||
#[Route(path: '/product/preview', methods: ['POST'])]
|
#[Route(path: '/product/preview', methods: ['POST'])]
|
||||||
#[ParamConverter(
|
#[ParamConverter(
|
||||||
|
|||||||
@ -78,7 +78,7 @@ class PreviewDesigner extends AbstractController
|
|||||||
content: new JsonContent(ref: new Model(type: PDOutput::class)),
|
content: new JsonContent(ref: new Model(type: PDOutput::class)),
|
||||||
)]
|
)]
|
||||||
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Price')]
|
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Price')]
|
||||||
#[RequestBody(ref: new Model(type: PDInput::class))]
|
#[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')]
|
#[ParamConverter('data', class: '\Plugin\System\PSC\XmlCalc\Dto\Input\PDInput', converter: 'psc_rest.request_body')]
|
||||||
public function preview(PDInput $data)
|
public function preview(PDInput $data)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -33,7 +33,7 @@ class Update extends AbstractController
|
|||||||
content: new JsonContent(ref: new Model(type: Product::class)),
|
content: new JsonContent(ref: new Model(type: Product::class)),
|
||||||
)]
|
)]
|
||||||
#[Security(name: 'Bearer')]
|
#[Security(name: 'Bearer')]
|
||||||
#[RequestBody(ref: new Model(type: Product::class))]
|
#[RequestBody(content: new JsonContent(ref: new Model(type: Product::class)))]
|
||||||
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Product')]
|
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Product')]
|
||||||
#[Route(path: '/product/{uuid}', methods: ['PUT'])]
|
#[Route(path: '/product/{uuid}', methods: ['PUT'])]
|
||||||
#[ParamConverter(
|
#[ParamConverter(
|
||||||
|
|||||||
@ -40,7 +40,7 @@ class XML extends AbstractController
|
|||||||
description: 'get config for product',
|
description: 'get config for product',
|
||||||
content: new JsonContent(ref: new Model(type: PluginProduct::class)),
|
content: new JsonContent(ref: new Model(type: PluginProduct::class)),
|
||||||
)]
|
)]
|
||||||
#[RequestBody(ref: new Model(type: XMLInput::class))]
|
#[RequestBody(content: new JsonContent(ref: new Model(type: XMLInput::class)))]
|
||||||
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Product')]
|
#[Tag(name: 'Plugin/System/psc/Xmlcalc/Product')]
|
||||||
#[Route(path: '/product/xml', methods: ['POST'])]
|
#[Route(path: '/product/xml', methods: ['POST'])]
|
||||||
#[ParamConverter(
|
#[ParamConverter(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user