Fixes
Some checks failed
Gitea Actions / Run-Tests-On-Arm64 (push) Failing after 8m41s
Gitea Actions / Run-Tests-On-Amd64 (push) Failing after 12m15s
Gitea Actions / Merge (push) Successful in 5m24s

This commit is contained in:
Thomas Peterson 2025-07-22 11:31:41 +02:00
parent 5ac5e328e2
commit 6382621ee5
60 changed files with 1966 additions and 941 deletions

View File

@ -3,7 +3,6 @@ APP_ENV=dev
APP_SECRET=347829efiubvf347fbisdc27f
###< symfony/framework-bundle ###
MAILER_DSN=smtp://smtp4dev:25
###> doctrine/doctrine-bundle ###
DATABASE_URL=mysql://psc:psc@mysql:3306/psc
###< doctrine/doctrine-bundle ###

View File

@ -2,5 +2,13 @@ PSC\Shop\EntityBundle\Entity\Install:
install_1:
# uid: 1
colordb: "TEST"
paperdb: >
<?xml version="1.0" encoding="UTF-8"?>
<!-- Dokument: Papiercontainer -->
<container>
<papiercontainer id="innen">
<papier id="ct120"/>
</papiercontainer>
</container>
calcTemplates: ""
calcTemplatesTest: ""

View File

@ -9,6 +9,12 @@ PSC\Shop\EntityBundle\Entity\Shop:
apiKey: 'testApiKey1'
install: '@install_1'
uuid: "771a1176-d531-48ed-93b8-eec1fd4b917f"
formel: >
\$formel1 = '\$Ptest\$P';
\$formel2 = '\$Ptest2\$P';
parameter: >
\$test1 = 10;
\$test2 = 12;
shop_2:
title: BestesVonHier
private: false

View File

@ -42,7 +42,7 @@
<table class="table">
<thead class="thead-dark">
<tr>
<th>{{ knp_pagination_sortable(pagination, 'Id'|trans, 'account.uid') }}</th>
<th>{{ knp_pagination_sortable(pagination, 'Uid'|trans, 'account.uid') }}</th>
<th>{{ knp_pagination_sortable(pagination, 'Locked'|trans, 'account.lock') }}</th>
<th>{{ knp_pagination_sortable(pagination, 'Name'|trans, 'account.title') }}</th>
<th>{{ knp_pagination_sortable(pagination, 'street'|trans, 'account.street') }}</th>

View File

@ -45,7 +45,7 @@
<table class="table">
<thead class="thead-dark">
<tr>
<th>{{ knp_pagination_sortable(pagination, 'Id', 'contact.uid') }}</th>
<th>{{ knp_pagination_sortable(pagination, 'Uid', 'contact.uid') }}</th>
<th>{{ knp_pagination_sortable(pagination, 'Loginname'|trans, 'contact.username') }}</th>
<th>{{ knp_pagination_sortable(pagination, 'generated'|trans, 'contact.createdAt') }}</th>
<th>{{ knp_pagination_sortable(pagination, 'changed'|trans, 'contact.updatedAt') }}</th>

View File

@ -63,8 +63,15 @@ class ProductType extends AbstractType
*/
private Price $priceService;
public function __construct(Price $priceService, Shop $shop, Status $statusService, Field $fields, FormFactory $formFactory, General $generalService, EntityManagerInterface $entityManager)
{
public function __construct(
Price $priceService,
Shop $shop,
Status $statusService,
Field $fields,
FormFactory $formFactory,
General $generalService,
EntityManagerInterface $entityManager,
) {
$this->shop = $shop;
$this->statusService = $statusService;
$this->fields = $fields;
@ -76,51 +83,52 @@ class ProductType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('uuid', TextType::class, array('disabled' => true))
->add('buyed', NumberType::class, array('disabled' => false, 'required' => false, 'label' => 'Sales'))
->add('enable', CheckboxType::class, array('required' => false, 'label' => 'Active'))
->add('asOffer', CheckboxType::class, array('required' => false, 'label' => 'showcreatepdfbtn'))
->add('asRequest', CheckboxType::class, array('required' => false, 'label' => 'showcreaterequestbtn'))
->add('private', CheckboxType::class, array('required' => false, 'label' => 'Private'))
->add('canBuyWithNoPrice', CheckboxType::class, array('required' => false, 'label' => 'pricenull'))
->add('displayNoPrice', CheckboxType::class, array('required' => false, 'label' => 'notpriceshow'))
->add('displayNotInOverview', CheckboxType::class, array('required' => false, 'label' => 'notshow'))
->add('notBuy', CheckboxType::class, array('required' => false, 'label' => 'notshoworderbtn'))
->add('notEdit', CheckboxType::class, array('required' => false, 'label' => 'Sellasproduct'))
->add('url', TextType::class, array('required' => true, 'label' => 'Url'))
->add('uuid', TextType::class, ['disabled' => true])
->add('buyed', NumberType::class, ['disabled' => false, 'required' => false, 'label' => 'Sales'])
->add('enable', CheckboxType::class, ['required' => false, 'label' => 'Active'])
->add('asOffer', CheckboxType::class, ['required' => false, 'label' => 'showcreatepdfbtn'])
->add('asRequest', CheckboxType::class, ['required' => false, 'label' => 'showcreaterequestbtn'])
->add('private', CheckboxType::class, ['required' => false, 'label' => 'Private'])
->add('canBuyWithNoPrice', CheckboxType::class, ['required' => false, 'label' => 'pricenull'])
->add('displayNoPrice', CheckboxType::class, ['required' => false, 'label' => 'notpriceshow'])
->add('displayNotInOverview', CheckboxType::class, ['required' => false, 'label' => 'notshow'])
->add('notBuy', CheckboxType::class, ['required' => false, 'label' => 'notshoworderbtn'])
->add('notEdit', CheckboxType::class, ['required' => false, 'label' => 'Sellasproduct'])
->add('url', TextType::class, ['required' => true, 'label' => 'Url'])
->add('title', TextType::class)
->add('subTitle', TextType::class, ['required' => false, 'label' => 'subTitle'])
->add('createdAt', DatePickerType::class, array('disabled' => true))
->add('createdAt', DatePickerType::class, ['disabled' => true])
->add('rawText', CheckboxType::class, ['label' => 'rawText', 'required' => false])
->add('image1', MediaType::class, array())
->add('image2', MediaType::class, array())
->add('image3', MediaType::class, array())
->add('image4', MediaType::class, array())
->add('image5', MediaType::class, array())
->add('image6', MediaType::class, array())
->add('image7', MediaType::class, array())
->add('image8', MediaType::class, array())
->add('hintEnable', CheckboxType::class, array('required' => false, 'label' => 'Active'))
->add('hintFile1', MediaType::class, array())
->add('hintFile2', MediaType::class, array())
->add('hintFile3', MediaType::class, array())
->add('hintFile4', MediaType::class, array())
->add('updatedAt', DatePickerType::class, array('disabled' => true))
->add('ablaufDatum', DatePickerType::class, array('required' => false, 'label' => 'ExpiryDate'))
->add('ansprechPartner', TextType::class, array('required' => false, 'label' => 'contactperson'))
->add('printPartnerEmail', EmailType::class, array('required' => false, 'label' => 'Printingpartneremail'))
->add('zusatzAbmessung', TextType::class, array('required' => false, 'label' => 'Additionaldimension'))
->add('zusatzDesigner', TextType::class, array('required' => false, 'label' => 'Additiondesigner'))
->add('zusatzShipping', TextType::class, array('required' => false, 'label' => 'Additionalshippinginformation'))
->add('extraSettings', TextareaType::class, array('required' => false, 'label' => 'Extrasettings'));
->add('image1', MediaType::class, [])
->add('image2', MediaType::class, [])
->add('image3', MediaType::class, [])
->add('image4', MediaType::class, [])
->add('image5', MediaType::class, [])
->add('image6', MediaType::class, [])
->add('image7', MediaType::class, [])
->add('image8', MediaType::class, [])
->add('hintEnable', CheckboxType::class, ['required' => false, 'label' => 'Active'])
->add('hintFile1', MediaType::class, [])
->add('hintFile2', MediaType::class, [])
->add('hintFile3', MediaType::class, [])
->add('hintFile4', MediaType::class, [])
->add('updatedAt', DatePickerType::class, ['disabled' => true])
->add('ablaufDatum', DatePickerType::class, ['required' => false, 'label' => 'ExpiryDate'])
->add('ansprechPartner', TextType::class, ['required' => false, 'label' => 'contactperson'])
->add('printPartnerEmail', EmailType::class, ['required' => false, 'label' => 'Printingpartneremail'])
->add('zusatzAbmessung', TextType::class, ['required' => false, 'label' => 'Additionaldimension'])
->add('zusatzDesigner', TextType::class, ['required' => false, 'label' => 'Additiondesigner'])
->add('zusatzShipping', TextType::class, [
'required' => false,
'label' => 'Additionalshippinginformation',
])
->add('extraSettings', TextareaType::class, ['required' => false, 'label' => 'Extrasettings']);
if ($options['data']->isRawText()) {
$builder->add(
'description', AceEditorType::class, array(
$builder->add('description', AceEditorType::class, [
'label' => 'description',
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -132,13 +140,10 @@ class ProductType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
)
)
->add(
'text', AceEditorType::class, array(
'highlight_active_line' => null,
])->add('text', AceEditorType::class, [
'label' => 'text',
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -150,40 +155,30 @@ class ProductType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
)
);
}else{
$builder->add(
'description', TextareaType::class, array(
'highlight_active_line' => null,
]);
} else {
$builder->add('description', TextareaType::class, [
'label' => 'description',
'required' => false
)
)
->add(
'text', TextareaType::class, array(
'required' => false,
])->add('text', TextareaType::class, [
'label' => 'Additionaldescription',
'required' => false
)
);
'required' => false,
]);
}
$builder->add(
'hintText', TextareaType::class, array(
$builder
->add('hintText', TextareaType::class, [
'label' => 'description',
'required' => false
)
)
->add('customTabEnable', CheckboxType::class, array('required' => false, 'label' => 'Active'))
->add('customTabTitle', TextType::class, array('required' => false, 'label' => 'Tabname'))
->add(
'customTabText', TextareaType::class, array(
'required' => false,
])
->add('customTabEnable', CheckboxType::class, ['required' => false, 'label' => 'Active'])
->add('customTabTitle', TextType::class, ['required' => false, 'label' => 'Tabname'])
->add('customTabText', TextareaType::class, [
'label' => 'Tabtext',
'required' => false
)
)
->add(
'product_groups', EntityType::class, array(
'required' => false,
])
->add('product_groups', EntityType::class, [
'class' => 'PSC\Shop\EntityBundle\Entity\Productgroup',
'choice_label' => function (Productgroup $choice, $key, $value) {
if ($choice->isEnable()) {
@ -195,46 +190,42 @@ class ProductType extends AbstractType
'multiple' => true,
'required' => false,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('u')
->where('u.shop = :shop')->setParameter('shop', $this->shop->getSelectedShop()->getId());
}
)
)
->add(
'releatedProducts', EntityType::class, array(
return $er->createQueryBuilder('u')->where('u.shop = :shop')->setParameter(
'shop',
$this->shop->getSelectedShop()->getId(),
);
},
])
->add('releatedProducts', EntityType::class, [
'class' => 'PSC\Shop\EntityBundle\Entity\Product',
'choice_label' => 'title',
'multiple' => true,
'required' => false,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('u')
->where('u.shop = :shop AND u.originalProduct = 0')->setParameter('shop', $this->shop->getSelectedShop()->getId());
}
)
)
->add(
'language', ChoiceType::class, array(
'choices' => array(
return $er->createQueryBuilder('u')->where(
'u.shop = :shop AND u.originalProduct = 0',
)->setParameter('shop', $this->shop->getSelectedShop()->getId());
},
])
->add('language', ChoiceType::class, [
'choices' => [
'Alle' => 'all',
'de_DE' => 'de_DE',
'en_US' => 'en_US',
'fr_FR' => 'fr_FR',
'nl_NL' => 'nl_NL',
'il_IL' => 'il_IL',
),
'label' => 'language'
)
)
->add(
'availability', ChoiceType::class, array(
'choices' => array(
],
'label' => 'language',
])
->add('availability', ChoiceType::class, [
'choices' => [
'instock' => 'in_stock',
'outofstock' => 'out_of_stock',
'preorder' => 'preorder'
),
'label' => 'Availability'
)
)
'preorder' => 'preorder',
],
'label' => 'Availability',
])
->add('videoId', TextType::class, ['required' => false, 'label' => 'VideoId'])
->add('metaKeywords', TextType::class, ['required' => false, 'label' => 'Keywords'])
->add('metaDescription', TextareaType::class, ['required' => false, 'label' => 'description'])
@ -247,7 +238,11 @@ class ProductType extends AbstractType
->add('metaOgDescription', TextareaType::class, ['required' => false, 'label' => 'OGDescription'])
->add('nrIntern', TextType::class, ['required' => false, 'label' => 'Itemnumberintern'])
->add('nrExtern', TextType::class, ['required' => false, 'label' => 'Itemnumberextern'])
->add('packagingUnit', ChoiceType::class, ['required' => true, 'label' => 'Unitofmeasurement', 'choices' => $this->priceService->getPackagingUnits()])
->add('packagingUnit', ChoiceType::class, [
'required' => true,
'label' => 'Unitofmeasurement',
'choices' => $this->priceService->getPackagingUnits(),
])
->add('salesUnit', NumberType::class, ['required' => false, 'label' => 'Salesunit'])
->add('baseUnit', NumberType::class, ['required' => false, 'label' => 'Basicunit'])
->add('kostenstelle', TextType::class, ['required' => false, 'label' => 'Costcentre'])
@ -269,88 +264,76 @@ class ProductType extends AbstractType
->add('custom11', TextType::class, ['required' => false, 'label' => 'Custom 11'])
->add('custom12', TextType::class, ['required' => false, 'label' => 'Custom 12'])
->add('uploadProduct', CheckboxType::class, ['required' => false, 'label' => 'Activate'])
->add(
"uploadProductInitalStatus", ChoiceType::class, array(
->add('uploadProductInitalStatus', ChoiceType::class, [
'required' => true,
'label' => 'Initialstatus',
'choices' => $this->statusService->getPositionStatusAsArray(),
'translation_domain' => 'posstatus'
)
)
'translation_domain' => 'posstatus',
])
->add('uploadFromLatestOrder', CheckboxType::class, ['required' => false, 'label' => 'Activate'])
->add(
"uploadFromLatestOrderInitalStatus", ChoiceType::class, array(
->add('uploadFromLatestOrderInitalStatus', ChoiceType::class, [
'required' => true,
'label' => 'Initialstatus',
'choices' => $this->statusService->getPositionStatusAsArray(),
'translation_domain' => 'posstatus'
)
)
->add(
"initialStatus", ChoiceType::class, array(
'translation_domain' => 'posstatus',
])
->add('initialStatus', ChoiceType::class, [
'required' => true,
'label' => 'Masterinitialstatus',
'choices' => $this->statusService->getPositionStatusAsArray(),
'translation_domain' => 'posstatus'
)
)
'translation_domain' => 'posstatus',
])
->add('uploadPost', CheckboxType::class, ['required' => false, 'label' => 'Activate'])
->add(
"uploadPostInitalStatus", ChoiceType::class, array(
->add('uploadPostInitalStatus', ChoiceType::class, [
'required' => true,
'label' => 'Initialstatus',
'choices' => $this->statusService->getPositionStatusAsArray(),
'translation_domain' => 'posstatus'
)
)
'translation_domain' => 'posstatus',
])
->add('uploadEmail', CheckboxType::class, ['required' => false, 'label' => 'Activate'])
->add(
"uploadEmailInitalStatus", ChoiceType::class, array(
->add('uploadEmailInitalStatus', ChoiceType::class, [
'required' => true,
'label' => 'Initialstatus',
'choices' => $this->statusService->getPositionStatusAsArray(),
'translation_domain' => 'posstatus'
)
)
'translation_domain' => 'posstatus',
])
->add('uploadProvided', CheckboxType::class, ['required' => false, 'label' => 'Activate'])
->add('uploadProvidedFile', MediaType::class, array('label' => 'Datei'))
->add(
"uploadProvidedInitalStatus", ChoiceType::class, array(
->add('uploadProvidedFile', MediaType::class, ['label' => 'Datei'])
->add('uploadProvidedInitalStatus', ChoiceType::class, [
'required' => true,
'label' => 'Initalstatus',
'choices' => $this->statusService->getPositionStatusAsArray(),
'translation_domain' => 'posstatus'
)
)
'translation_domain' => 'posstatus',
])
->add('uploadProvidedDownload', CheckboxType::class, ['required' => false, 'label' => 'Download'])
->add('uploadCenter', CheckboxType::class, ['required' => false, 'label' => 'Activate'])
->add(
"uploadCenterInitalStatus", ChoiceType::class, array(
->add('uploadCenterInitalStatus', ChoiceType::class, [
'required' => true,
'label' => 'Initialstatus',
'choices' => $this->statusService->getPositionStatusAsArray(),
'translation_domain' => 'posstatus'
)
);
'translation_domain' => 'posstatus',
]);
/**
* @var \PSC\System\PluginBundle\Form\Interfaces\Field $field
*/
*/
foreach ($this->fields->getFields(\PSC\System\PluginBundle\Form\Interfaces\Field::Product) as $field) {
$builder->add($field->buildForm($this->formFactory->createNamedBuilder($field->getGroup()), $options));
}
/**
* @var \PSC\System\PluginBundle\Form\Interfaces\Field $field
*/
foreach ($this->fields->getProductFields(\PSC\System\PluginBundle\Form\Interfaces\Field::Product, $options['productType']) as $field) {
*/
foreach ($this->fields->getProductFields(
\PSC\System\PluginBundle\Form\Interfaces\Field::Product,
$options['productType'],
) as $field) {
$builder->add($field->buildForm($this->formFactory->createNamedBuilder($field->getGroup()), $options));
}
$builder->add('save', SubmitType::class, array('label' => 'save'));
$builder->add('save', SubmitType::class, ['label' => 'save']);
$builder->addEventListener(
FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($options) {
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($options) {
/**
* @var \PSC\System\PluginBundle\Form\Interfaces\Field $field
*/
@ -360,14 +343,15 @@ class ProductType extends AbstractType
/**
* @var \PSC\System\PluginBundle\Form\Interfaces\Field $field
*/
foreach ($this->fields->getProductFields(\PSC\System\PluginBundle\Form\Interfaces\Field::Product, $options['productType']) as $field) {
foreach ($this->fields->getProductFields(
\PSC\System\PluginBundle\Form\Interfaces\Field::Product,
$options['productType'],
) as $field) {
$field->formPreSetData($event);
}
}
);
});
$builder->addEventListener(
FormEvents::POST_SET_DATA, function (FormEvent $event) use ($options) {
$builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) use ($options) {
/**
* @var \PSC\System\PluginBundle\Form\Interfaces\Field $field
*/
@ -377,14 +361,15 @@ class ProductType extends AbstractType
/**
* @var \PSC\System\PluginBundle\Form\Interfaces\Field $field
*/
foreach ($this->fields->getProductFields(\PSC\System\PluginBundle\Form\Interfaces\Field::Product, $options['productType']) as $field) {
foreach ($this->fields->getProductFields(
\PSC\System\PluginBundle\Form\Interfaces\Field::Product,
$options['productType'],
) as $field) {
$field->formPostSetData($event);
}
}
);
});
$builder->addEventListener(
FormEvents::POST_SUBMIT, function (FormEvent $event) use ($options) {
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use ($options) {
/**
* @var \PSC\System\PluginBundle\Form\Interfaces\Field $field
*/
@ -394,14 +379,15 @@ class ProductType extends AbstractType
/**
* @var \PSC\System\PluginBundle\Form\Interfaces\Field $field
*/
foreach ($this->fields->getProductFields(\PSC\System\PluginBundle\Form\Interfaces\Field::Product, $options['productType']) as $field) {
foreach ($this->fields->getProductFields(
\PSC\System\PluginBundle\Form\Interfaces\Field::Product,
$options['productType'],
) as $field) {
$field->formPostSubmit($event);
}
}
);
});
$builder->addEventListener(
FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($options) {
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($options) {
/**
* @var \PSC\System\PluginBundle\Form\Interfaces\Field $field
*/
@ -411,11 +397,13 @@ class ProductType extends AbstractType
/**
* @var \PSC\System\PluginBundle\Form\Interfaces\Field $field
*/
foreach ($this->fields->getProductFields(\PSC\System\PluginBundle\Form\Interfaces\Field::Product, $options['productType']) as $field) {
foreach ($this->fields->getProductFields(
\PSC\System\PluginBundle\Form\Interfaces\Field::Product,
$options['productType'],
) as $field) {
$field->formPreSubmit($event);
}
}
);
});
}
public function getName()
@ -425,14 +413,12 @@ class ProductType extends AbstractType
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
array(
$resolver->setDefaults([
'data_class' => 'PSC\Shop\EntityBundle\Entity\Product',
'productType' => 0,
'product' => null,
'productDoc' => null,
'translation_domain' => 'core_product_edit'
)
);
'translation_domain' => 'core_product_edit',
]);
}
}

View File

@ -27,55 +27,74 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
class ProductSearchType extends AbstractType
{
public function __construct(private readonly Shop $shop)
{
}
public function __construct(
private readonly Shop $shop,
) {}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->setMethod('GET')
->add('mainProduct', CheckboxType::class, array(
->add('mainProduct', CheckboxType::class, [
'label' => 'showsubproducts',
'required' => false,
'apply_filter' => function (QueryInterface $filterQuery, $field, $values) {
if (empty($values['value'])) {
$filterQuery->getQueryBuilder()
->andWhere("
$filterQuery->getQueryBuilder()->andWhere('
product.originalProduct = 0
");
');
}
}))
->add('term', TextFilterType::class, array(
},
])
->add('term', TextFilterType::class, [
'apply_filter' => function (QueryInterface $filterQuery, $field, $values) {
if (empty($values['value'])) {
return null;
}
$filterQuery->getQueryBuilder()
$filterQuery
->getQueryBuilder()
->andWhere("
(product.uid LIKE '%" . $values['value'] . "%' OR
product.title LIKE '%" . $values['value'] . "%' OR
product.subTitle LIKE '%" . $values['value'] . "%' OR
product.calcXml LIKE '%" . $values['value'] . "%' OR
product.textFormat LIKE '%" . $values['value'] . "%' OR
product.description LIKE '%" . $values['value'] . "%' OR
product.nrIntern LIKE '%" . $values['value'] . "%' OR
product.nrExtern LIKE '%" . $values['value'] . "%' OR
product.textArt LIKE '%" . $values['value'] . "%')
(product.uid LIKE '%" .
$values['value'] .
"%' OR
product.title LIKE '%" .
$values['value'] .
"%' OR
product.uuid LIKE '%" .
$values['value'] .
"%' OR
product.subTitle LIKE '%" .
$values['value'] .
"%' OR
product.calcXml LIKE '%" .
$values['value'] .
"%' OR
product.textFormat LIKE '%" .
$values['value'] .
"%' OR
product.description LIKE '%" .
$values['value'] .
"%' OR
product.nrIntern LIKE '%" .
$values['value'] .
"%' OR
product.nrExtern LIKE '%" .
$values['value'] .
"%' OR
product.textArt LIKE '%" .
$values['value'] .
"%')
");
}))
->add('product_groups', EntityFilterType::class, array(
},
])
->add('product_groups', EntityFilterType::class, [
'apply_filter' => function (QueryInterface $filterQuery, $field, $values) {
if (empty($values['value'])) {
return null;
}
$qb = $filterQuery->getQueryBuilder();
$qb->leftJoin('product.product_groups', 'g')->andWhere('g.uid = '.$values['value']->getUid());
$qb->leftJoin('product.product_groups', 'g')->andWhere('g.uid = ' . $values['value']->getUid());
},
'class' => 'PSC\Shop\EntityBundle\Entity\Productgroup',
'choice_label' => function (Productgroup $choice, $key, $value) {
@ -88,15 +107,17 @@ class ProductSearchType extends AbstractType
'multiple' => false,
'required' => false,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('u')
->where('u.shop = :shop')->setParameter('shop', $this->shop->getSelectedShop()->getId())
return $er
->createQueryBuilder('u')
->where('u.shop = :shop')
->setParameter('shop', $this->shop->getSelectedShop()->getId())
->orderBy('u.title', 'asc');
}
))
},
])
->add('filter', SubmitType::class, [
'icon_before' => 'fas fa-search',
'label' => 'Filter',
'attr' => array('class' => 'btn btn-sm btn-success')
'attr' => ['class' => 'btn btn-sm btn-success'],
]);
}
@ -107,9 +128,9 @@ class ProductSearchType extends AbstractType
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
$resolver->setDefaults([
'csrf_protection' => false,
'translation_domain' => 'core_product_list'
));
'translation_domain' => 'core_product_list',
]);
}
}

View File

@ -31,7 +31,7 @@ a[href^="#formlayouter"] {display:none;}
<div class="body">
<div class="panel">
<div class="header">
<h5>{{ product.title }} ({{ product.uid }}) {% if product.originalProduct != 0 %}(Subprodukt von <a target="_blank" href="{{ path('backend_production_product_edit', {uuid: subProduct.uuid}) }}">{{ subProduct.title }}</a>){% endif %}</h5>
<h5>{{ product.title }} (ID: {{ product.uid }}) {% if product.originalProduct != 0 %}(Subprodukt von <a target="_blank" href="{{ path('backend_production_product_edit', {uuid: subProduct.uuid}) }}">{{ subProduct.title }}</a>){% endif %}</h5>
</div>
<div class="body">

View File

@ -20,13 +20,13 @@ use PSC\System\SettingsBundle\Service\Language;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CurrencyType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\CurrencyType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
@ -39,6 +39,7 @@ class ShopSettingsType extends AbstractType
protected $fields;
protected $formFactory;
protected Language $localeService;
public function __construct(Language $localeService, Field $fields, FormFactoryInterface $formFactory)
{
$this->fields = $fields;
@ -49,103 +50,140 @@ class ShopSettingsType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class, array('required' => false, 'label' => 'Title'))
->add('title', TextType::class, ['required' => false, 'label' => 'Title'])
->add('uid', HiddenType::class)
->add('subTitle', TextType::class, array('required' => false, 'label' => 'subtitle'))
->add('keywords', TextareaType::class, array('required' => false, 'label' => 'Keywords'))
->add('description', TextareaType::class, array('required' => false, 'label' => 'description'))
->add('author', TextareaType::class, array('required' => false, 'label' => 'Autor'))
->add('copyright', TextareaType::class, array('required' => false, 'label' => 'Copyright'))
->add('logo1', MediaType::class, array('label' => 'Logo (Topbanner)'))
->add('sitemap', MediaType::class, array('label' => 'Sitemap'))
->add('robots', MediaType::class, array('label' => 'robots'))
->add('logo2', MediaType::class, array('label' => 'Logo 2 (Background)'))
->add('browsericon', MediaType::class, array('label' => 'Logo 3 (Favicon)'))
->add('private', CheckboxType::class, array('required' => false, 'label' => 'Private'))
->add('guestEnable', CheckboxType::class, array('required' => false, 'label' => 'guestEnable'))
->add('registration', CheckboxType::class, array('required' => false, 'label' => 'Registrationpossible'))
->add('noVerify', CheckboxType::class, array('required' => false, 'label' => 'Withoutactivation'))
->add('betreiberCompany', TextType::class, array('required' => false, 'label' => 'company'))
->add('betreiberName', TextType::class, array('required' => false, 'label' => 'Name'))
->add('betreiberStreet', TextType::class, array('required' => false, 'label' => 'Streethousenumber'))
->add('betreiberAddress', TextType::class, array('required' => false, 'label' => 'ZipCity'))
->add('betreiberEmail', TextType::class, array('required' => false, 'label' => 'EMail'))
->add('betreiberTel', TextType::class, array('required' => false, 'label' => 'Phone'))
->add('betreiberFax', TextType::class, array('required' => false, 'label' => 'Fax'))
->add('betreiberUid', TextType::class, array('required' => false, 'label' => 'VATnumber'))
->add('betreiberHid', TextType::class, array('required' => false, 'label' => 'registrationnumber'))
->add('betreiberSid', TextType::class, array('required' => false, 'label' => 'taxnumber'))
->add('betreiberRegister', TextType::class, array('required' => false, 'label' => 'register'))
->add('betreiberVb', TextType::class, array('required' => false, 'label' => 'Authorizedrepresentative'))
->add('betreiberRechtsform', TextType::class, array('required' => false, 'label' => 'legalform'))
->add('betreiberWeb', TextType::class, array('required' => false, 'label' => 'Homepage'))
->add('senderCompany', TextType::class, array('required' => false, 'label' => 'company'))
->add('senderFirstname', TextType::class, array('required' => false, 'label' => 'firstname'))
->add('senderLastname', TextType::class, array('required' => false, 'label' => 'lastname'))
->add('senderStreet', TextType::class, array('required' => false, 'label' => 'Street'))
->add('senderHouseNumber', TextType::class, array('required' => false, 'label' => 'housenumber'))
->add('senderZip', TextType::class, array('required' => false, 'label' => 'Zip'))
->add('senderCity', TextType::class, array('required' => false, 'label' => 'City'))
->add('senderCountry', TextType::class, array('required' => false, 'label' => 'Country'))
->add('senderTel', TextType::class, array('required' => false, 'label' => 'Phone'))
->add('senderFax', TextType::class, array('required' => false, 'label' => 'Fax'))
->add('senderMobile', TextType::class, array('required' => false, 'label' => 'mobilephonenumber'))
->add('senderPhone', TextType::class, array('required' => false, 'label' => 'phonenumber'))
->add('senderEmail', TextType::class, array('required' => false, 'label' => 'EMail'))
->add('senderIban', TextType::class, array('required' => false, 'label' => 'Iban'))
->add('senderLId', TextType::class, array('required' => false, 'label' => 'Leitweg Id'))
->add('senderUstId', TextType::class, array('required' => false, 'label' => 'Umsatzsteuer Nr'))
->add('senderSteuerId', TextType::class, array('required' => false, 'label' => 'Steuer Nr'))
->add('priceFactor', NumberType::class, array('required' => false, 'label' => 'Factor', 'scale' => 5, 'html5' => true,
'attr' => array(
->add('subTitle', TextType::class, ['required' => false, 'label' => 'subtitle'])
->add('keywords', TextareaType::class, ['required' => false, 'label' => 'Keywords'])
->add('description', TextareaType::class, ['required' => false, 'label' => 'description'])
->add('author', TextareaType::class, ['required' => false, 'label' => 'Autor'])
->add('copyright', TextareaType::class, ['required' => false, 'label' => 'Copyright'])
->add('logo1', MediaType::class, ['label' => 'Logo (Topbanner)'])
->add('sitemap', MediaType::class, ['label' => 'Sitemap'])
->add('robots', MediaType::class, ['label' => 'robots'])
->add('logo2', MediaType::class, ['label' => 'Logo 2 (Background)'])
->add('browsericon', MediaType::class, ['label' => 'Logo 3 (Favicon)'])
->add('private', CheckboxType::class, ['required' => false, 'label' => 'Private'])
->add('guestEnable', CheckboxType::class, ['required' => false, 'label' => 'guestEnable'])
->add('registration', CheckboxType::class, ['required' => false, 'label' => 'Registrationpossible'])
->add('noVerify', CheckboxType::class, ['required' => false, 'label' => 'Withoutactivation'])
->add('betreiberCompany', TextType::class, ['required' => false, 'label' => 'company'])
->add('betreiberName', TextType::class, ['required' => false, 'label' => 'Name'])
->add('betreiberStreet', TextType::class, ['required' => false, 'label' => 'Streethousenumber'])
->add('betreiberAddress', TextType::class, ['required' => false, 'label' => 'ZipCity'])
->add('betreiberEmail', TextType::class, ['required' => false, 'label' => 'EMail'])
->add('betreiberTel', TextType::class, ['required' => false, 'label' => 'Phone'])
->add('betreiberFax', TextType::class, ['required' => false, 'label' => 'Fax'])
->add('betreiberUid', TextType::class, ['required' => false, 'label' => 'VATnumber'])
->add('betreiberHid', TextType::class, ['required' => false, 'label' => 'registrationnumber'])
->add('betreiberSid', TextType::class, ['required' => false, 'label' => 'taxnumber'])
->add('betreiberRegister', TextType::class, ['required' => false, 'label' => 'register'])
->add('betreiberVb', TextType::class, ['required' => false, 'label' => 'Authorizedrepresentative'])
->add('betreiberRechtsform', TextType::class, ['required' => false, 'label' => 'legalform'])
->add('betreiberWeb', TextType::class, ['required' => false, 'label' => 'Homepage'])
->add('senderCompany', TextType::class, ['required' => false, 'label' => 'company'])
->add('senderFirstname', TextType::class, ['required' => false, 'label' => 'firstname'])
->add('senderLastname', TextType::class, ['required' => false, 'label' => 'lastname'])
->add('senderStreet', TextType::class, ['required' => false, 'label' => 'Street'])
->add('senderHouseNumber', TextType::class, ['required' => false, 'label' => 'housenumber'])
->add('senderZip', TextType::class, ['required' => false, 'label' => 'Zip'])
->add('senderCity', TextType::class, ['required' => false, 'label' => 'City'])
->add('senderCountry', TextType::class, ['required' => false, 'label' => 'Country'])
->add('senderTel', TextType::class, ['required' => false, 'label' => 'Phone'])
->add('senderFax', TextType::class, ['required' => false, 'label' => 'Fax'])
->add('senderMobile', TextType::class, ['required' => false, 'label' => 'mobilephonenumber'])
->add('senderPhone', TextType::class, ['required' => false, 'label' => 'phonenumber'])
->add('senderEmail', TextType::class, ['required' => false, 'label' => 'EMail'])
->add('senderIban', TextType::class, ['required' => false, 'label' => 'Iban'])
->add('senderLId', TextType::class, ['required' => false, 'label' => 'Leitweg Id'])
->add('senderUstId', TextType::class, ['required' => false, 'label' => 'Umsatzsteuer Nr'])
->add('senderSteuerId', TextType::class, ['required' => false, 'label' => 'Steuer Nr'])
->add('priceFactor', NumberType::class, [
'required' => false,
'label' => 'Factor',
'scale' => 5,
'html5' => true,
'attr' => [
'min' => -0.00001,
'max' => 2.00,
'step' => 0.00001,
)))
->add('ownNumber', CheckboxType::class, array('required' => false, 'label' => 'Useyourownnumberrange'))
->add('numberStart', TextType::class, array('required' => false, 'label' => 'startnumber'))
->add('numberPattern', TextType::class, array('required' => false, 'label' => 'Numberrangeformatexample'))
->add('invoiceOwnNumber', CheckboxType::class, array('required' => false, 'label' => 'Useyourownnumberrange'))
->add('invoiceNumberStart', TextType::class, array('required' => false, 'label' => 'startnumber'))
->add('invoiceNumberPattern', TextType::class, array('required' => false, 'label' => 'Numberrangeformatexample'))
->add('creditOwnNumber', CheckboxType::class, array('required' => false, 'label' => 'Useyourownnumberrange'))
->add('creditNumberStart', TextType::class, array('required' => false, 'label' => 'startnumber'))
->add('creditNumberPattern', TextType::class, array('required' => false, 'label' => 'Numberrangeformatexample'))
->add('cancelationOwnNumber', CheckboxType::class, array('required' => false, 'label' => 'Useyourownnumberrange'))
->add('cancelationNumberStart', TextType::class, array('required' => false, 'label' => 'startnumber'))
->add('cancelationNumberPattern', TextType::class, array('required' => false, 'label' => 'Numberrangeformatexample'))
->add('parcelInvoiceOwnNumber', CheckboxType::class, array('required' => false, 'label' => 'Useyourownnumberrange'))
->add('parcelInvoiceNumberStart', TextType::class, array('required' => false, 'label' => 'startnumber'))
->add('parcelInvoiceNumberPattern', TextType::class, array('required' => false, 'label' => 'Numberrangeformatexample'))
->add('parcelCancelationOwnNumber', CheckboxType::class, array('required' => false, 'label' => 'Useyourownnumberrange'))
->add('parcelCancelationNumberStart', TextType::class, array('required' => false, 'label' => 'startnumber'))
->add('parcelCancelationNumberPattern', TextType::class, array('required' => false, 'label' => 'Numberrangeformatexample'))
->add('contactOwnNumber', CheckboxType::class, array('required' => false, 'label' => 'Useyourownnumberrange'))
->add('offerOwnNumber', CheckboxType::class, array('required' => false, 'label' => 'Useyourownnumberrange'))
->add('deleted', CheckboxType::class, array('required' => false, 'label' => 'Storedisabled'))
->add('contactNumberStart', TextType::class, array('required' => false, 'label' => 'startnumber'))
->add('offerNumberStart', TextType::class, array('required' => false, 'label' => 'startnumber'))
->add('contactNumberPattern', TextType::class, array('required' => false, 'label' => 'Numberrangeformatexample'))
->add('offerNumberPattern', TextType::class, array('required' => false, 'label' => 'Numberrangeformatexample'))
->add('redirectAfterBuy', TextType::class, array('required' => false, 'label' => 'Redirectafterorder'))
->add('redirectLogin', TextType::class, array('required' => false, 'label' => 'Redirectafterlogin'))
->add('redirectLogout', TextType::class, array('required' => false, 'label' => 'Redirectafterlogout'))
->add('redirectToSSL', CheckboxType::class, array('required' => false, 'label' => 'alwaysforwardtoSSL'))
->add('createPackageAfterBuy', CheckboxType::class, array('required' => false, 'label' => 'Generatepackagedirectly'))
->add('tpSaveUserData', CheckboxType::class, array('required' => false, 'label' => 'Restorecustomerdata'))
->add('apiKey', TextType::class, array('required' => false, 'disabled' => true, 'label' => 'APIKey'))
->add('docJobticketJasperXml', AceEditorType::class, array(
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
],
])
->add('ownNumber', CheckboxType::class, ['required' => false, 'label' => 'Useyourownnumberrange'])
->add('numberStart', TextType::class, ['required' => false, 'label' => 'startnumber'])
->add('numberPattern', TextType::class, ['required' => false, 'label' => 'Numberrangeformatexample'])
->add('invoiceOwnNumber', CheckboxType::class, [
'required' => false,
'label' => 'Useyourownnumberrange',
])
->add('invoiceNumberStart', TextType::class, ['required' => false, 'label' => 'startnumber'])
->add('invoiceNumberPattern', TextType::class, [
'required' => false,
'label' => 'Numberrangeformatexample',
])
->add('creditOwnNumber', CheckboxType::class, [
'required' => false,
'label' => 'Useyourownnumberrange',
])
->add('creditNumberStart', TextType::class, ['required' => false, 'label' => 'startnumber'])
->add('creditNumberPattern', TextType::class, [
'required' => false,
'label' => 'Numberrangeformatexample',
])
->add('cancelationOwnNumber', CheckboxType::class, [
'required' => false,
'label' => 'Useyourownnumberrange',
])
->add('cancelationNumberStart', TextType::class, ['required' => false, 'label' => 'startnumber'])
->add('cancelationNumberPattern', TextType::class, [
'required' => false,
'label' => 'Numberrangeformatexample',
])
->add('parcelInvoiceOwnNumber', CheckboxType::class, [
'required' => false,
'label' => 'Useyourownnumberrange',
])
->add('parcelInvoiceNumberStart', TextType::class, ['required' => false, 'label' => 'startnumber'])
->add('parcelInvoiceNumberPattern', TextType::class, [
'required' => false,
'label' => 'Numberrangeformatexample',
])
->add('parcelCancelationOwnNumber', CheckboxType::class, [
'required' => false,
'label' => 'Useyourownnumberrange',
])
->add('parcelCancelationNumberStart', TextType::class, ['required' => false, 'label' => 'startnumber'])
->add('parcelCancelationNumberPattern', TextType::class, [
'required' => false,
'label' => 'Numberrangeformatexample',
])
->add('contactOwnNumber', CheckboxType::class, [
'required' => false,
'label' => 'Useyourownnumberrange',
])
->add('offerOwnNumber', CheckboxType::class, ['required' => false, 'label' => 'Useyourownnumberrange'])
->add('deleted', CheckboxType::class, ['required' => false, 'label' => 'Storedisabled'])
->add('contactNumberStart', TextType::class, ['required' => false, 'label' => 'startnumber'])
->add('offerNumberStart', TextType::class, ['required' => false, 'label' => 'startnumber'])
->add('contactNumberPattern', TextType::class, [
'required' => false,
'label' => 'Numberrangeformatexample',
])
->add('offerNumberPattern', TextType::class, [
'required' => false,
'label' => 'Numberrangeformatexample',
])
->add('redirectAfterBuy', TextType::class, ['required' => false, 'label' => 'Redirectafterorder'])
->add('redirectLogin', TextType::class, ['required' => false, 'label' => 'Redirectafterlogin'])
->add('redirectLogout', TextType::class, ['required' => false, 'label' => 'Redirectafterlogout'])
->add('redirectToSSL', CheckboxType::class, ['required' => false, 'label' => 'alwaysforwardtoSSL'])
->add('createPackageAfterBuy', CheckboxType::class, [
'required' => false,
'label' => 'Generatepackagedirectly',
])
->add('tpSaveUserData', CheckboxType::class, ['required' => false, 'label' => 'Restorecustomerdata'])
->add('apiKey', TextType::class, ['required' => false, 'disabled' => true, 'label' => 'APIKey'])
->add('docJobticketJasperXml', AceEditorType::class, [
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -157,13 +195,13 @@ class ShopSettingsType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
))
->add('docJobticketBg', MediaType::class, array('label' => 'background'))
->add('docOfferProductBg', MediaType::class, array('label' => 'background'))
->add('docOfferProductFileName', TextType::class, array('label' => 'filename', 'required' => false))
->add('docOfferProductXml', AceEditorType::class, array(
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'highlight_active_line' => null,
])
->add('docJobticketBg', MediaType::class, ['label' => 'background'])
->add('docOfferProductBg', MediaType::class, ['label' => 'background'])
->add('docOfferProductFileName', TextType::class, ['label' => 'filename', 'required' => false])
->add('docOfferProductXml', AceEditorType::class, [
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -175,12 +213,12 @@ class ShopSettingsType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
))
->add('docJobticketPositionBg', MediaType::class, array('label' => 'background'))
->add('docJobticketFileName', TextType::class, array('label' => 'filenamej', 'required' => false))
->add('docJobticketPosition', AceEditorType::class, array(
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'highlight_active_line' => null,
])
->add('docJobticketPositionBg', MediaType::class, ['label' => 'background'])
->add('docJobticketFileName', TextType::class, ['label' => 'filenamej', 'required' => false])
->add('docJobticketPosition', AceEditorType::class, [
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -192,10 +230,10 @@ class ShopSettingsType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
))
->add('docJobticketPPJasperXml', AceEditorType::class, array(
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'highlight_active_line' => null,
])
->add('docJobticketPPJasperXml', AceEditorType::class, [
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -207,13 +245,13 @@ class ShopSettingsType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
))
->add('docJobticketPPBg', MediaType::class, array('label' => 'background'))
->add('docJobticketPPFileName', TextType::class, array('label' => 'filename', 'required' => false))
->add('docJobticketPPPositionBg', MediaType::class, array('label' => 'background'))
->add('docJobticketPPPosition', AceEditorType::class, array(
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'highlight_active_line' => null,
])
->add('docJobticketPPBg', MediaType::class, ['label' => 'background'])
->add('docJobticketPPFileName', TextType::class, ['label' => 'filename', 'required' => false])
->add('docJobticketPPPositionBg', MediaType::class, ['label' => 'background'])
->add('docJobticketPPPosition', AceEditorType::class, [
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -225,10 +263,10 @@ class ShopSettingsType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
))
->add('docOfferJasperXml', AceEditorType::class, array(
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'highlight_active_line' => null,
])
->add('docOfferJasperXml', AceEditorType::class, [
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -240,13 +278,13 @@ class ShopSettingsType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
))
->add('docOfferBg', MediaType::class, array('label' => 'background'))
->add('docOfferFileName', TextType::class, array('label' => 'filenameo', 'required' => false))
->add('docOfferPositionBg', MediaType::class, array('label' => 'background'))
->add('docOfferPosition', AceEditorType::class, array(
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'highlight_active_line' => null,
])
->add('docOfferBg', MediaType::class, ['label' => 'background'])
->add('docOfferFileName', TextType::class, ['label' => 'filenameo', 'required' => false])
->add('docOfferPositionBg', MediaType::class, ['label' => 'background'])
->add('docOfferPosition', AceEditorType::class, [
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -258,10 +296,10 @@ class ShopSettingsType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
))
->add('docOrderJasperXml', AceEditorType::class, array(
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'highlight_active_line' => null,
])
->add('docOrderJasperXml', AceEditorType::class, [
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -273,13 +311,13 @@ class ShopSettingsType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
))
->add('docOrderBg', MediaType::class, array('label' => 'background'))
->add('docOrderFileName', TextType::class, array('label' => 'filenameor', 'required' => false))
->add('docOrderPositionBg', MediaType::class, array('label' => 'background'))
->add('docOrderPosition', AceEditorType::class, array(
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'highlight_active_line' => null,
])
->add('docOrderBg', MediaType::class, ['label' => 'background'])
->add('docOrderFileName', TextType::class, ['label' => 'filenameor', 'required' => false])
->add('docOrderPositionBg', MediaType::class, ['label' => 'background'])
->add('docOrderPosition', AceEditorType::class, [
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -291,10 +329,10 @@ class ShopSettingsType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
))
->add('docInvoiceJasperXml', AceEditorType::class, array(
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'highlight_active_line' => null,
])
->add('docInvoiceJasperXml', AceEditorType::class, [
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -306,19 +344,19 @@ class ShopSettingsType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
))
->add('docInvoiceBg', MediaType::class, array('label' => 'background'))
->add('docInvoiceFileName', TextType::class, array('label' => 'filenamei', 'required' => false))
->add('docInvoicePositionBg', MediaType::class, array('label' => 'background'))
->add('docInvoiceXML', CheckboxType::class, array('label' => 'embed XRechnung', 'required' => false))
->add('docJobticketXML', CheckboxType::class, array('label' => 'embed XRechnung', 'required' => false))
->add('docOfferXML', CheckboxType::class, array('label' => 'embed XRechnung', 'required' => false))
->add('docDeliveryXML', CheckboxType::class, array('label' => 'embed XRechnung', 'required' => false))
->add('docOrderXML', CheckboxType::class, array('label' => 'embed XRechnung', 'required' => false))
->add('docStornoXML', CheckboxType::class, array('label' => 'embed XRechnung', 'required' => false))
->add('docInvoicePosition', AceEditorType::class, array(
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'highlight_active_line' => null,
])
->add('docInvoiceBg', MediaType::class, ['label' => 'background'])
->add('docInvoiceFileName', TextType::class, ['label' => 'filenamei', 'required' => false])
->add('docInvoicePositionBg', MediaType::class, ['label' => 'background'])
->add('docInvoiceXML', CheckboxType::class, ['label' => 'embed XRechnung', 'required' => false])
->add('docJobticketXML', CheckboxType::class, ['label' => 'embed XRechnung', 'required' => false])
->add('docOfferXML', CheckboxType::class, ['label' => 'embed XRechnung', 'required' => false])
->add('docDeliveryXML', CheckboxType::class, ['label' => 'embed XRechnung', 'required' => false])
->add('docOrderXML', CheckboxType::class, ['label' => 'embed XRechnung', 'required' => false])
->add('docStornoXML', CheckboxType::class, ['label' => 'embed XRechnung', 'required' => false])
->add('docInvoicePosition', AceEditorType::class, [
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -330,10 +368,10 @@ class ShopSettingsType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
))
->add('docLabelJasperXml', AceEditorType::class, array(
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'highlight_active_line' => null,
])
->add('docLabelJasperXml', AceEditorType::class, [
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -345,13 +383,13 @@ class ShopSettingsType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
))
->add('docLabelBg', MediaType::class, array('label' => 'background'))
->add('docLabelFileName', TextType::class, array('label' => 'filenamel', 'required' => false))
->add('docLabelPositionBg', MediaType::class, array('label' => 'background'))
->add('docLabelPosition', AceEditorType::class, array(
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'highlight_active_line' => null,
])
->add('docLabelBg', MediaType::class, ['label' => 'background'])
->add('docLabelFileName', TextType::class, ['label' => 'filenamel', 'required' => false])
->add('docLabelPositionBg', MediaType::class, ['label' => 'background'])
->add('docLabelPosition', AceEditorType::class, [
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -363,10 +401,10 @@ class ShopSettingsType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
))
->add('docDeliveryJasperXml', AceEditorType::class, array(
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'highlight_active_line' => null,
])
->add('docDeliveryJasperXml', AceEditorType::class, [
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -378,13 +416,13 @@ class ShopSettingsType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
))
->add('docDeliveryBg', MediaType::class, array('label' => 'background'))
->add('docDeliveryFileName', TextType::class, array('label' => 'filenamed', 'required' => false))
->add('docDeliveryPositionBg', MediaType::class, array('label' => 'background'))
->add('docDeliveryPosition', AceEditorType::class, array(
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'highlight_active_line' => null,
])
->add('docDeliveryBg', MediaType::class, ['label' => 'background'])
->add('docDeliveryFileName', TextType::class, ['label' => 'filenamed', 'required' => false])
->add('docDeliveryPositionBg', MediaType::class, ['label' => 'background'])
->add('docDeliveryPosition', AceEditorType::class, [
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -396,10 +434,10 @@ class ShopSettingsType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
))
->add('docStornoJasperXml', AceEditorType::class, array(
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'highlight_active_line' => null,
])
->add('docStornoJasperXml', AceEditorType::class, [
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -411,13 +449,13 @@ class ShopSettingsType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
))
->add('docStornoBg', MediaType::class, array('label' => 'background'))
->add('docStornoFileName', TextType::class, array('label' => 'filenames', 'required' => false))
->add('docStornoPositionBg', MediaType::class, array('label' => 'background'))
->add('docStornoPosition', AceEditorType::class, array(
'wrapper_attr' => array(), // aceeditor wrapper html attributes.
'highlight_active_line' => null,
])
->add('docStornoBg', MediaType::class, ['label' => 'background'])
->add('docStornoFileName', TextType::class, ['label' => 'filenames', 'required' => false])
->add('docStornoPositionBg', MediaType::class, ['label' => 'background'])
->add('docStornoPosition', AceEditorType::class, [
'wrapper_attr' => [], // aceeditor wrapper html attributes.
'width' => '90%',
'height' => '500',
'font_size' => 14,
@ -429,116 +467,267 @@ class ShopSettingsType extends AbstractType
'use_wrap_mode' => null,
'show_print_margin' => null,
'required' => false,
'highlight_active_line' => null
))
->add('productFieldName1', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field1Designation'))
->add('productFieldName2', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field2Designation'))
->add('productFieldName3', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field3Designation'))
->add('productFieldName4', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field4Designation'))
->add('productFieldName5', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field5Designation'))
->add('productFieldName6', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field6Designation'))
->add('productFieldName7', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field7Designation'))
->add('productFieldName8', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field8Designation'))
->add('productFieldName9', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field9Designation'))
->add('productFieldName10', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field10Designation'))
->add('productFieldName11', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field11Designation'))
->add('productFieldName12', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field12Designation'))
->add('customerFieldName1', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field1Designation'))
->add('customerFieldName2', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field2Designation'))
->add('customerFieldName3', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field3Designation'))
->add('customerFieldName4', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field4Designation'))
->add('customerFieldName5', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field5Designation'))
->add('customerFieldName6', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field6Designation'))
->add('customerFieldName7', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field7Designation'))
->add('customerFieldName8', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field8Designation'))
->add('customerFieldName9', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field9Designation'))
->add('customerFieldName10', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field10Designation'))
->add('customerFieldName11', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field11Designation'))
->add('customerFieldName12', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field12Designation'))
->add('customerFieldName13', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field13Designation'))
->add('customerFieldName14', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field14Designation'))
->add('customerFieldName15', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field15Designation'))
->add('customerFieldName16', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field16Designation'))
->add('customerFieldName17', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field17Designation'))
->add('customerFieldName18', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field18Designation'))
->add('customerFieldName19', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field19Designation'))
->add('customerFieldName20', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field20Designation'))
->add('customerFieldName21', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field21Designation'))
->add('customerFieldName22', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field22Designation'))
->add('customerFieldName23', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field23Designation'))
->add('customerFieldName24', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Field24Designation'))
->add('defaultLocale', ChoiceType::class, array('choices' => $this->localeService->getShopLocale(), 'required' => true, 'label' => 'defaultLanguage'))
->add('defaultCurrency', CurrencyType::class, array('required' => true, 'label' => 'defaultCurrency'))
->add('extraSettings', TextareaType::class, array('required' => false, 'label' => 'extrasettings'))
->add('mailOrderCustomerSubjectTemplate', TextType::class, array('required' => false, 'disabled' => false, 'label' => 'Ordermailtocustomersubject'))
->add('mailOrderCustomerTextTemplate', TextareaType::class, array(
'highlight_active_line' => null,
])
->add('productFieldName1', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field1Designation',
])
->add('productFieldName2', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field2Designation',
])
->add('productFieldName3', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field3Designation',
])
->add('productFieldName4', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field4Designation',
])
->add('productFieldName5', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field5Designation',
])
->add('productFieldName6', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field6Designation',
])
->add('productFieldName7', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field7Designation',
])
->add('productFieldName8', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field8Designation',
])
->add('productFieldName9', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field9Designation',
])
->add('productFieldName10', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field10Designation',
])
->add('productFieldName11', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field11Designation',
])
->add('productFieldName12', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field12Designation',
])
->add('customerFieldName1', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field1Designation',
])
->add('customerFieldName2', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field2Designation',
])
->add('customerFieldName3', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field3Designation',
])
->add('customerFieldName4', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field4Designation',
])
->add('customerFieldName5', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field5Designation',
])
->add('customerFieldName6', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field6Designation',
])
->add('customerFieldName7', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field7Designation',
])
->add('customerFieldName8', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field8Designation',
])
->add('customerFieldName9', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field9Designation',
])
->add('customerFieldName10', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field10Designation',
])
->add('customerFieldName11', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field11Designation',
])
->add('customerFieldName12', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field12Designation',
])
->add('customerFieldName13', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field13Designation',
])
->add('customerFieldName14', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field14Designation',
])
->add('customerFieldName15', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field15Designation',
])
->add('customerFieldName16', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field16Designation',
])
->add('customerFieldName17', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field17Designation',
])
->add('customerFieldName18', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field18Designation',
])
->add('customerFieldName19', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field19Designation',
])
->add('customerFieldName20', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field20Designation',
])
->add('customerFieldName21', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field21Designation',
])
->add('customerFieldName22', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field22Designation',
])
->add('customerFieldName23', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field23Designation',
])
->add('customerFieldName24', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Field24Designation',
])
->add('defaultLocale', ChoiceType::class, [
'choices' => $this->localeService->getShopLocale(),
'required' => true,
'label' => 'defaultLanguage',
])
->add('defaultCurrency', CurrencyType::class, ['required' => true, 'label' => 'defaultCurrency'])
->add('extraSettings', TextareaType::class, ['required' => false, 'label' => 'extrasettings'])
->add('mailOrderCustomerSubjectTemplate', TextType::class, [
'required' => false,
'disabled' => false,
'label' => 'Ordermailtocustomersubject',
])
->add('mailOrderCustomerTextTemplate', TextareaType::class, [
'required' => false,
'disabled' => false,
'label' => 'Ordermailtocustomer',
'attr' => ['rows' => 10]))
->add('imprintText', TextareaType::class, array(
'attr' => ['rows' => 10],
])
->add('imprintText', TextareaType::class, [
'label' => 'Text',
'required' => false,
))
->add('templateCopyright', TextareaType::class, array(
])
->add('templateCopyright', TextareaType::class, [
'label' => 'Text',
'required' => false,
))
->add('conditionsText', TextareaType::class, array(
])
->add('conditionsText', TextareaType::class, [
'label' => 'Text',
'required' => false,
))
->add('cancellationTermsText', TextareaType::class, array(
])
->add('cancellationTermsText', TextareaType::class, [
'label' => 'Text',
'required' => false,
))
->add('privacyPolicyText', TextareaType::class, array(
])
->add('privacyPolicyText', TextareaType::class, [
'label' => 'Text',
'required' => false,
))
->add('productSort', ChoiceType::class, array(
])
->add('productSort', ChoiceType::class, [
'label' => 'productsorting',
'choices' => ['Position' => 'pos', 'Name' => 'name'],
'required' => false,
))
->add('productSortDir', ChoiceType::class, array(
])
->add('productSortDir', ChoiceType::class, [
'label' => 'productsorting',
'choices' => ['Ascending' => 'asc', 'Descending' => 'desc'],
'required' => false,
))
->add('disableOldCalc', CheckboxType::class, array('required' => false, 'label' => 'disableOldCalc'));
])
->add('disableOldCalc', CheckboxType::class, ['required' => false, 'label' => 'disableOldCalc']);
/** @var \PSC\System\PluginBundle\Form\Interfaces\Field $field */
foreach ($this->fields->getFields(\PSC\System\PluginBundle\Form\Interfaces\Field::Shop) as $field) {
$builder->add($field->buildForm($this->formFactory->createNamedBuilder($field->getGroup(), FormType::class, null, ['mapped' => false]), $options));
$builder->add($field->buildForm($this->formFactory->createNamedBuilder(
$field->getGroup(),
FormType::class,
null,
['mapped' => false],
), $options));
}
$builder->add('save', SubmitType::class, array('label' => 'save'));
$builder->add('save', SubmitType::class, ['label' => 'save']);
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
/** @var \PSC\System\PluginBundle\Form\Interfaces\Field $field */
foreach ($this->fields->getFields(\PSC\System\PluginBundle\Form\Interfaces\Field::Shop) as $field) {
$field->formPreSetData($event);
}
});
$builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
/** @var \PSC\System\PluginBundle\Form\Interfaces\Field $field */
foreach ($this->fields->getFields(\PSC\System\PluginBundle\Form\Interfaces\Field::Shop) as $field) {
$field->formPostSetData($event);
}
});
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
/** @var \PSC\System\PluginBundle\Form\Interfaces\Field $field */
foreach ($this->fields->getFields(\PSC\System\PluginBundle\Form\Interfaces\Field::Shop) as $field) {
$field->formPostSubmit($event);
}
});
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
/** @var \PSC\System\PluginBundle\Form\Interfaces\Field $field */
foreach ($this->fields->getFields(\PSC\System\PluginBundle\Form\Interfaces\Field::Shop) as $field) {
$field->formPreSubmit($event);
@ -553,9 +742,9 @@ class ShopSettingsType extends AbstractType
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
$resolver->setDefaults([
'data_class' => 'PSC\Shop\EntityBundle\Document\Shop',
'translation_domain' => 'core_settings_edit'
));
'translation_domain' => 'core_settings_edit',
]);
}
}

View File

@ -21,7 +21,7 @@
{{ form_errors(form) }}
<div class="panel">
<div class="header">
<h4>{{ shop.title }} {{ shop.uid }}</h4>
<h4>{{ shop.title }} (ID: {{ shop.uid }})</h4>
</div>
<div class="body">
<div class="row">

View File

@ -0,0 +1,41 @@
<?php
namespace Tests\PSC\System\SettingsBundle\Api;
use PSC\Shop\ContactBundle\Repository\ContactRepository;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Tests\RefreshDatabaseTrait;
class PaperDBTest extends WebTestCase
{
use RefreshDatabaseTrait;
public function testGet(): void
{
$client = static::createClient();
$userRepository = static::getContainer()->get(ContactRepository::class);
$testUser = $userRepository->loadUserByUsername('company@shop.de');
$client->loginUser($testUser, 'api');
$client->jsonRequest('GET', '/api/system/papercontainer', [], []);
$this->assertResponseIsSuccessful();
var_dump($client->getResponse()->getContent());
self::assertJson($client->getResponse()->getContent());
}
public function testPUT(): void
{
$client = static::createClient();
$userRepository = static::getContainer()->get(ContactRepository::class);
$testUser = $userRepository->loadUserByUsername('company@shop.de');
$client->loginUser($testUser, 'api');
$client->jsonRequest('GET', '/api/system/papercontainer', [], []);
$this->assertResponseIsSuccessful();
self::assertJson($client->getResponse()->getContent());
}
}

View File

@ -19,7 +19,9 @@ class DesignTest extends WebTestCase
'/api/plugin/system/psc/xmlcalc/product/design',
[
'product' => '01938686-0e4d-7da9-bae3-b2e1b1681f9f',
'jsonProduct' => '[{"uuid":"df2df718-b28e-482d-bf0c-67d246f05d32","name":"Test Artikel","options":[{"id":"auflage","name":"Auflage","default":"100","dependencys":[],"placeHolder":"Placeholder","required":false,"type":2},{"id":"seiten_umschlag","name":"Seiten Umschlag","default":"2","dependencys":[],"placeHolder":"Placeholder","required":false,"type":2},{"id":"seiten_anzahl_inhalt","name":"Seiten Anzahl Inhalt","default":"10","dependencys":[{"relation":"auflage","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vauflage$V*0.12","price":0,"value":"1-10","dependencys":[{"relation":"seiten_umschlag","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vseiten_umschlag$V*0.24","price":0,"value":"1-2","dependencys":[]},{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vseiten_umschlag$V*0.23","price":0,"value":"3-","dependencys":[]}]}]},{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vauflage$V*0.11","price":0,"value":"11-","dependencys":[{"relation":"seiten_umschlag","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vseiten_umschlag$V*0.21","price":0,"value":"1-2","dependencys":[]},{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vseiten_umschlag$V*0.20","price":0,"value":"3-","dependencys":[]}]}]}]}],"placeHolder":"Placeholder","required":true,"type":2},{"id":"farbigkeit","name":"Farbigkeit","default":"10","dependencys":[],"type":3,"options":[{"id":"10","name":"1\/0 farbig","dependencys":[{"relation":"auflage","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"","price":0,"value":"1-101","dependencys":[]}]}]},{"id":"11","name":"1\/1 farbig","dependencys":[]},{"id":"20","name":"2\/0 farbig","dependencys":[]},{"id":"21","name":"2\/1 farbig","dependencys":[]},{"id":"22","name":"2\/2 farbig","dependencys":[{"relation":"auflage","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"","price":0,"value":"11-50","dependencys":[]}]}]}],"mode":"normal"},{"id":"calc","name":"calc","dependencys":[{"relation":"auflage","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vauflage$V*$Vseiten_anzahl_inhalt$V","price":0,"value":"1-","dependencys":[]}]}],"type":1}]}]',
'jsonProduct' => json_decode(
'[{"uuid":"df2df718-b28e-482d-bf0c-67d246f05d32","name":"Test Artikel","options":[{"id":"auflage","name":"Auflage","default":"100","dependencys":[],"placeHolder":"Placeholder","required":false,"type":2},{"id":"seiten_umschlag","name":"Seiten Umschlag","default":"2","dependencys":[],"placeHolder":"Placeholder","required":false,"type":2},{"id":"seiten_anzahl_inhalt","name":"Seiten Anzahl Inhalt","default":"10","dependencys":[{"relation":"auflage","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vauflage$V*0.12","price":0,"value":"1-10","dependencys":[{"relation":"seiten_umschlag","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vseiten_umschlag$V*0.24","price":0,"value":"1-2","dependencys":[]},{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vseiten_umschlag$V*0.23","price":0,"value":"3-","dependencys":[]}]}]},{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vauflage$V*0.11","price":0,"value":"11-","dependencys":[{"relation":"seiten_umschlag","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vseiten_umschlag$V*0.21","price":0,"value":"1-2","dependencys":[]},{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vseiten_umschlag$V*0.20","price":0,"value":"3-","dependencys":[]}]}]}]}],"placeHolder":"Placeholder","required":true,"type":2},{"id":"farbigkeit","name":"Farbigkeit","default":"10","dependencys":[],"type":3,"options":[{"id":"10","name":"1\/0 farbig","dependencys":[{"relation":"auflage","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"","price":0,"value":"1-101","dependencys":[]}]}]},{"id":"11","name":"1\/1 farbig","dependencys":[]},{"id":"20","name":"2\/0 farbig","dependencys":[]},{"id":"21","name":"2\/1 farbig","dependencys":[]},{"id":"22","name":"2\/2 farbig","dependencys":[{"relation":"auflage","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"","price":0,"value":"11-50","dependencys":[]}]}]}],"mode":"normal"},{"id":"calc","name":"calc","dependencys":[{"relation":"auflage","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vauflage$V*$Vseiten_anzahl_inhalt$V","price":0,"value":"1-","dependencys":[]}]}],"type":1}]}]',
),
],
[],
);

View File

@ -0,0 +1,32 @@
<?php
namespace Plugins\System\PSC\XmlCalc\Api;
use PSC\Shop\ContactBundle\Repository\ContactRepository;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Tests\RefreshDatabaseTrait;
class JsonTest extends WebTestCase
{
use RefreshDatabaseTrait;
public function testJsonApi(): void
{
$client = static::createClient();
$client->jsonRequest(
'POST',
'/api/plugin/system/psc/xmlcalc/product/json',
[
'product' => '01938686-0e4d-7da9-bae3-b2e1b1681f9f',
'json' => json_decode(
'[{"uuid":"df2df718-b28e-482d-bf0c-67d246f05d32","name":"Test Artikel","options":[{"id":"auflage","name":"Auflage","default":"100","dependencys":[],"placeHolder":"Placeholder","required":false,"type":2},{"id":"seiten_umschlag","name":"Seiten Umschlag","default":"2","dependencys":[],"placeHolder":"Placeholder","required":false,"type":2},{"id":"seiten_anzahl_inhalt","name":"Seiten Anzahl Inhalt","default":"10","dependencys":[{"relation":"auflage","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vauflage$V*0.12","price":0,"value":"1-10","dependencys":[{"relation":"seiten_umschlag","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vseiten_umschlag$V*0.24","price":0,"value":"1-2","dependencys":[]},{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vseiten_umschlag$V*0.23","price":0,"value":"3-","dependencys":[]}]}]},{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vauflage$V*0.11","price":0,"value":"11-","dependencys":[{"relation":"seiten_umschlag","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vseiten_umschlag$V*0.21","price":0,"value":"1-2","dependencys":[]},{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vseiten_umschlag$V*0.20","price":0,"value":"3-","dependencys":[]}]}]}]}],"placeHolder":"Placeholder","required":true,"type":2},{"id":"farbigkeit","name":"Farbigkeit","default":"10","dependencys":[],"type":3,"options":[{"id":"10","name":"1\/0 farbig","dependencys":[{"relation":"auflage","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"","price":0,"value":"1-101","dependencys":[]}]}]},{"id":"11","name":"1\/1 farbig","dependencys":[]},{"id":"20","name":"2\/0 farbig","dependencys":[]},{"id":"21","name":"2\/1 farbig","dependencys":[]},{"id":"22","name":"2\/2 farbig","dependencys":[{"relation":"auflage","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"","price":0,"value":"11-50","dependencys":[]}]}]}],"mode":"normal"},{"id":"calc","name":"calc","dependencys":[{"relation":"auflage","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vauflage$V*$Vseiten_anzahl_inhalt$V","price":0,"value":"1-","dependencys":[]}]}],"type":1}]}]',
),
],
[],
);
$this->assertResponseIsSuccessful();
self::assertJson($client->getResponse()->getContent());
}
}

View File

@ -0,0 +1,55 @@
<?php
namespace Plugins\System\PSC\XmlCalc\Api;
use PSC\Shop\ContactBundle\Repository\ContactRepository;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Tests\RefreshDatabaseTrait;
class ShopTest extends WebTestCase
{
use RefreshDatabaseTrait;
public function testGet(): void
{
$client = static::createClient();
$userRepository = static::getContainer()->get(ContactRepository::class);
$testUser = $userRepository->loadUserByUsername('company@shop.de');
$client->loginUser($testUser, 'api');
$client->jsonRequest('GET', '/api/plugin/system/psc/xmlcalc/shop/771a1176-d531-48ed-93b8-eec1fd4b917f', [], []);
$this->assertResponseIsSuccessful();
self::assertJson($client->getResponse()->getContent());
}
public function testUpdate(): void
{
$client = static::createClient();
$userRepository = static::getContainer()->get(ContactRepository::class);
$testUser = $userRepository->loadUserByUsername('company@shop.de');
$client->loginUser($testUser, 'api');
$str = '$test1 = 12;' . PHP_EOL . '$test2 => 13;' . PHP_EOL . '$test3 = 15;';
$client->jsonRequest(
'PUT',
'/api/plugin/system/psc/xmlcalc/shop/771a1176-d531-48ed-93b8-eec1fd4b917f',
[
'parameter' => $str,
],
[],
);
$this->assertResponseIsSuccessful();
self::assertJson($client->getResponse()->getContent());
$client->jsonRequest('GET', '/api/plugin/system/psc/xmlcalc/shop/771a1176-d531-48ed-93b8-eec1fd4b917f', [], []);
$this->assertResponseIsSuccessful();
self::assertJson($client->getResponse()->getContent());
self::assertSame($str, json_decode($client->getResponse()->getContent(), true)['parameter']);
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace Plugins\System\PSC\XmlCalc\Api;
use PSC\Shop\ContactBundle\Repository\ContactRepository;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Tests\RefreshDatabaseTrait;
class SystemTest extends WebTestCase
{
use RefreshDatabaseTrait;
public function testGetApi(): void
{
$client = static::createClient();
$userRepository = static::getContainer()->get(ContactRepository::class);
$testUser = $userRepository->loadUserByUsername('company@shop.de');
$client->loginUser($testUser, 'api');
$client->jsonRequest('GET', '/api/plugin/system/psc/xmlcalc/shop/771a1176-d531-48ed-93b8-eec1fd4b917f', [], []);
$this->assertResponseIsSuccessful();
self::assertJson($client->getResponse()->getContent());
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace Plugins\System\PSC\XmlCalc\Api;
use PSC\Shop\ContactBundle\Repository\ContactRepository;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Tests\RefreshDatabaseTrait;
class XMLTest extends WebTestCase
{
use RefreshDatabaseTrait;
public function testXMLApi(): void
{
$client = static::createClient();
$client->jsonRequest(
'POST',
'/api/plugin/system/psc/xmlcalc/product/xml',
[
'product' => '01938686-0e4d-7da9-bae3-b2e1b1681f9f',
'xml' => '<?xml version="1.0" encoding="utf-8"?>
<kalkulation>
<artikel>
<name>SD-Durchschreibesätze A4-Blocks</name>
<kommentar>210 mm x 297 mm</kommentar>
<option id="auflage" name="Auflage" type="Input" default="10"/>
<option id="calc_rabatt" type="Hidden">
<contact.accountType default="1">
<grenze calc_value="1">0-1</grenze>
<grenze calc_value="0.8">2</grenze>
<grenze calc_value="0.5">3</grenze>
</contact.accountType>
</option>
<option id="calc_rabatt_account" type="Hidden">
<contact.account default="1">
<grenze calc_value="1">1</grenze>
<grenze calc_value="8">2</grenze>
<grenze calc_value="5">3</grenze>
</contact.account>
</option>
<option id="selectTest" name="selectTest" type="Select" default="1">
<opt id="1" name="eins"></opt>
<opt id="2" name="zwei"></opt>
</option>
<option id="calc" type="Hidden">
<auflage>
<grenze formel="0.26*$Vauflage$V">1-</grenze>
</auflage>
</option>
</artikel>
</kalkulation>',
],
[],
);
$this->assertResponseIsSuccessful();
self::assertJson($client->getResponse()->getContent());
}
}

View File

@ -16,6 +16,7 @@
"reka-ui": "^2.3.2",
"tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.10",
"ts-debounce": "^4.0.0",
"tw-animate-css": "^1.3.4",
"uuid": "^11.1.0",
"vue": "^3.5.13",
@ -23,6 +24,7 @@
"vue-draggable-plus": "^0.6.0",
"vue-i18n": "^11.1.9",
"xml-beautify": "^1.2.3",
"xml-formatter": "^3.6.6",
},
"devDependencies": {
"@types/node": "^24.0.1",
@ -582,6 +584,8 @@
"totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="],
"ts-debounce": ["ts-debounce@4.0.0", "", {}, "sha512-+1iDGY6NmOGidq7i7xZGA4cm8DAa6fqdYcvO5Z6yBevH++Bdo9Qt/mN0TzHUgcCcKv1gmh9+W5dHqz8pMWbCbg=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"tw-animate-css": ["tw-animate-css@1.3.4", "", {}, "sha512-dd1Ht6/YQHcNbq0znIT6dG8uhO7Ce+VIIhZUhjsryXsMPJQz3bZg7Q2eNzLwipb25bRZslGb2myio5mScd1TFg=="],
@ -628,6 +632,10 @@
"xml-beautify": ["xml-beautify@1.2.3", "", {}, "sha512-VsYpkqoVawIP84pi00XukPsgQHqOhgrpwTHlXqqRMAgYZ1u+Yw3KHIUhO1Igf19d5CQ5h6ExJT1hFCJRLmzADg=="],
"xml-formatter": ["xml-formatter@3.6.6", "", { "dependencies": { "xml-parser-xo": "^4.1.4" } }, "sha512-yfofQht42x2sN1YThT6Er6GFXiQinfDAsMTNvMPi2uZw5/Vtc2PYHfvALR8U+b2oN2ekBxLd2tGWV06rAM8nQA=="],
"xml-parser-xo": ["xml-parser-xo@4.1.4", "", {}, "sha512-wo+yWDNeMwd1ctzH4CsiGXaAappDsxuR+VnmPewOzHk/zvefksT2ZlcWpAePl11THOWgnIZM4GjvumevurNWZw=="],
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
"yoctocolors": ["yoctocolors@2.1.1", "", {}, "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ=="],

View File

@ -22,13 +22,14 @@
"reka-ui": "^2.3.2",
"tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.10",
"ts-debounce": "^4.0.0",
"tw-animate-css": "^1.3.4",
"uuid": "^11.1.0",
"vue": "^3.5.13",
"vue-codemirror": "^6.1.1",
"vue-draggable-plus": "^0.6.0",
"vue-i18n": "^11.1.9",
"xml-beautify": "^1.2.3"
"xml-formatter": "^3.6.6"
},
"devDependencies": {
"@types/node": "^24.0.1",

View File

@ -1,16 +1,25 @@
<script setup lang="ts">
import Gui from './components/Gui.vue'
import { onMounted } from 'vue'
import { useElementStore } from './stores/Items'
import { useItemStore } from './stores/Items'
import { useGlobalStore } from './stores/Global'
onMounted(() => {
const store = useElementStore();
const params = new URLSearchParams(window.location.search);
const uuid = params.get('uuid');
const itemStore = useItemStore()
const globalStore = useGlobalStore()
const params = new URLSearchParams(window.location.search)
const uuid = params.get('uuid')
if (uuid) {
store.loadConfigFromProductApi(uuid);
store.loadFormulaAnalyserDataFromApi(uuid);
globalStore.setProductUuid(uuid)
globalStore.loadConfigFromProductApi(uuid).then(data => {
itemStore.parseJSON(data)
})
globalStore.loadFormulaAnalyserDataFromApi(uuid)
}
itemStore.$subscribe((mutation, state) => {
globalStore.saveDesign(itemStore.loadJSON());
});
})
</script>

View File

@ -5,6 +5,8 @@ import {
ResizablePanelGroup,
} from '../components/ui/resizable'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '../components/ui/tabs'
import TopBar from './app/TopBar.vue'
import { useGlobalStore } from '../stores/Global'
import { Library } from '../components/app/library'
import { ElementProperties, SpecialElementProperties } from '../components/app/elementproperties'
@ -13,10 +15,16 @@ import { Main } from '../components/app/main'
import FormulaVisualizer from './app/FormulaVisualizer.vue'
import JsonView from './app/JsonView.vue'
import XmlView from './app/XmlView.vue'
import ParameterView from './app/ParameterView.vue'
import PaperDBView from './app/PaperDBView.vue'
import FormelView from './app/FormelView.vue'
const globalStore = useGlobalStore()
</script>
<template>
<div class="w-screen h-screen">
<div class="w-screen h-screen flex flex-col">
<div class="flex-grow w-full h-full ">
<ResizablePanelGroup
id="handle-demo-group-1"
direction="horizontal"
@ -24,12 +32,13 @@ import XmlView from './app/XmlView.vue'
>
<ResizablePanel id="" :default-size="15">
<div class="flex flex-col gap-2 h-full">
<TopBar />
<Library />
</div>
</ResizablePanel>
<ResizableHandle id="" with-handle />
<ResizablePanel id="" :default-size="85">
<Tabs default-value="designer" class="w-full h-full">
<Tabs :default-value="globalStore.currentTab" @update:model-value="(value) => globalStore.setCurrentTab(value)" class="w-full h-full">
<div class="flex justify-center">
<TabsList>
<TabsTrigger value="designer">
@ -41,8 +50,14 @@ import XmlView from './app/XmlView.vue'
<TabsTrigger value="xml">
{{ $t('xml_view') }}
</TabsTrigger>
<TabsTrigger value="json">
{{ $t('json_view') }}
<TabsTrigger value="formel">
{{ $t('formel_view') }}
</TabsTrigger>
<TabsTrigger value="parameter">
{{ $t('parameter_view') }}
</TabsTrigger>
<TabsTrigger value="paperdb">
{{ $t('paperdb_view') }}
</TabsTrigger>
</TabsList>
</div>
@ -57,8 +72,14 @@ import XmlView from './app/XmlView.vue'
<TabsContent value="xml" class="h-full overflow-y-auto">
<XmlView />
</TabsContent>
<TabsContent value="json" class="h-full overflow-y-auto">
<JsonView />
<TabsContent value="formel" class="h-full overflow-y-auto">
<FormelView />
</TabsContent>
<TabsContent value="parameter" class="h-full overflow-y-auto">
<ParameterView />
</TabsContent>
<TabsContent value="paperdb" class="h-full overflow-y-auto">
<PaperDBView />
</TabsContent>
</Tabs>
</ResizablePanel>
@ -67,6 +88,7 @@ import XmlView from './app/XmlView.vue'
<SpecialElementProperties />
<ElementDependency />
</div>
</div>
</template>
<style scoped>

View File

@ -0,0 +1,44 @@
<script setup lang="ts">
import { ref, watch } from 'vue'
import { Codemirror } from 'vue-codemirror'
import { xml } from '@codemirror/lang-xml'
import { useGlobalStore } from '../../stores/Global'
import xmlFormat from 'xml-formatter'
import { debounce } from 'ts-debounce'
import { Button } from '../ui/button'
const store = useGlobalStore();
const xmlString = ref(xmlFormat(store.formel))
const extensions = [xml()];
const cmOptions = {
lineNumbers: true,
mode: 'application/xml',
theme: 'default',
};
watch(xmlString, (formel) => {
store.formel = formel
})
function manualSync() {
store.manualSync()
}
</script>
<template>
<div class="p-4">
<Button @click="manualSync" :disabled="store.syncing">
{{ store.syncing ? $t('syncing') : $t('sync') }}
</Button>
<codemirror
v-model="xmlString"
:options="cmOptions"
:extensions="extensions"
/>
</div>
</template>

View File

@ -1,22 +1,14 @@
<script setup lang="ts">
import { ref, onMounted, provide, computed } from 'vue';
import { ref, provide, computed } from 'vue';
import NodeRenderer from './NodeRenderer.vue';
import { useElementStore } from '../../stores/Items';
interface Node {
name: string;
unParsed?: string;
parsed?: string;
result?: number;
parts: Node[];
}
import { useGlobalStore } from '../../stores/Global';
const expandedNodes = ref(new Set<string>());
const store = useElementStore();
const globalStore = useGlobalStore();
const parsedData = computed(() => store.getFormulaData);
const error = computed(() => store.getFormulaError);
const isLoading = computed(() => store.isFormulaLoading);
const parsedData = computed(() => globalStore.getFormulaData);
const error = computed(() => globalStore.getFormulaError);
const isLoading = computed(() => globalStore.isFormulaLoading);
const toggleNode = (nodeId: string) => {
const newExpanded = new Set(expandedNodes.value);
@ -85,7 +77,7 @@ const getColoredFormulaParts = (formulaString: string) => {
const totalSum = () => {
if (!parsedData.value) return 0;
return parsedData.value.reduce((sum, root) => sum + (root.result || 0), 0);
return parsedData.value.reduce((sum, item: any) => sum + (item.result || 0), 0);
};
provide('expandedNodes', expandedNodes);
@ -129,7 +121,7 @@ provide('getColoredFormulaParts', getColoredFormulaParts);
<div class="flex items-center justify-between bg-green-50 p-4 rounded-lg">
<div class="flex items-center space-x-3">
<span class="text-lg font-medium text-gray-800">
{{ parsedData.map(root => root.result || 0).join(' + ') }}
{{ parsedData.map((root: any) => root.result || 0).join(' + ') }}
</span>
<span class="text-gray-500">=</span>
<span class="text-2xl font-bold text-green-600">

View File

@ -10,18 +10,18 @@
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import { computed } from 'vue';
import { Codemirror } from 'vue-codemirror';
import { json } from '@codemirror/lang-json';
import { useElementStore } from '../../stores/Items';
import { useGlobalStore } from '../../stores/Global';
const store = useElementStore();
const globalStore = useGlobalStore();
const jsonString = computed(() => {
try {
// The store.json is already a string, but we parse and re-stringify it
// to ensure it's well-formed and nicely formatted.
const parsed = JSON.parse(store.json);
const parsed = JSON.parse(globalStore.json);
return JSON.stringify(parsed, null, 2);
} catch (e) {
return "Invalid JSON in store";
@ -34,6 +34,5 @@ const cmOptions = {
lineNumbers: true,
mode: 'application/json',
theme: 'default',
readOnly: true,
};
</script>

View File

@ -0,0 +1,44 @@
<script setup lang="ts">
import { ref, watch } from 'vue'
import { Codemirror } from 'vue-codemirror'
import { xml } from '@codemirror/lang-xml'
import { useGlobalStore } from '../../stores/Global'
import xmlFormat from 'xml-formatter'
import { debounce } from 'ts-debounce'
import { Button } from '../ui/button'
const store = useGlobalStore();
const xmlString = ref(xmlFormat(store.paperdb))
const extensions = [xml()];
const cmOptions = {
lineNumbers: true,
mode: 'application/xml',
theme: 'default',
};
watch(xmlString, (paperdb) => {
store.paperdb = paperdb
})
function manualSync() {
store.manualSync()
}
</script>
<template>
<div class="p-4">
<Button @click="manualSync" :disabled="store.syncing">
{{ store.syncing ? $t('syncing') : $t('sync') }}
</Button>
<codemirror
v-model="xmlString"
:options="cmOptions"
:extensions="extensions"
/>
</div>
</template>

View File

@ -0,0 +1,44 @@
<script setup lang="ts">
import { ref, watch } from 'vue'
import { Codemirror } from 'vue-codemirror'
import { xml } from '@codemirror/lang-xml'
import { useGlobalStore } from '../../stores/Global'
import xmlFormat from 'xml-formatter'
import { debounce } from 'ts-debounce'
import { Button } from '../ui/button'
const store = useGlobalStore();
const xmlString = ref(xmlFormat(store.parameter))
const extensions = [xml()];
const cmOptions = {
lineNumbers: true,
mode: 'application/xml',
theme: 'default',
};
watch(xmlString, (parameter) => {
store.parameter = parameter
})
function manualSync() {
store.manualSync()
}
</script>
<template>
<div class="p-4">
<Button @click="manualSync" :disabled="store.syncing">
{{ store.syncing ? $t('syncing') : $t('sync') }}
</Button>
<codemirror
v-model="xmlString"
:options="cmOptions"
:extensions="extensions"
/>
</div>
</template>

View File

@ -0,0 +1,20 @@
<script setup lang="ts">
import { Button } from '../ui/button'
import { useGlobalStore } from '../../stores/Global'
import { useItemStore } from '../../stores/Items'
const globalStore = useGlobalStore()
const itemStore = useItemStore()
function manualSave() {
globalStore.manualSave(itemStore.loadJSON())
}
</script>
<template>
<div class="w-full p-2 flex">
<Button @click="manualSave" :disabled="globalStore.saving">
{{ globalStore.saving ? $t('saving') : $t('save') }}
</Button>
</div>
</template>

View File

@ -1,28 +1,15 @@
<template>
<div class="p-4">
<codemirror
v-model="xmlString"
:options="cmOptions"
:extensions="extensions"
disabled
/>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { Codemirror } from 'vue-codemirror';
import { xml } from '@codemirror/lang-xml';
import { useElementStore } from '../../stores/Items';
import XmlBeautify from 'xml-beautify'
import { ref, watch } from 'vue'
import { Codemirror } from 'vue-codemirror'
import { xml } from '@codemirror/lang-xml'
import { useGlobalStore } from '../../stores/Global'
import xmlFormat from 'xml-formatter'
import { debounce } from 'ts-debounce'
import { Button } from '../ui/button'
const store = useElementStore();
const store = useGlobalStore();
const xmlString = computed(() => new XmlBeautify().beautify(store.xml,
{
indent: " ", //indent pattern like white spaces
useSelfClosingElement: true //true:use self-closing element when empty element.
}));
const xmlString = ref(xmlFormat(store.xml))
const extensions = [xml()];
@ -30,7 +17,28 @@ const cmOptions = {
lineNumbers: true,
mode: 'application/xml',
theme: 'default',
readOnly: true,
};
watch(xmlString, (xml) => {
store.xml = xml
})
function manualSync() {
store.manualSync()
}
</script>
<template>
<div class="p-4">
<Button @click="manualSync" :disabled="store.syncing">
{{ store.syncing ? $t('syncing') : $t('sync') }}
</Button>
<codemirror
v-model="xmlString"
:options="cmOptions"
:extensions="extensions"
/>
</div>
</template>

View File

@ -1,5 +1,5 @@
<script lang="ts" setup>
import { useElementStore } from '../../../stores/Items'
import { useItemStore } from '../../../stores/Items'
import { Input } from '../../../components/ui/input'
import { Button } from '../../../components/ui/button'
import { Label } from '../../../components/ui/label'
@ -12,7 +12,7 @@ defineProps<{
dependencys: Dependency[]
}>()
const store = useElementStore()
const itemStore = useItemStore()
function addBorder(dep: Dependency) {
dep.addBorder(new Border())
@ -29,7 +29,7 @@ function addBorder(dep: Dependency) {
<SelectValue placeholder="Select Relation" />
</SelectTrigger>
<SelectContent>
<SelectItem v-for="item in store.getItems" :value="item.id">{{item.id}}</SelectItem>
<SelectItem v-for="item in itemStore.getItems" :value="item.id">{{item.id}}</SelectItem>
</SelectContent>
</Select>
<Label for="formula">Formula</Label>

View File

@ -1,6 +1,6 @@
<script lang="ts" setup>
import { ref, watch } from 'vue'
import { useElementStore } from '../../../stores/Items'
import { useGlobalStore } from '../../../stores/Global'
import { Button } from '../../../components/ui/button'
import { Dependency } from '.'
import { default as DepModel } from '../../../model/Dependency.ts'
@ -13,22 +13,22 @@ import {
DialogTitle,
} from '../../../components/ui/dialog'
const store = useElementStore()
const globalStore = useGlobalStore()
let openModal = ref(false)
function addDependency() {
store.getActiveItem.addDependency(new DepModel());
globalStore.getActiveItem.addDependency(new DepModel());
}
store.$subscribe((mutation, state) => {
globalStore.$subscribe((mutation, state) => {
if(state.showDependency) {
openModal.value = true
}
})
watch(openModal, (newOpenModal) => {
if(newOpenModal === false) {
store.setShowDependency(false)
globalStore.setShowDependency(false)
}
})
@ -44,7 +44,7 @@ watch(openModal, (newOpenModal) => {
</DialogHeader>
<div class="overflow-auto h-full w-full">
<Button v-on:click="addDependency()">Add Dependency</Button>
<Dependency :dependencys="store.getActiveItem.dependencys" />
<Dependency :dependencys="globalStore.getActiveItem.dependencys" />
</div>
<DialogFooter>

View File

@ -1,5 +1,5 @@
<script lang="ts" setup>
import { useElementStore } from '../../../stores/Items'
import { useGlobalStore } from '../../../stores/Global'
import InputElement from '../../../model/InputElement'
import SelectElement from '../../../model/SelectElement'
import MediaElement from '../../../model/MediaElement'
@ -28,16 +28,16 @@ import {
let openModal = ref(false)
let emit = defineEmits(['update:modelValue']);
const store = useElementStore()
const globalStore = useGlobalStore()
store.$subscribe((mutation, state) => {
globalStore.$subscribe((mutation, state) => {
if(state.showProperties) {
openModal.value = true
}
})
watch(openModal, (newOpenModal) => {
if(newOpenModal === false) {
store.setShowProperties(false)
globalStore.setShowProperties(false)
}
})
</script>
@ -52,50 +52,50 @@ watch(openModal, (newOpenModal) => {
</SheetHeader>
<div class="flex flex-col w-full m-2">
<HeadlineElementProperties
v-if="store.getActiveItem.type === 6"
v-model="store.getActiveItem as HeadlineElement"
v-if="globalStore.getActiveItem.type === 6"
v-model="globalStore.getActiveItem as HeadlineElement"
>
</HeadlineElementProperties>
<MediaElementProperties
v-if="store.getActiveItem.type === 9"
v-model="store.getActiveItem as MediaElement"
v-if="globalStore.getActiveItem.type === 9"
v-model="globalStore.getActiveItem as MediaElement"
>
</MediaElementProperties>
<RowProperties
v-if="store.getActiveItem.type === 7"
v-model="store.getActiveItem as Row"
v-if="globalStore.getActiveItem.type === 7"
v-model="globalStore.getActiveItem as Row"
>
</RowProperties>
<TextareaElementProperties
v-if="store.getActiveItem.type === 5"
v-model="store.getActiveItem as TextareaElement"
v-if="globalStore.getActiveItem.type === 5"
v-model="globalStore.getActiveItem as TextareaElement"
>
</TextareaElementProperties>
<TextElementProperties
v-if="store.getActiveItem.type === 4"
v-model="store.getActiveItem as TextElement"
v-if="globalStore.getActiveItem.type === 4"
v-model="globalStore.getActiveItem as TextElement"
>
</TextElementProperties>
<SelectElementProperties
v-if="store.getActiveItem.type === 3"
v-model="store.getActiveItem as SelectElement"
v-if="globalStore.getActiveItem.type === 3"
v-model="globalStore.getActiveItem as SelectElement"
>
</SelectElementProperties>
<InputElementProperties
v-if="store.getActiveItem.type === 2"
v-model="store.getActiveItem as InputElement"
v-if="globalStore.getActiveItem.type === 2"
v-model="globalStore.getActiveItem as InputElement"
>
</InputElementProperties>
<HiddenElementProperties
v-if="store.getActiveItem.type === 1"
v-model="store.getActiveItem as HiddenElement"
v-if="globalStore.getActiveItem.type === 1"
v-model="globalStore.getActiveItem as HiddenElement"
>
</HiddenElementProperties>
</div>

View File

@ -1,18 +1,17 @@
<script lang="ts" setup>
import { useElementStore } from '../../../stores/Items'
import { useGlobalStore } from '../../../stores/Global'
import SelectSpecialProperties from '../properties/SelectSpecial.vue'
import { ref, watch } from 'vue'
import SelectElement from '../../../model/SelectElement'
let emit = defineEmits(['update:modelValue']);
const store = useElementStore()
const globalStore = useGlobalStore()
</script>
<template>
<div class="">
<SelectSpecialProperties
v-model="store.getActiveItem as SelectElement"
v-model="globalStore.getActiveItem as SelectElement"
>
</SelectSpecialProperties>

View File

@ -19,6 +19,6 @@ const theModel = computed({
<template>
<div class="flex gap-2 flex-row">
<label class="w-60 flex-inital">{{theModel.name}}</label>
<label class="w-60 flex-inital">{{theModel.id}}</label>
</div>
</template>

View File

@ -20,6 +20,6 @@ const theModel = computed<InputElement>({
<template>
<div class="flex gap-2 flex-row items-center">
<label class="w-60 flex-inital">{{theModel.name}}</label>
<Input v-model:placeholder="theModel.placeHolder" :modelValue="theModel.default" v-model:name="theModel.name" v-model:id="theModel.id" v-model:required="theModel.required"/>
<Input v-model:placeholder="theModel.placeHolder" v-model="theModel.default" v-model:name="theModel.name" v-model:id="theModel.id" v-model:required="theModel.required"/>
</div>
</template>

View File

@ -5,7 +5,8 @@ import BaseElement from '../../../model/BaseElement';
import { ref, computed } from 'vue';
import EmptyElementForm from './EmptyElementForm.vue'
import { RenderElements } from './../renderelements'
import { useElementStore } from '../../../stores/Items'
import { useItemStore } from '../../../stores/Items'
import { useGlobalStore } from '../../../stores/Global'
import Parser from '../../../lib/parser'
import { CirclePlus } from 'lucide-vue-next';
@ -19,7 +20,8 @@ let emit = defineEmits(['update:modelValue']);
const dragUuid = ref("");
let isPreview = ref(false)
const store = useElementStore()
const itemStore = useItemStore()
const globalStore = useGlobalStore()
const theModel = computed({
get: () => props.modelValue,
@ -29,19 +31,19 @@ const theModel = computed({
const onDrop = (event: DragEvent, targetUuid: string, column: Column) => {
dragUuid.value = ""
if(event.dataTransfer?.getData('mode') == "sort") {
let item: BaseElement|null = store.cutItem(store.getSourceDragUuid)
let item: BaseElement|null = itemStore.cutItem(globalStore.getSourceDragUuid)
if(item !== null) {
column.items.push(item)
}
store.setDragMode("")
globalStore.setDragMode("")
event.stopImmediatePropagation()
}
if(store.getDragMode == "insert") {
if(globalStore.getDragMode == "insert") {
const itemId = Number(event.dataTransfer?.getData('itemId'));
column.items.push(Parser.getModelForType(itemId))
store.setDragMode("")
globalStore.setDragMode("")
event.stopImmediatePropagation()
}
}
@ -51,7 +53,7 @@ const dragLeaveEmpty = (event: DragEvent, uuid: string) => {
event.stopImmediatePropagation()
}
store.$subscribe((mutation, state) => {
globalStore.$subscribe((mutation, state) => {
if(state.showPreview) {
isPreview.value = true
}else{
@ -62,7 +64,7 @@ store.$subscribe((mutation, state) => {
const dragEnterEmpty = (event: DragEvent, uuid: string) => {
dragUuid.value = uuid
event.stopImmediatePropagation()
if(store.getDragMode == "sort" && uuid != store.getSourceDragUuid) {
if(globalStore.getDragMode == "sort" && uuid != globalStore.getSourceDragUuid) {
event.stopImmediatePropagation()
}
}

View File

@ -28,7 +28,7 @@ const theModel = computed({
<div class="flex gap-2 flex-row items-center">
<label class="w-60 flex-inital">{{theModel?.name}}</label>
<div class="w-full">
<Select :modelValue="theModel?.default">
<Select v-model="theModel!.default">
<SelectTrigger>
<SelectValue />
</SelectTrigger>

View File

@ -1,13 +1,13 @@
<script setup lang="ts">
import { useElementStore } from '../../../stores/Items'
import { useGlobalStore } from '../../../stores/Global'
import { Image, SquareParking, SquareDot, SquareMenu, SquarePen, SquareChevronDown, SquareDashed } from 'lucide-vue-next';
import { Switch } from '../../../components/ui/switch'
import { Label } from '../../../components/ui/label'
import { ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
const { t, locale } = useI18n()
const store = useElementStore()
const { locale } = useI18n()
const globalStore = useGlobalStore()
let previewMode = ref(false)
@ -17,14 +17,14 @@ function startDrag(event: DragEvent, item: string) {
event.dataTransfer.effectAllowed = 'move'
event.dataTransfer.setData('itemId', item)
}
store.setDragMode("insert")
globalStore.setDragMode("insert")
}
watch(previewMode, (newPreviewMode) => {
if(newPreviewMode === false) {
store.setShowPreview(false)
globalStore.setShowPreview(false)
}else{
store.setShowPreview(true)
globalStore.setShowPreview(true)
}
})
@ -32,6 +32,7 @@ watch(previewMode, (newPreviewMode) => {
<template>
<div class="flex flex-col p-3 gap-3 overflow-auto">
<div class="flex flex-row gap-2">
<div class="flex items-center space-x-2">
<select v-model="locale">
<option value="de">DE</option>
@ -42,6 +43,7 @@ watch(previewMode, (newPreviewMode) => {
<Switch id="preview-mode" v-model="previewMode" />
<Label for="preview-mode">{{ $t('preview_mode') }}</Label>
</div>
</div>
<div id="headline" class="border-1 p-2 w-full flex flex-row gap-2" draggable="true" @dragstart="startDrag($event, '6')" @dragenter.prevent @dragover.prevent>
<SquareDot />
<span>{{ $t('headline') }}</span>

View File

@ -1,21 +1,22 @@
<script setup lang="ts">
import { RenderElements } from '../../../components/app/renderelements'
import { useElementStore } from '../../../stores/Items'
import { useGlobalStore } from '../../../stores/Global'
import { useItemStore } from '../../../stores/Items'
import Parser from '../../../lib/parser'
const store = useElementStore()
const globalStore = useGlobalStore()
const itemStore = useItemStore()
function onDrop(event: DragEvent) {
if(store.dragMode == "insert") {
if(globalStore.dragMode == "insert") {
const itemType = Number(event.dataTransfer?.getData('itemId'));
store.addElement(Parser.getModelForType(itemType))
store.clearSelection()
itemStore.addElement(Parser.getModelForType(itemType))
}
}
</script>
<template>
<div class="border m-1 p-4 rounded-xl w-full h-full shadow bg-white" @drop="onDrop($event)" @dragover.prevent>
<RenderElements v-bind:items="store.getItems" />
<RenderElements v-bind:items="itemStore.getItems" />
</div>
</template>

View File

@ -1,9 +1,7 @@
<script lang="ts" setup>
import SelectElement from '../../../model/SelectElement';
import Option from '../../../model/select/Option';
import { computed } from 'vue';
import { Input } from '../../../components/ui/input'
import { Button } from '../../../components/ui/button'
import {
Select,
SelectContent,
@ -12,18 +10,6 @@ import {
SelectTrigger,
SelectValue,
} from '../../../components/ui/select'
import OptionElement from './OptionElement.vue'
import {
Dialog,
DialogContent,
DialogClose,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '../../../components/ui/dialog'
import { ref, watch } from 'vue'
const props = defineProps<{
modelValue: SelectElement

View File

@ -1,19 +1,11 @@
<script lang="ts" setup>
import { useElementStore } from '../../../stores/Items'
import { useGlobalStore } from '../../../stores/Global'
import SelectElement from '../../../model/SelectElement';
import Option from '../../../model/select/Option';
import { computed } from 'vue';
import { Input } from '../../../components/ui/input'
import { Button } from '../../../components/ui/button'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from '../../../components/ui/select'
import OptionElement from './OptionElement.vue'
import { ref, watch } from 'vue'
import {
Dialog,
DialogContent,
@ -24,7 +16,6 @@ import {
DialogTitle,
DialogTrigger,
} from '../../../components/ui/dialog'
import { ref, watch } from 'vue'
const props = defineProps<{
modelValue: SelectElement
@ -42,24 +33,24 @@ const theModel = computed<SelectElement>({
function addOption(obj: SelectElement) {
obj.addOption(new Option(String(obj.options.length + 1)));
}
const store = useElementStore()
const globalStore = useGlobalStore()
store.$subscribe((mutation, state) => {
globalStore.$subscribe((mutation, state) => {
if(state.showOptions) {
openModal.value = true
}
}, true)
}, { detached: true})
watch(openModal, (newOpenModal) => {
watch(openModal, (newOpenModal: boolean) => {
if(newOpenModal === false) {
store.setShowOptions(false)
globalStore.setShowOptions(false)
}
})
</script>
<template>
<Dialog v-if="store.getActiveItem.type === 3" v-model:open="openModal">
<Dialog v-if="globalStore.getActiveItem.type === 3" v-model:open="openModal">
<DialogTrigger>
<Button class="mt-2">{{ $t('edit_options') }}</Button>
</DialogTrigger>

View File

@ -16,7 +16,8 @@ import HeadlineElement from '../../../model/HeadlineElement'
import MediaElement from '../../../model/MediaElement'
import Row from '../../../model/Row'
import SelectElement from '../../../model/SelectElement'
import { useElementStore } from '../../../stores/Items'
import { useItemStore } from '../../../stores/Items'
import { useGlobalStore } from '../../../stores/Global'
import Parser from '../../../lib/parser'
import { Settings, Trash, CirclePlus, List, Option } from 'lucide-vue-next';
import { ref } from 'vue'
@ -27,12 +28,15 @@ interface Props {
defineProps<Props>()
const store = useElementStore()
const itemStore = useItemStore()
const globalStore = useGlobalStore()
const dragUuid = ref("")
let isPreview = ref(false)
store.$subscribe((mutation, state) => {
isPreview.value = globalStore.showPreview
globalStore.$subscribe((mutation, state) => {
if(state.showPreview) {
isPreview.value = true
}else{
@ -44,8 +48,8 @@ const startDrag = (event: DragEvent, uuid: string) => {
event.dataTransfer!.dropEffect = 'move'
event.dataTransfer!.effectAllowed = 'move'
event.dataTransfer?.setData('mode', "sort")
store.setDragMode("sort")
store.setSourceDragUuid(uuid)
globalStore.setDragMode("sort")
globalStore.setSourceDragUuid(uuid)
event.stopImmediatePropagation()
}
@ -56,7 +60,7 @@ const dragLeave = (event: DragEvent, uuid: string) => {
const dragEnter = (event: DragEvent, uuid: string) => {
dragUuid.value = uuid
if(store.getDragMode == "sort" && uuid != store.getSourceDragUuid) {
if(globalStore.getDragMode == "sort" && uuid != globalStore.getSourceDragUuid) {
event.stopImmediatePropagation()
}
}
@ -64,38 +68,37 @@ const dragEnter = (event: DragEvent, uuid: string) => {
const stopDrag = (event: DragEvent, uuid: string) => {
if(event.dataTransfer?.getData('mode') == "sort") {
dragUuid.value = ""
if(store.getSourceDragUuid == uuid) {
store.setDragMode("")
if(globalStore.getSourceDragUuid == uuid) {
globalStore.setDragMode("")
event.stopImmediatePropagation()
return
}
store.moveItemBefore(store.getSourceDragUuid, uuid)
store.setDragMode("")
itemStore.moveItemBefore(globalStore.getSourceDragUuid, uuid)
globalStore.setDragMode("")
event.stopImmediatePropagation()
}
if(store.dragMode == "insert") {
if(globalStore.dragMode == "insert") {
const itemType = Number(event.dataTransfer?.getData('itemId'))
store.addElementAfter(Parser.getModelForType(itemType), uuid)
store.clearSelection()
itemStore.addElementAfter(Parser.getModelForType(itemType), uuid)
event.stopImmediatePropagation()
}
}
const deleteItem = (item: BaseElement) => {
store.deleteItem(item)
itemStore.deleteItem(item)
}
const editElementProperties = (item: BaseElement) => {
store.setActiveItem(item)
store.setShowProperties(true)
globalStore.setActiveItem(item)
globalStore.setShowProperties(true)
}
const editOptions = (item: BaseElement) => {
store.setActiveItem(item)
store.setShowOptions(true)
globalStore.setActiveItem(item)
globalStore.setShowOptions(true)
}
const editElementDependency = (item: BaseElement) => {
store.setActiveItem(item)
store.setShowDependency(true)
globalStore.setActiveItem(item)
globalStore.setShowDependency(true)
}
</script>

View File

@ -3,8 +3,7 @@ import type { TabsRootEmits, TabsRootProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { TabsRoot, useForwardPropsEmits } from 'reka-ui'
import { cn } from '@/lib/utils'
import { cn } from '../../../lib/utils'
const props = defineProps<TabsRootProps & { class?: HTMLAttributes['class'] }>()
const emits = defineEmits<TabsRootEmits>()

View File

@ -2,7 +2,7 @@
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { TabsContent, type TabsContentProps } from 'reka-ui'
import { cn } from '@/lib/utils'
import { cn } from '../../../lib/utils'
const props = defineProps<TabsContentProps & { class?: HTMLAttributes['class'] }>()

View File

@ -2,7 +2,7 @@
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { TabsList, type TabsListProps } from 'reka-ui'
import { cn } from '@/lib/utils'
import { cn } from '../../../lib/utils'
const props = defineProps<TabsListProps & { class?: HTMLAttributes['class'] }>()

View File

@ -2,7 +2,7 @@
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { TabsTrigger, type TabsTriggerProps, useForwardProps } from 'reka-ui'
import { cn } from '@/lib/utils'
import { cn } from '../../../lib/utils'
const props = defineProps<TabsTriggerProps & { class?: HTMLAttributes['class'] }>()

View File

@ -40,5 +40,7 @@
"close": "Schließen",
"dependencies": "Abhängigkeiten",
"options": "Optionen",
"settings": "Einstellungen"
"settings": "Einstellungen",
"save": "Speichern",
"saving": "Speichern..."
}

View File

@ -40,5 +40,7 @@
"close": "Close",
"dependencies": "Dependencies",
"options": "Options",
"settings": "Settings"
"settings": "Settings",
"save": "Save",
"saving": "Saving..."
}

View File

@ -1,7 +1,7 @@
import ky from 'ky';
const api = ky.create({
prefixUrl: 'apps',
prefixUrl: '/apps',
headers: {
'Content-Type': 'application/json',
},
@ -40,5 +40,34 @@ export const loadPriceFromApi = async (uuid: string) => {
}
};
export const saveDesignToApi = async (uuid: string, json: object[]) => {
try {
const response = await api.post('api/plugin/system/psc/xmlcalc/product/design', { json: { product: uuid, jsonProduct: json } });
return await response.json();
} catch (error) {
console.error('Error saving design to API:', error);
throw error;
}
}
export const saveXmlToApi = async (uuid: string, xml: string) => {
try {
const response = await api.post('api/plugin/system/psc/xmlcalc/product/xml', { json: { product: uuid, xml: xml } });
return await response.json();
} catch (error) {
console.error('Error saving design to API:', error);
throw error;
}
}
export const saveJsonToApi = async (uuid: string, json: string) => {
try {
const response = await api.post('api/plugin/system/psc/xmlcalc/product/json', { json: { product: uuid, json: json } });
return await response.json();
} catch (error) {
console.error('Error saving design to API:', error);
throw error;
}
};
export default api;

View File

@ -18,8 +18,8 @@ export default class SelectElement extends BaseElement {
}
hasDependencys() {
let hasDep = this.options.reduce((result: bool, opt: Option) => {
if(opt.dependencys.length > 0) {
let hasDep = this.options.reduce((result: boolean, opt: Option) => {
if (opt.dependencys.length > 0) {
result = true
}
return result

View File

@ -0,0 +1,157 @@
import { defineStore } from 'pinia'
import BaseElement from '../model/BaseElement'
import { loadJsonFromApi, loadPriceFromApi, saveDesignToApi, saveJsonToApi, saveXmlToApi } from '../lib/api'
import { useItemStore } from './Items'
export const useGlobalStore = defineStore('global', {
state: () => ({
activeItem: {} as BaseElement | {},
formulaData: [],
formulaError: '',
productUuid: '',
isFormulaLoading: false,
showProperties: false,
showDependency: false,
showOptions: false,
showPreview: false,
sourceDragUuid: "",
dragMode: "",
json: "",
xml: "",
formel: "",
paperdb: "",
parameter: "",
saving: false,
syncing: false,
currentTab: 'designer',
}),
getters: {
getActiveItem: (state) => state.activeItem as BaseElement,
isShowPropierties: (state) => state.showProperties,
isShowDependency: (state) => state.showDependency,
isShowOptions: (state) => state.showOptions,
isShowPreview: (state) => state.showPreview,
getSourceDragUuid: (state) => state.sourceDragUuid,
getDragMode: (state) => state.dragMode,
getFormulaData: (state) => state.formulaData,
getFormulaError: (state) => state.formulaError,
},
actions: {
setXml(value: string) {
this.xml = value
},
setFormel(value: string) {
this.formel = value
},
setPaperDB(value: string) {
this.paperdb = value
},
setParameter(value: string) {
this.parameter = value
},
setJson(value: string) {
this.json = value
},
setShowDependency(value: boolean) {
this.showDependency = value
},
setShowOptions(value: boolean) {
this.showOptions = value
},
setShowProperties(value: boolean) {
this.showProperties = value
},
setProductUuid(value: string) {
this.productUuid = value
},
setShowPreview(value: boolean) {
this.showPreview = value
},
setActiveItem(item: BaseElement) {
this.activeItem = item
},
setSourceDragUuid(uuid: string) {
this.sourceDragUuid = uuid
},
setDragMode(mode: string) {
this.dragMode = mode
},
async loadConfigFromProductApi(uuid: string) {
const data: any = await loadJsonFromApi(uuid)
this.json = data.json
this.xml = data.xml
return data.json;
},
async loadFormulaAnalyserDataFromApi(uuid: string) {
if (this.formulaData && this.formulaData.length > 0) {
return;
}
this.isFormulaLoading = true;
this.formulaError = '';
try {
const response: any = await loadPriceFromApi(uuid);
if (response && response.debug && response.debug.graphJson) {
this.formulaData = JSON.parse(response.debug.graphJson);
} else {
throw new Error('Invalid or empty response format from API.');
}
} catch (e: any) {
this.formulaError = `Failed to load formula data: ${e.message}`;
console.error(e);
} finally {
this.isFormulaLoading = false;
}
},
setXML(xml: string) {
this.xml = xml
},
setJSON(json: string) {
this.json = json
},
saveDesign(json: object[]) {
saveDesignToApi(this.productUuid, json).then((result: any) => {
this.setXML(result.xml)
this.setJSON(result.json)
this.formulaData = JSON.parse(result.jsonGraph);
})
},
manualSave(json: object[]) {
this.saving = true
saveDesignToApi(this.productUuid, json).then((result: any) => {
this.setXML(result.xml)
this.setJSON(result.json)
this.formulaData = JSON.parse(result.jsonGraph);
const itemStore = useItemStore()
itemStore.parseJSON(result.json)
this.saving = false
})
},
manualSync() {
this.syncing = true
if (this.currentTab == 'xml') {
saveXmlToApi(this.productUuid, this.xml).then((result: any) => {
this.setXML(result.xml)
this.setJSON(result.json)
this.formulaData = JSON.parse(result.jsonGraph);
this.syncing = false
const itemStore = useItemStore()
itemStore.parseJSON(result.json)
})
}
if (this.currentTab == 'json') {
saveJsonToApi(this.productUuid, this.json).then((result: any) => {
this.setXML(result.xml)
this.setJSON(result.json)
this.formulaData = JSON.parse(result.jsonGraph);
this.syncing = false
const itemStore = useItemStore()
itemStore.parseJSON(result.json)
})
}
},
setCurrentTab(tab: string) {
this.currentTab = tab
}
}
})

View File

@ -1,63 +1,37 @@
import { defineStore } from 'pinia'
import BaseElement from '../model/BaseElement'
import Parser from '../lib/parser'
import {v4 as uuidv4} from 'uuid'
import { loadJsonFromApi, loadPriceFromApi } from '../lib/api'
import { v4 as uuidv4 } from 'uuid'
export const useElementStore = defineStore('items', {
export const useItemStore = defineStore('items', {
state: () => ({
uuid: uuidv4(),
items: [] as BaseElement[],
activeItem: {} as BaseElement | {},
formulaData: [],
formulaError: '',
isFormulaLoading: false,
showProperties: false,
showDependency: false,
showOptions: false,
showPreview: false,
sourceDragUuid: "",
dragMode: "",
json: "",
xml: "",
name: uuidv4(),
}),
getters: {
getCount: (state) => state.items.length,
getItems: (state) => state.items,
getActiveItem: (state) => state.activeItem as BaseElement,
isShowPropierties: (state) => state.showProperties,
isShowDependency: (state) => state.showDependency,
isShowOptions: (state) => state.showOptions,
isShowPreview: (state) => state.showPreview,
getSourceDragUuid: (state) => state.sourceDragUuid,
getDragMode: (state) => state.dragMode,
getFormulaData: (state) => state.formulaData,
getUuid: (state) => state.uuid,
},
actions: {
addElement(item: BaseElement) {
this.items.push(item)
},
loadJSON() {
let options: object[] = this.items.reduce((result: object[], opt: BaseElement) => {
result.push(opt.toJSON())
return result
}, [])
this.json = JSON.stringify([{
return [{
uuid: this.uuid,
name: this.name,
options: options
}])
}]
},
parseJSON() {
parseJSON(json: string) {
this.items = []
let obj = JSON.parse(this.json)
let obj = JSON.parse(json)
this.name = obj[0].name
if(obj[0].uuid) {
if (obj[0].uuid) {
this.uuid = obj[0].uuid
}
obj[0].options.map((ob: any) => {
@ -66,46 +40,23 @@ export const useElementStore = defineStore('items', {
this.addElement(item)
})
},
changeFocus(uuid: string) {
this.items.forEach((element: BaseElement) => {
element.changeFocus(uuid)
})
},
clearSelection() {
this.items.forEach((element: BaseElement) => {
element.changeFocus("xx")
})
this.showProperties = false
},
setShowDependency(value: boolean) {
this.showDependency = value
},
setShowOptions(value: boolean) {
this.showOptions = value
},
setShowProperties(value: boolean) {
this.showProperties = value
},
setShowPreview(value: boolean) {
this.showPreview = value
},
setActiveItem(item: BaseElement) {
this.activeItem = item
addElement(item: BaseElement) {
this.items.push(item)
},
deleteItem(item: BaseElement): boolean {
return this.items.some((element: BaseElement,indexArray: number) => {
if(element.uuid === item.uuid) {
return this.items.some((element: BaseElement, indexArray: number) => {
if (element.uuid === item.uuid) {
item = this.items.splice(indexArray, 1)[0]
return true
}
if(element.deleteItem(item)) {
if (element.deleteItem(item)) {
return true
}
})
},
moveItemBefore(dragUuid: string, targetUuid: string): boolean {
const item = this.cutItem(dragUuid)
if(item) {
if (item) {
return this.insertItem(this.items, item, targetUuid)
}
return false
@ -113,19 +64,16 @@ export const useElementStore = defineStore('items', {
addElementAfter(item: BaseElement, targetUuid: string) {
this.insertItem(this.items, item, targetUuid)
},
setSourceDragUuid(uuid: string) {
this.sourceDragUuid = uuid
},
cutItem(existingUuid: string) {
let item: BaseElement|null = null
this.items.some((element: BaseElement,indexArray: number) => {
if(element.uuid === existingUuid) {
let item: BaseElement | null = null
this.items.some((element: BaseElement, indexArray: number) => {
if (element.uuid === existingUuid) {
item = this.items.splice(indexArray, 1)[0]
return true
}
if(item === null) {
if (item === null) {
item = element.cutItem(existingUuid)
if(item !== null) {
if (item !== null) {
return true
}
}
@ -135,47 +83,17 @@ export const useElementStore = defineStore('items', {
insertItem(items: BaseElement[], item: BaseElement, targetUuid: string): boolean {
let inserted = false
for (let i = 0; i < items.length; ++i) {
if(items[i].uuid === targetUuid) {
if (items[i].uuid === targetUuid) {
items.splice(i, 0, item)
inserted = true
break
}
if(!inserted) {
if (!inserted) {
inserted = items[i].insertItem(item, targetUuid)
}
}
return inserted
},
setDragMode(mode: string) {
this.dragMode = mode
},
async loadConfigFromProductApi(uuid: string) {
const data = await loadJsonFromApi(uuid);
this.json = data.json;
this.xml = data.xml;
this.parseJSON();
},
async loadFormulaAnalyserDataFromApi(uuid: string) {
if (this.formulaData && this.formulaData.length > 0) {
return;
}
this.isFormulaLoading = true;
this.formulaError = '';
try {
const response = await loadPriceFromApi(uuid);
if (response && response.debug && response.debug.graphJson) {
this.formulaData = JSON.parse(response.debug.graphJson);
} else {
throw new Error('Invalid or empty response format from API.');
}
} catch (e: any) {
this.formulaError = `Failed to load formula data: ${e.message}`;
console.error(e);
} finally {
this.isFormulaLoading = false;
}
}
}
})

View File

@ -27,9 +27,9 @@ export default defineConfig({
'/apps': {
target: 'http://type-dev-tp.local',
changeOrigin: true,
configure: (proxy, options) => {
proxy.on('proxyReq', (proxyReq, req, res) => {
proxyReq.setHeader('Authorization', 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE3NTI1Nzc2NzIsImV4cCI6MTc1MjU4MTI3Miwicm9sZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfU0hPUF9PUEVSQVRPUiIsIlJPTEVfVVNFUiIsIlJPTEVfVVNFUiIsIlJPTEVfUFNDX0NvbGxlY3RfQ29udGFjdF9FZGl0IiwiUk9MRV9QU0NfQ29sbGVjdF9Db250YWN0X0FkZCIsIlJPTEVfUFNDX0NvbGxlY3RfQ29udGFjdF9EZWxldGUiLCJST0xFX1BTQ19Db2xsZWN0X0NvbnRhY3RfTG9jayIsIlJPTEVfUFNDX1IyX1NlbmRjbG91ZF9TaG93Il0sInVpZCI6MX0.ViKfV_6cSsP6UvqibTJ5zXE8F5JZWmOEhNquw5_3bpB5N7rOtTIM8ZaD5i9VfoRf2a1CaSIKAzhte_8K49bNIpMd4B8mh3ufqUIHn33L34TsiTNblKv4PlQB_FZbCgujzfP2UenrDi3SAsHd5bynZUOJNbkGzMtv2sUot-mrKJmUvchl-yvcSFw4bYfy-88hnfXJ6sCDlIU-Vd9OSChoBqD12z3Nr6fEqY-ngq7Xv315yFY9Fhg3gxu5NqyAMzN-F6QJHjUsHlo2b9oLeAo2nFZ_Cj2nAMVa6VbxAXMrj6Ogf2POr1TWtvBBaJZj4c1D5rWktkFkPLTUAStNOwMRvQ');
configure: (proxy) => {
proxy.on('proxyReq', (proxyReq) => {
proxyReq.setHeader('Authorization', 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE3NTMxMDgzOTMsImV4cCI6MTc1MzExMTk5Mywicm9sZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfU0hPUF9PUEVSQVRPUiIsIlJPTEVfVVNFUiIsIlJPTEVfVVNFUiIsIlJPTEVfUFNDX0NvbGxlY3RfQ29udGFjdF9FZGl0IiwiUk9MRV9QU0NfQ29sbGVjdF9Db250YWN0X0FkZCIsIlJPTEVfUFNDX0NvbGxlY3RfQ29udGFjdF9EZWxldGUiLCJST0xFX1BTQ19Db2xsZWN0X0NvbnRhY3RfTG9jayIsIlJPTEVfUFNDX1IyX1NlbmRjbG91ZF9TaG93Il0sInVpZCI6MX0.BsoNxbHgk_B-_72aYyItK199n1UoKkqhvMLRxNCMdLn18c4MDegZgpLB46kQ2kafNCoIvLEWzmTDBsFXTwRizUyyWWd6qORb6J2YNdM5t5r_qKEQKeaFDTkULGKmMwmu51MrleYr0lxbW18SqQKV2M88Y_qr-NvYeC-Pkwk3plqEw7qoaQQY9qQvRBfkXI90QBL5nFjgvearcdc2NMQJUWOTG9eUwz7LM-9R5CW9Wx8HUXWjM9prUiPgPrEf-amHq_gnCpqzpd8O6c2zRJ7U9nBQ9r0vI4bgFtPysKZ6QOB-ByW9oLs2Y70n0f22YNmox2SwVbMiAWMlMyGXb1TnpA');
});
},
},

File diff suppressed because one or more lines are too long

View File

@ -68,7 +68,7 @@ class Design extends AbstractController
if ($product->getShop()->getInstall()->getCalcTemplatesTest() && $data->test) {
$engine->setTemplates('<root>' . $product->getShop()->getInstall()->getCalcTemplatesTest() . '</root>');
}
$engine->loadJson($data->jsonProduct);
$engine->loadJson(json_encode($data->jsonProduct));
if (!$data->test) {
$engine->setFormulas($product->getShop()->getFormel());
$engine->setParameters($product->getShop()->getParameter());
@ -77,7 +77,7 @@ class Design extends AbstractController
$engine->setFormulas($product->getShop()->getTestFormel());
$engine->setParameters($product->getShop()->getTestParameter());
}
$engine->setVariables($data->values);
// $engine->setVariables($data->values);
$engine->setTax($product->getMwert());
if ($this->tokenStorage->getToken()) {
$contact = new Contact();
@ -85,6 +85,7 @@ class Design extends AbstractController
$engine->setVariable('contact.accountType', $contact->getAccountType()->value);
$engine->setVariable('contact.account', $contact->getAccount()->getUid());
}
$engine->calc();
return $this->json([
'json' => $engine->generateJson(),

View File

@ -0,0 +1,97 @@
<?php
namespace Plugin\System\PSC\XmlCalc\Api\Product;
use Doctrine\ODM\MongoDB\DocumentManager;
use Doctrine\ORM\EntityManagerInterface;
use Nelmio\ApiDocBundle\Annotation\Model;
use Nelmio\ApiDocBundle\Annotation\Security;
use OpenApi\Annotations as OA;
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\Routing\Attribute\Route;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
class Json extends AbstractController
{
public function __construct(
private \PSC\System\SettingsBundle\Service\Shop $shopService,
private DocumentManager $documentManager,
private PaperDB $paperDB,
private ContactTransformer $contactTransformer,
private TokenStorageInterface $tokenStorage,
private EntityManagerInterface $entityManager,
) {}
/**
* @OA\Response(
* response=200,
* description="get config for product",
* @OA\JsonContent(ref=@Model(type=\Plugin\System\PSC\XmlCalc\Model\Product::class))
* )
* @OA\RequestBody(
*
* @Model(type=\Plugin\System\PSC\XmlCalc\Dto\Input\JsonInput::class))
* )
* @OA\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)
{
$product = $this->entityManager
->getRepository('PSC\Shop\EntityBundle\Entity\Product')
->findOneBy(['uuid' => $data->product]);
$paperContainer = new PaperContainer();
$paperContainer->parse(simplexml_load_string($product->getShop()->getInstall()->getPaperContainer()));
$engine = new Engine();
$engine->setPaperRepository($this->paperDB);
$engine->setPaperContainer($paperContainer);
if ($product->getShop()->getInstall()->getCalcTemplates() && !$data->test) {
$engine->setTemplates('<root>' . $product->getShop()->getInstall()->getCalcTemplates() . '</root>');
}
if ($product->getShop()->getInstall()->getCalcTemplatesTest() && $data->test) {
$engine->setTemplates('<root>' . $product->getShop()->getInstall()->getCalcTemplatesTest() . '</root>');
}
$engine->loadJson(json_encode($data->json));
if (!$data->test) {
$engine->setFormulas($product->getShop()->getFormel());
$engine->setParameters($product->getShop()->getParameter());
}
if ($data->test) {
$engine->setFormulas($product->getShop()->getTestFormel());
$engine->setParameters($product->getShop()->getTestParameter());
}
// $engine->setVariables($data->values);
$engine->setTax($product->getMwert());
if ($this->tokenStorage->getToken()) {
$contact = new Contact();
$this->contactTransformer->fromDb($contact, $this->tokenStorage->getToken()->getUser());
$engine->setVariable('contact.accountType', $contact->getAccountType()->value);
$engine->setVariable('contact.account', $contact->getAccount()->getUid());
}
$engine->calc();
return $this->json([
'json' => $engine->generateJson(),
'xml' => $engine->generateXML(true),
'jsonGraph' => $engine->getCalcGraph()->generateJsonGraph(),
'price' => $engine->getPrice() * 100,
]);
}
}

View File

@ -0,0 +1,97 @@
<?php
namespace Plugin\System\PSC\XmlCalc\Api\Product;
use Doctrine\ODM\MongoDB\DocumentManager;
use Doctrine\ORM\EntityManagerInterface;
use Nelmio\ApiDocBundle\Annotation\Model;
use Nelmio\ApiDocBundle\Annotation\Security;
use OpenApi\Annotations as OA;
use Plugin\System\PSC\XmlCalc\Dto\Input\XMLInput;
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\Routing\Attribute\Route;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
class XML extends AbstractController
{
public function __construct(
private \PSC\System\SettingsBundle\Service\Shop $shopService,
private DocumentManager $documentManager,
private PaperDB $paperDB,
private ContactTransformer $contactTransformer,
private TokenStorageInterface $tokenStorage,
private EntityManagerInterface $entityManager,
) {}
/**
* @OA\Response(
* response=200,
* description="get config for product",
* @OA\JsonContent(ref=@Model(type=\Plugin\System\PSC\XmlCalc\Model\Product::class))
* )
* @OA\RequestBody(
*
* @Model(type=\Plugin\System\PSC\XmlCalc\Dto\Input\XML::class))
* )
* @OA\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)
{
$product = $this->entityManager
->getRepository('PSC\Shop\EntityBundle\Entity\Product')
->findOneBy(['uuid' => $data->product]);
$paperContainer = new PaperContainer();
$paperContainer->parse(simplexml_load_string($product->getShop()->getInstall()->getPaperContainer()));
$engine = new Engine();
$engine->setPaperRepository($this->paperDB);
$engine->setPaperContainer($paperContainer);
if ($product->getShop()->getInstall()->getCalcTemplates() && !$data->test) {
$engine->setTemplates('<root>' . $product->getShop()->getInstall()->getCalcTemplates() . '</root>');
}
if ($product->getShop()->getInstall()->getCalcTemplatesTest() && $data->test) {
$engine->setTemplates('<root>' . $product->getShop()->getInstall()->getCalcTemplatesTest() . '</root>');
}
$engine->loadString($data->xml);
if (!$data->test) {
$engine->setFormulas($product->getShop()->getFormel());
$engine->setParameters($product->getShop()->getParameter());
}
if ($data->test) {
$engine->setFormulas($product->getShop()->getTestFormel());
$engine->setParameters($product->getShop()->getTestParameter());
}
// $engine->setVariables($data->values);
$engine->setTax($product->getMwert());
if ($this->tokenStorage->getToken()) {
$contact = new Contact();
$this->contactTransformer->fromDb($contact, $this->tokenStorage->getToken()->getUser());
$engine->setVariable('contact.accountType', $contact->getAccountType()->value);
$engine->setVariable('contact.account', $contact->getAccount()->getUid());
}
$engine->calc();
return $this->json([
'json' => $engine->generateJson(),
'xml' => $engine->generateXML(true),
'jsonGraph' => $engine->getCalcGraph()->generateJsonGraph(),
'price' => $engine->getPrice() * 100,
]);
}
}

View File

@ -3,25 +3,26 @@
namespace Plugin\System\PSC\XmlCalc\Api\Shop;
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 as PluginShop;
use PSC\Component\ApiBundle\Dto\Error\NotFound;
use PSC\Shop\EntityBundle\Entity\Shop as PSCShop;
use PSC\System\SettingsBundle\Service\Shop;
use Plugin\System\PSC\XmlCalc\Model\Shop as PluginShop;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
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 Sensio\Bundle\FrameworkExtraBundle\Configuration\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 shop calc settings
*
@ -38,17 +39,17 @@ class One extends AbstractController {
public function one(string $uuid): 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) {
$output = new PluginShop();
$output->formel = (string)$shop->getFormel();
$output->formelTest = (string)$shop->getTestFormel();
$output->parameter = (string)$shop->getParameter();
$output->parameterTest = (string)$shop->getTestParameter();
}else{
$output = new NotFound("shop not found");
$output->formel = (string) $shop->getFormel();
$output->formelTest = (string) $shop->getTestFormel();
$output->parameter = (string) $shop->getParameter();
$output->parameterTest = (string) $shop->getTestParameter();
} else {
$output = new NotFound('shop not found');
}
return $this->json($output);
}

View File

@ -15,11 +15,11 @@ final class DesignInput
public string $product;
/**
* @var string
* @var array
*
* @OA\Property(type="string")
* @OA\Property(type="array", @OA\Items(type="array", @OA\Items()))
*/
public string $jsonProduct = '';
public array $jsonProduct = [];
/**
* @var bool

View File

@ -0,0 +1,37 @@
<?php
namespace Plugin\System\PSC\XmlCalc\Dto\Input;
use Nelmio\ApiDocBundle\Annotation\Model;
use OpenApi\Annotations as OA;
final class JsonInput
{
/**
* @var string
*
* @OA\Property(type="string")
*/
public string $product;
/**
* @var array
*
* @OA\Property(type="array", @OA\Items(type="array", @OA\Items()))
*/
public array $json = [];
/**
* @var bool
*
* @OA\Property(type="boolean")
*/
public bool $test = false;
/**
* @var array
*
* @OA\Property(type="array", @OA\Items(type="string"))
*/
public array $values = ['auflage' => 100];
}

View File

@ -0,0 +1,36 @@
<?php
namespace Plugin\System\PSC\XmlCalc\Dto\Input;
use Nelmio\ApiDocBundle\Annotation\Model;
use OpenApi\Annotations as OA;
final class XMLInput
{
/**
* @var string
*
* @OA\Property(type="string")
*/
public string $product;
/**
*
* @OA\Property(type="string")
*/
public string $xml = '';
/**
* @var bool
*
* @OA\Property(type="boolean")
*/
public bool $test = false;
/**
* @var array
*
* @OA\Property(type="array", @OA\Items(type="string"))
*/
public array $values = ['auflage' => 100];
}