before icons

This commit is contained in:
Thomas Peterson 2026-07-11 22:08:51 +02:00
parent 1647175122
commit 06cffec25a
27 changed files with 145 additions and 57 deletions

View File

@ -0,0 +1 @@
{"pid":2966987,"startedAt":1783596410229}

View File

@ -122,7 +122,7 @@ ordernumber: Auftragsnummer
createdat: Erzeugt createdat: Erzeugt
name: Name name: Name
wkpos1: WK/Pos 1 wkpos1: WK/Pos 1
wkpos2: WK/Pos 2 wkpos2: WK/Pos 2 (für XRechnung BT-13)
grossprice: Preis Brutto grossprice: Preis Brutto
status: Status status: Status
details: Details details: Details

View File

@ -116,7 +116,7 @@ ordernumber: Order Number
createdat: Created at createdat: Created at
name: Name name: Name
wkpos1: WK/Pos 1 wkpos1: WK/Pos 1
wkpos2: WK/Pos 2 wkpos2: WK/Pos 2 (for XRechnung BT-13)
grossprice: Gross Price grossprice: Gross Price
status: Status status: Status
details: Details details: Details

View File

@ -12,13 +12,13 @@ street: Straße
EMail: EMail EMail: EMail
company: Firma company: Firma
wkpos1: WK_Pos_1 wkpos1: WK_Pos_1
wkpos2: WK_Pos_2 wkpos2: WK_Pos_2 (für XRechnung BT-13)
orderdate: Auftragsdatum orderdate: Auftragsdatum
paymentmethod: Zahlart paymentmethod: Zahlart
payment: Zahlung Gateway (Ref) payment: Zahlung Gateway (Ref)
shippingmethod: Versandart shippingmethod: Versandart
shoppingcartfield1: Warenkorbfeld 1 shoppingcartfield1: Warenkorbfeld 1
shoppingcartfield2: Warenkorbfeld 2 shoppingcartfield2: Warenkorbfeld 2 (für XRechnung BT-13)
coupon: Gutschein (Code) coupon: Gutschein (Code)
weight: Gewicht weight: Gewicht
paymentCost: Zahlartkosten paymentCost: Zahlartkosten

View File

@ -12,13 +12,13 @@ street: Street
EMail: E-Mail EMail: E-Mail
company: Company company: Company
wkpos1: WK/Pos 1 wkpos1: WK/Pos 1
wkpos2: WK/Pos 2 wkpos2: WK/Pos 2 (for XRechnung BT-13)
orderdate: Order Date orderdate: Order Date
paymentmethod: Payment Method paymentmethod: Payment Method
payment: Payment (Ref) payment: Payment (Ref)
shippingmethod: Shipping Method shippingmethod: Shipping Method
shoppingcartfield1: Shopping Cart Field 1 shoppingcartfield1: Shopping Cart Field 1
shoppingcartfield2: Shopping Cart Field 2 shoppingcartfield2: Shopping Cart Field 2 (for XRechnung BT-13)
coupon: Coupon coupon: Coupon
Packageexported: Package exported Packageexported: Package exported
packagenumber: Package Number packagenumber: Package Number

View File

@ -7,7 +7,7 @@ Name: Username/Login
firstname: Vorname firstname: Vorname
lastname: Nachname lastname: Nachname
wkpos1: WK/Pos 1 wkpos1: WK/Pos 1
wkpos2: WK/Pos 2 wkpos2: WK/Pos 2 (für XRechnung BT-13)
grossprice: Preis Netto (Brutto) grossprice: Preis Netto (Brutto)
status: Status status: Status
details: Details details: Details

View File

@ -7,7 +7,7 @@ Name: Username/Login
firstname: First Name firstname: First Name
lastname: Last Name lastname: Last Name
wkpos1: WK/Pos 1 wkpos1: WK/Pos 1
wkpos2: WK/Pos 2 wkpos2: WK/Pos 2 (for XRechnung BT-13)
grossprice: Gross Price grossprice: Gross Price
status: Status status: Status
details: Details details: Details

View File

@ -147,8 +147,8 @@
</div> </div>
</div> </div>
<div class="flex gap-1.5 justify-end"> <div class="flex gap-1.5 justify-end">
{# Download - GRÜN #} {# Download - ORANGE #}
<a href="{{ path("psc_shop_order_backend_detail_package_download", {uuid: order.uuid}) }}" target="_blank" title="Package Download" class="inline-flex items-center justify-center gap-1 px-2.5 py-1.5 rounded-md text-xs font-medium text-white bg-green-600 hover:bg-green-700 transition-colors shadow-sm"> <a href="{{ path("psc_shop_order_backend_detail_package_download", {uuid: order.uuid}) }}" target="_blank" title="Package Download" class="inline-flex items-center justify-center gap-1 px-2.5 py-1.5 rounded-md text-xs font-medium text-white bg-orange-500 hover:bg-orange-600 transition-colors shadow-sm">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" /> <path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" />
</svg> </svg>
@ -157,8 +157,8 @@
{% for customListButton in customListButtons %} {% for customListButton in customListButtons %}
{{ customListButton.render(orderObj)|raw }} {{ customListButton.render(orderObj)|raw }}
{% endfor %} {% endfor %}
{# Details - BLAU #} {# Details - GRÜN #}
<a href="{{ path("psc_shop_order_backend_detail_show", {uuid: order.uuid}) }}" title="Details anzeigen" class="inline-flex items-center justify-center gap-1 px-2.5 py-1.5 rounded-md text-xs font-medium text-white bg-blue-600 hover:bg-blue-700 transition-colors shadow-sm"> <a href="{{ path("psc_shop_order_backend_detail_show", {uuid: order.uuid}) }}" title="Details anzeigen" class="inline-flex items-center justify-center gap-1 px-2.5 py-1.5 rounded-md text-xs font-medium text-white bg-green-600 hover:bg-green-700 transition-colors shadow-sm">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" /> <path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" />
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /> <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />

View File

@ -107,7 +107,7 @@ ordernumber: Auftragsnummer
createdat: Erzeugt createdat: Erzeugt
name: Name name: Name
wkpos1: WK/Pos 1 wkpos1: WK/Pos 1
wkpos2: WK/Pos 2 wkpos2: WK/Pos 2 (für XRechnung BT-13)
grossprice: Preis Brutto grossprice: Preis Brutto
status: Status status: Status
details: Details details: Details

View File

@ -105,7 +105,7 @@ ordernumber: Order Number
createdat: Created at createdat: Created at
name: Name name: Name
wkpos1: WK/Pos 1 wkpos1: WK/Pos 1
wkpos2: WK/Pos 2 wkpos2: WK/Pos 2 (for XRechnung BT-13)
grossprice: Gross Price grossprice: Gross Price
status: Status status: Status
details: Details details: Details

View File

@ -67,7 +67,7 @@ class SettingsController extends AbstractController
$form = $this->createForm(SettingsType::class, $instance); $form = $this->createForm(SettingsType::class, $instance);
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
if ($instance->getSmtpPassword() == "") { if (empty($instance->getSmtpPassword())) {
$instance->setSmtpPassword($password); $instance->setSmtpPassword($password);
} }
$documentManager->persist($instance); $documentManager->persist($instance);

View File

@ -21,7 +21,6 @@ use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\NumberType; use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\TextType;
@ -87,7 +86,11 @@ class SettingsType extends AbstractType
->add('smtpPort', NumberType::class, ['required' => false, 'label' => 'Port']) ->add('smtpPort', NumberType::class, ['required' => false, 'label' => 'Port'])
->add('smtpHost', TextType::class, ['required' => false, 'label' => 'Host']) ->add('smtpHost', TextType::class, ['required' => false, 'label' => 'Host'])
->add('smtpUsername', TextType::class, ['required' => false, 'label' => 'Username']) ->add('smtpUsername', TextType::class, ['required' => false, 'label' => 'Username'])
->add('smtpPassword', PasswordType::class, ['required' => false, 'label' => 'Password']) ->add('smtpPassword', TextType::class, [
'required' => false,
'label' => 'Password',
'attr' => ['type' => 'password', 'autocomplete' => 'new-password'],
])
->add('smtpSenderEmail', TextType::class, ['required' => false, 'label' => 'Absender E-Mail']) ->add('smtpSenderEmail', TextType::class, ['required' => false, 'label' => 'Absender E-Mail'])
->add('smtpSenderName', TextType::class, ['required' => false, 'label' => 'Absender Name']) ->add('smtpSenderName', TextType::class, ['required' => false, 'label' => 'Absender Name'])
->add('extraSettings', TextareaType::class, ['required' => false, 'label' => 'Extra Einstellungen']) ->add('extraSettings', TextareaType::class, ['required' => false, 'label' => 'Extra Einstellungen'])

View File

@ -100,7 +100,7 @@
{{ form_label(form.smtpPassword) }} {{ form_label(form.smtpPassword) }}
<div class="relative" data-pw-wrap> <div class="relative" data-pw-wrap>
{{ form_widget(form.smtpPassword, {'attr': {'style': 'padding-right:2.5rem'}}) }} {{ form_widget(form.smtpPassword, {'attr': {'style': 'padding-right:2.5rem'}}) }}
<button type="button" data-pw-toggle class="absolute inset-y-0 right-0 flex items-center pr-3 text-gray-400 hover:text-gray-600" title="Passwort anzeigen/verbergen"> <button type="button" onclick="togglePw(this)" class="absolute inset-y-0 right-0 flex items-center pr-3 text-gray-400 hover:text-gray-600" title="Passwort anzeigen/verbergen">
<svg data-pw-eye xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" /><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" /></svg> <svg data-pw-eye xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" /><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" /></svg>
<svg data-pw-eye xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 hidden"><path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88" /></svg> <svg data-pw-eye xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 hidden"><path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88" /></svg>
</button> </button>
@ -154,7 +154,7 @@
<dd class="text-gray-800 flex items-center gap-2"> <dd class="text-gray-800 flex items-center gap-2">
<span data-pw-mask class="font-mono tracking-widest">••••••••••</span> <span data-pw-mask class="font-mono tracking-widest">••••••••••</span>
<span data-pw-mask class="hidden break-all">{{ instance.ftpPassword }}</span> <span data-pw-mask class="hidden break-all">{{ instance.ftpPassword }}</span>
<button type="button" data-pw-toggle class="text-gray-400 hover:text-gray-600" title="Passwort anzeigen/verbergen"> <button type="button" onclick="togglePw(this)" class="text-gray-400 hover:text-gray-600" title="Passwort anzeigen/verbergen">
<svg data-pw-eye xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" /><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" /></svg> <svg data-pw-eye xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" /><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" /></svg>
<svg data-pw-eye xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 hidden"><path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88" /></svg> <svg data-pw-eye xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 hidden"><path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88" /></svg>
</button> </button>
@ -287,6 +287,40 @@
} }
}); });
</script> </script>
<script>
// Passwort-Feld: standardmäßig verbergen
window.addEventListener("load", () => {
document.querySelectorAll('[data-pw-wrap]').forEach((wrap) => {
const input = wrap.querySelector('input[name*="smtpPassword"]');
if (input) {
input.setAttribute('type', 'password');
}
});
});
function togglePw(btn) {
const wrap = btn.closest('[data-pw-wrap]');
if (!wrap) return;
// Input-Feld togglen (SMTP)
const input = wrap.querySelector('input');
if (input) {
input.setAttribute('type', input.getAttribute('type') === 'password' ? 'text' : 'password');
}
// data-pw-mask Spans togglen nur im selben Elternelement wie der Button
const parent = btn.parentElement;
const masks = parent.querySelectorAll('[data-pw-mask]');
if (masks.length >= 2) {
masks.forEach((el) => el.classList.toggle('hidden'));
}
// Auge-Icon togglen
wrap.querySelectorAll('[data-pw-eye]').forEach((svg) => {
svg.classList.toggle('hidden');
});
}
</script>
<script> <script>
// SMTP-Test nutzt nur GESPEICHERTE Einstellungen. Hat der Benutzer im // SMTP-Test nutzt nur GESPEICHERTE Einstellungen. Hat der Benutzer im
// Formular etwas geändert ohne zu speichern, fangen wir den Test-Klick ab. // Formular etwas geändert ohne zu speichern, fangen wir den Test-Klick ab.

View File

@ -77,6 +77,7 @@ class Printing
->setDocumentBuyer($orderModel->getInvoiceAddress()->getCompany() . ' ' . $orderModel->getInvoiceAddress()->getFirstname() . ' ' . $orderModel->getInvoiceAddress()->getLastname(), $orderModel->getInvoiceAddress()->getKundenNr()) ->setDocumentBuyer($orderModel->getInvoiceAddress()->getCompany() . ' ' . $orderModel->getInvoiceAddress()->getFirstname() . ' ' . $orderModel->getInvoiceAddress()->getLastname(), $orderModel->getInvoiceAddress()->getKundenNr())
->setDocumentBuyerAddress($orderModel->getInvoiceAddress()->getStreet() . ' ' . $orderModel->getInvoiceAddress()->getHouseNumber(), "", "", $orderModel->getInvoiceAddress()->getZip(), $orderModel->getInvoiceAddress()->getCity(), $orderModel->getInvoiceAddress()->getCountry() ?? 'DE') ->setDocumentBuyerAddress($orderModel->getInvoiceAddress()->getStreet() . ' ' . $orderModel->getInvoiceAddress()->getHouseNumber(), "", "", $orderModel->getInvoiceAddress()->getZip(), $orderModel->getInvoiceAddress()->getCity(), $orderModel->getInvoiceAddress()->getCountry() ?? 'DE')
->setDocumentBuyerCommunication("EM", $orderModel->getInvoiceAddress()->getEmail()) ->setDocumentBuyerCommunication("EM", $orderModel->getInvoiceAddress()->getEmail())
->setDocumentBuyerOrderReferencedDocument($orderModel->getBasketfield2())
->addDocumentPaymentTermXRechnung($orderModel->getPayment()->getTitle(), [], [], [], null, null) ->addDocumentPaymentTermXRechnung($orderModel->getPayment()->getTitle(), [], [], [], null, null)
->addDocumentPaymentMean(ZugferdPaymentMeans::UNTDID_4461_58, null, null, null, null, null, $orderModel->getOperator()->getIban(), null, null, null) ->addDocumentPaymentMean(ZugferdPaymentMeans::UNTDID_4461_58, null, null, null, null, null, $orderModel->getOperator()->getIban(), null, null, null)
@ -294,6 +295,7 @@ class Printing
->setDocumentBuyer($orderModel->getInvoiceAddress()->getCompany() . ' ' . $orderModel->getInvoiceAddress()->getFirstname() . ' ' . $orderModel->getInvoiceAddress()->getLastname(), $orderModel->getInvoiceAddress()->getKundenNr()) ->setDocumentBuyer($orderModel->getInvoiceAddress()->getCompany() . ' ' . $orderModel->getInvoiceAddress()->getFirstname() . ' ' . $orderModel->getInvoiceAddress()->getLastname(), $orderModel->getInvoiceAddress()->getKundenNr())
->setDocumentBuyerAddress($orderModel->getInvoiceAddress()->getStreet() . ' ' . $orderModel->getInvoiceAddress()->getHouseNumber(), "", "", $orderModel->getInvoiceAddress()->getZip(), $orderModel->getInvoiceAddress()->getCity(), $orderModel->getInvoiceAddress()->getCountry() ?? 'DE') ->setDocumentBuyerAddress($orderModel->getInvoiceAddress()->getStreet() . ' ' . $orderModel->getInvoiceAddress()->getHouseNumber(), "", "", $orderModel->getInvoiceAddress()->getZip(), $orderModel->getInvoiceAddress()->getCity(), $orderModel->getInvoiceAddress()->getCountry() ?? 'DE')
->setDocumentBuyerCommunication("EM", $orderModel->getInvoiceAddress()->getEmail()) ->setDocumentBuyerCommunication("EM", $orderModel->getInvoiceAddress()->getEmail())
->setDocumentBuyerOrderReferencedDocument($orderModel->getBasketfield2())
->addDocumentPaymentTermXRechnung($orderModel->getPayment()->getTitle(), [], [], [], null, null) ->addDocumentPaymentTermXRechnung($orderModel->getPayment()->getTitle(), [], [], [], null, null)
->addDocumentPaymentMean(ZugferdPaymentMeans::UNTDID_4461_58, null, null, null, null, null, $orderModel->getOperator()->getIban(), null, null, null) ->addDocumentPaymentMean(ZugferdPaymentMeans::UNTDID_4461_58, null, null, null, null, null, $orderModel->getOperator()->getIban(), null, null, null)

View File

@ -23,7 +23,7 @@ class OrderListButton
'<a href="' '<a href="'
. $url . $url
. '" target="_blank" title="Bearbeiten"' . '" target="_blank" title="Bearbeiten"'
. ' class="inline-flex items-center justify-center gap-1 px-2.5 py-1.5 rounded-md text-xs font-medium text-white bg-orange-500 hover:bg-orange-600 transition-colors shadow-sm">' . ' class="inline-flex items-center justify-center gap-1 px-2.5 py-1.5 rounded-md text-xs font-medium text-white bg-blue-600 hover:bg-blue-700 transition-colors shadow-sm">'
. '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">' . '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">'
. '<path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" />' . '<path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" />'
. '</svg>' . '</svg>'

View File

@ -8,9 +8,25 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class OrderController extends AbstractController class OrderController extends AbstractController
{ {
private const TYPE_LABELS = [
1 => 'Auftrag',
2 => 'Angebot',
3 => 'Storno',
4 => 'Gutschrift',
5 => 'Rechnung',
6 => 'Teilrechnung',
7 => 'Teilstorno',
];
#[Template('@PluginSystemPSCInvoice/backend/order/index.html.twig')] #[Template('@PluginSystemPSCInvoice/backend/order/index.html.twig')]
public function indexAction(?\PSC\Shop\EntityBundle\Entity\Order $order, ?Order $orderDoc) public function indexAction(?\PSC\Shop\EntityBundle\Entity\Order $order, ?Order $orderDoc)
{ {
return ['uuid' => $order ? $order->getUuid() : false]; $type = $order ? $order->getType() : 0;
$typeLabel = self::TYPE_LABELS[$type] ?? 'Auftrag';
return [
'uuid' => $order ? $order->getUuid() : false,
'typeLabel' => $typeLabel,
];
} }
} }

View File

@ -168,7 +168,7 @@ const BaseComponent = () => {
onClick={() => setIsSetup(false)} onClick={() => setIsSetup(false)}
className="mt-2 h-11 rounded-sm border border-psc-orange bg-psc-orange px-6 text-sm font-medium text-white transition hover:bg-psc-orange-dark disabled:cursor-not-allowed disabled:opacity-50" className="mt-2 h-11 rounded-sm border border-psc-orange bg-psc-orange px-6 text-sm font-medium text-white transition hover:bg-psc-orange-dark disabled:cursor-not-allowed disabled:opacity-50"
> >
Weiter zur Auftragsmaske Weiter zur Eingabemaske
</button> </button>
</div> </div>
</div> </div>

View File

@ -6,12 +6,17 @@ type BoxProps = {
subtitle?: React.ReactNode subtitle?: React.ReactNode
action?: React.ReactNode action?: React.ReactNode
className?: string className?: string
incomplete?: boolean
children?: React.ReactNode children?: React.ReactNode
} }
const Box = ({ icon, title, subtitle, action, className = '', children }: BoxProps) => ( const Box = ({ icon, title, subtitle, action, className = '', incomplete = false, children }: BoxProps) => (
<section <section
className={`rounded-sm border border-psc-border bg-white px-7.5 py-6 shadow-lg ${className}`} className={`rounded-sm border-2 bg-white px-7.5 py-6 shadow-lg ${
incomplete
? 'border-orange-400 bg-orange-50/50 shadow-orange-100 ring-2 ring-psc-orange/20'
: 'border-psc-border'
} ${className}`}
> >
{(title || icon || action) && ( {(title || icon || action) && (
<div className="mb-6 flex flex-col gap-4 border-b border-psc-border pb-4 sm:flex-row sm:items-start sm:justify-between"> <div className="mb-6 flex flex-col gap-4 border-b border-psc-border pb-4 sm:flex-row sm:items-start sm:justify-between">

View File

@ -61,13 +61,11 @@ const AddressCard = ({ title, emptyHint, type, contact, shop, value, onChange }:
address_service.update(addr).then(() => onChange(addr, type)) address_service.update(addr).then(() => onChange(addr, type))
} }
const { showAdd, showEdit } = useAddressModal(shop, onAddressAdded, onAddressEdited, title, extraTypes) const { showEdit } = useAddressModal(shop, onAddressAdded, onAddressEdited, title, extraTypes)
const openPicker = () => { const openPicker = () => {
pickerModal.show({ contact, type, current: value }).then((res: any) => { pickerModal.show({ contact, type, current: value, shop }).then((res: any) => {
if (res && res.createNew) { if (res && res.uuid) {
showAdd()
} else if (res && res.uuid) {
onChange(res as Address, type) onChange(res as Address, type)
} }
}) })

View File

@ -1,4 +1,4 @@
import React, { useEffect, useMemo, useState } from 'react' import React, { useEffect, useMemo, useState, useCallback } from 'react'
import NiceModal, { useModal } from '@ebay/nice-modal-react' import NiceModal, { useModal } from '@ebay/nice-modal-react'
import Modal from '../base/Modal' import Modal from '../base/Modal'
import Button from '../base/Button' import Button from '../base/Button'
@ -6,21 +6,31 @@ import Spinner from '../base/Spinner'
import { Address } from '../../model/address' import { Address } from '../../model/address'
import { Contact } from '../../model/contact' import { Contact } from '../../model/contact'
import AddressService from '../../services/address' import AddressService from '../../services/address'
import AddressModal from './AddressModal'
const fullName = (a: Address) => `${a.firstname ?? ''} ${a.lastname ?? ''}`.trim() const fullName = (a: Address) => `${a.firstname ?? ''} ${a.lastname ?? ''}`.trim()
const TYPE_LABELS: Record<number, string> = {
1: 'Rechnungsadresse',
2: 'Lieferadresse',
3: 'Absenderadresse',
}
const AddressPickerModal = NiceModal.create( const AddressPickerModal = NiceModal.create(
({ contact, type, current }: { contact: Contact; type: number; current?: Address | null }) => { ({ contact, type, current, shop }: { contact: Contact; type: number; current?: Address | null; shop?: any }) => {
const modal = useModal() const modal = useModal()
const addressModal = useModal(AddressModal)
const [term, setTerm] = useState('') const [term, setTerm] = useState('')
const [addresses, setAddresses] = useState<Address[]>([]) const [addresses, setAddresses] = useState<Address[]>([])
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
useEffect(() => { const addressService = new AddressService()
const loadAddresses = useCallback(() => {
let active = true let active = true
setLoading(true) setLoading(true)
new AddressService() addressService
.getContactAddress(contact.uuid, type) .getContactAddress(contact.uuid, type)
.then((data) => { .then((data) => {
if (active) setAddresses(data) if (active) setAddresses(data)
@ -31,7 +41,12 @@ const AddressPickerModal = NiceModal.create(
return () => { return () => {
active = false active = false
} }
}, []) }, [contact.uuid, type])
useEffect(() => {
const cleanup = loadAddresses()
return cleanup
}, [loadAddresses])
const filtered = useMemo(() => { const filtered = useMemo(() => {
const t = term.trim().toLowerCase() const t = term.trim().toLowerCase()
@ -51,8 +66,17 @@ const AddressPickerModal = NiceModal.create(
} }
const createNew = () => { const createNew = () => {
modal.resolve({ createNew: true }) addressModal
modal.remove() .show({ title: `${TYPE_LABELS[type] || 'Adresse'} anlegen`, action: 'Save', shop: shop || {}, extraTypes: [] })
.then((formData: any) => {
const addr = new Address()
addr.parseFromFormData(formData)
addr.type = type
addr.contact.uuid = contact.uuid
addressService.create(addr).then(() => {
loadAddresses()
})
})
} }
return ( return (

View File

@ -82,6 +82,7 @@ const ContactComponent = ({ order, shop }) => {
<Box <Box
title="Kontakt" title="Kontakt"
subtitle="Kunde und Accountdaten." subtitle="Kunde und Accountdaten."
incomplete={!contactSelected}
icon={ icon={
<svg className="h-5 w-5" fill="none" stroke="currentColor" strokeWidth={2} viewBox="0 0 24 24"> <svg className="h-5 w-5" fill="none" stroke="currentColor" strokeWidth={2} viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" d="M20 21a8 8 0 1 0-16 0M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z" /> <path strokeLinecap="round" strokeLinejoin="round" d="M20 21a8 8 0 1 0-16 0M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z" />
@ -145,6 +146,7 @@ const ContactComponent = ({ order, shop }) => {
<Box <Box
title="Adressdaten" title="Adressdaten"
subtitle="Rechnung, Lieferung und Absender." subtitle="Rechnung, Lieferung und Absender."
incomplete={!invoiceAddress?.uuid || !deliveryAddress?.uuid}
icon={ icon={
<svg className="h-5 w-5" fill="none" stroke="currentColor" strokeWidth={2} viewBox="0 0 24 24"> <svg className="h-5 w-5" fill="none" stroke="currentColor" strokeWidth={2} viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" d="M12 21s7-5.2 7-12A7 7 0 1 0 5 9c0 6.8 7 12 7 12zM12 11.5A2.5 2.5 0 1 0 12 6a2.5 2.5 0 0 0 0 5.5z" /> <path strokeLinecap="round" strokeLinejoin="round" d="M12 21s7-5.2 7-12A7 7 0 1 0 5 9c0 6.8 7 12 7 12zM12 11.5A2.5 2.5 0 1 0 12 6a2.5 2.5 0 0 0 0 5.5z" />

View File

@ -47,6 +47,7 @@ const PaymentComponent = ({ shop, order }) => {
<Box <Box
title="Zahlart" title="Zahlart"
subtitle="Zahlungsbedingung" subtitle="Zahlungsbedingung"
incomplete={payment === 0}
icon={ icon={
<svg className="h-5 w-5" fill="none" stroke="currentColor" strokeWidth={2} viewBox="0 0 24 24"> <svg className="h-5 w-5" fill="none" stroke="currentColor" strokeWidth={2} viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" /> <path strokeLinecap="round" strokeLinejoin="round" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" />

View File

@ -47,6 +47,7 @@ const PositionsComponent = ({order, shop, updateOrder}) => {
<Box <Box
title="Positionen" title="Positionen"
subtitle="Zentraler Arbeitsbereich für Artikel, Mengen und Druckdaten." subtitle="Zentraler Arbeitsbereich für Artikel, Mengen und Druckdaten."
incomplete={positions.length === 0}
icon={ icon={
<svg className="h-5 w-5" fill="none" stroke="currentColor" strokeWidth={2} viewBox="0 0 24 24"> <svg className="h-5 w-5" fill="none" stroke="currentColor" strokeWidth={2} viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01" /> <path strokeLinecap="round" strokeLinejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01" />

View File

@ -45,6 +45,7 @@ const ShippingComponent = ({shop, order}) => {
<Box <Box
title="Versandart" title="Versandart"
subtitle="Versand oder Abholung" subtitle="Versand oder Abholung"
incomplete={shipping === 0}
icon={ icon={
<svg className="h-5 w-5" fill="none" stroke="currentColor" strokeWidth={2} viewBox="0 0 24 24"> <svg className="h-5 w-5" fill="none" stroke="currentColor" strokeWidth={2} viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4" /> <path strokeLinecap="round" strokeLinejoin="round" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4" />

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
{% if uuid %} {% if uuid %}
<a href="/apps/backend/component/invoice/index/create#/{{ uuid }}" target="_blank" class="inline-flex items-center justify-center py-1 gap-1 font-medium rounded-sm px-4 text-sm text-white shadow-lg bg-indigo-500 hover:bg-indigo-600 hover:ring-2 hover:ring-indigo-500 hover:ring-offset-2 min-h-[2.25rem]">Auftrag bearbeiten</a> <a href="/apps/backend/component/invoice/index/create#/{{ uuid }}" target="_blank" class="inline-flex items-center justify-center py-1 gap-1 font-medium rounded-sm px-4 text-sm text-white shadow-lg bg-indigo-500 hover:bg-indigo-600 hover:ring-2 hover:ring-indigo-500 hover:ring-offset-2 min-h-[2.25rem]">{{ typeLabel }} bearbeiten</a>
{% else %} {% else %}
<div class="panel"> <div class="panel">
<div class="body"><a href="/apps/backend/component/invoice/index/create" target="_blank" class="inline-flex items-center justify-center py-1 gap-1 font-medium rounded-sm px-4 text-sm text-white shadow-lg bg-indigo-500 hover:bg-indigo-600 hover:ring-2 hover:ring-indigo-500 hover:ring-offset-2 min-h-[2.25rem]">Auftrag anlegen</a></div> <div class="body"><a href="/apps/backend/component/invoice/index/create" target="_blank" class="inline-flex items-center justify-center py-1 gap-1 font-medium rounded-sm px-4 text-sm text-white shadow-lg bg-indigo-500 hover:bg-indigo-600 hover:ring-2 hover:ring-indigo-500 hover:ring-offset-2 min-h-[2.25rem]">Neu anlegen</a></div>
</div> </div>
{% endif %} {% endif %}