Backend Revocaton
This commit is contained in:
parent
51061f1699
commit
982642543d
@ -476,7 +476,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||
* datetime?: array{
|
||||
* default_format?: scalar|Param|null, // Default: "Y-m-d\\TH:i:sP"
|
||||
* default_deserialization_formats?: list<scalar|Param|null>,
|
||||
* default_timezone?: scalar|Param|null, // Default: "Europe/Berlin"
|
||||
* default_timezone?: scalar|Param|null, // Default: "UTC"
|
||||
* cdata?: scalar|Param|null, // Default: true
|
||||
* },
|
||||
* array_collection?: array{
|
||||
@ -576,7 +576,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||
* datetime?: array{
|
||||
* default_format?: scalar|Param|null, // Default: "Y-m-d\\TH:i:sP"
|
||||
* default_deserialization_formats?: list<scalar|Param|null>,
|
||||
* default_timezone?: scalar|Param|null, // Default: "Europe/Berlin"
|
||||
* default_timezone?: scalar|Param|null, // Default: "UTC"
|
||||
* cdata?: scalar|Param|null, // Default: true
|
||||
* },
|
||||
* array_collection?: array{
|
||||
|
||||
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace PSC\Shop\QueueBundle\Event\Order\Revocation;
|
||||
|
||||
use PSC\Shop\QueueBundle\Event\Event;
|
||||
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
|
||||
|
||||
/**
|
||||
* Wird aus dem Alt-System (Zend) ausgelöst, sobald ein Kunde auf der
|
||||
* auftragsbezogenen Widerrufsseite eine konkrete Position widerrufen hat.
|
||||
* Das Widerruf-Flag und der Zeitpunkt sind dann bereits auf der Position
|
||||
* gesetzt. Hierauf kann z.B. der Queue-Typ "Mail" reagieren.
|
||||
*/
|
||||
#[AutoconfigureTag('events')]
|
||||
class PositionRequest extends Event
|
||||
{
|
||||
/** @var string */
|
||||
protected $order;
|
||||
/** @var string */
|
||||
protected $position;
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return 'order_revocation_position_request';
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Widerruf für eine Position durchgeführt';
|
||||
}
|
||||
|
||||
public function getData()
|
||||
{
|
||||
return array(
|
||||
'order' => $this->order,
|
||||
'position' => $this->position,
|
||||
);
|
||||
}
|
||||
|
||||
public function setData($data)
|
||||
{
|
||||
$this->order = $data['order'] ?? null;
|
||||
$this->position = $data['position'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOrder()
|
||||
{
|
||||
return $this->order;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $order
|
||||
*/
|
||||
public function setOrder($order)
|
||||
{
|
||||
$this->order = $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPosition()
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $position
|
||||
*/
|
||||
public function setPosition($position)
|
||||
{
|
||||
$this->position = $position;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace PSC\Shop\QueueBundle\Event\Order\Revocation;
|
||||
|
||||
use PSC\Shop\QueueBundle\Event\Event;
|
||||
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
|
||||
|
||||
/**
|
||||
* Wird aus dem Alt-System (Zend) ausgelöst, sobald ein Kunde über das
|
||||
* Widerrufsformular (/revocationform) für einen Auftrag einen Widerruf
|
||||
* anfordert. Hierauf kann z.B. der Queue-Typ "Mail" reagieren und dem
|
||||
* Kunden den Deep-Link zur auftragsbezogenen Widerrufsseite zusenden.
|
||||
*/
|
||||
#[AutoconfigureTag('events')]
|
||||
class Request extends Event
|
||||
{
|
||||
/** @var string */
|
||||
protected $order;
|
||||
/** @var string */
|
||||
protected $alias;
|
||||
/** @var string */
|
||||
protected $email;
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return 'order_revocation_request';
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Widerruf für einen Auftrag angefordert';
|
||||
}
|
||||
|
||||
public function getData()
|
||||
{
|
||||
return array(
|
||||
'order' => $this->order,
|
||||
'alias' => $this->alias,
|
||||
'email' => $this->email,
|
||||
);
|
||||
}
|
||||
|
||||
public function setData($data)
|
||||
{
|
||||
$this->order = $data['order'] ?? null;
|
||||
$this->alias = $data['alias'] ?? null;
|
||||
$this->email = $data['email'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOrder()
|
||||
{
|
||||
return $this->order;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $order
|
||||
*/
|
||||
public function setOrder($order)
|
||||
{
|
||||
$this->order = $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAlias()
|
||||
{
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $alias
|
||||
*/
|
||||
public function setAlias($alias)
|
||||
{
|
||||
$this->alias = $alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEmail()
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $email
|
||||
*/
|
||||
public function setEmail($email)
|
||||
{
|
||||
$this->email = $email;
|
||||
}
|
||||
}
|
||||
@ -25,6 +25,8 @@ use PSC\Shop\QueueBundle\Event\Contact\Password\Reset\Finish;
|
||||
use PSC\Shop\QueueBundle\Event\Contact\Password\Reset\Start;
|
||||
use PSC\Shop\QueueBundle\Event\EventInterface;
|
||||
use PSC\Shop\QueueBundle\Event\Order\Create;
|
||||
use PSC\Shop\QueueBundle\Event\Order\Revocation\PositionRequest as RevocationPositionRequest;
|
||||
use PSC\Shop\QueueBundle\Event\Order\Revocation\Request as RevocationRequest;
|
||||
use PSC\Shop\QueueBundle\Event\Position\ApprovalExternalAccept;
|
||||
use PSC\Shop\QueueBundle\Event\Position\ApprovalExternalDeclined;
|
||||
use PSC\Shop\QueueBundle\Event\Position\ApprovalExternalRequest;
|
||||
@ -1709,6 +1711,155 @@ class Mail implements QueueInterface, ConfigurableElementInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
if ($event instanceof RevocationRequest) {
|
||||
$templateVars->loadOrder($event->getOrder());
|
||||
$vars = $templateVars->getTwigVars();
|
||||
// Zusätzliche Variablen für die Mail an den Kunden inkl. Deep-Link
|
||||
// auf die auftragsbezogene Widerrufsseite im Alt-System.
|
||||
$vars['revocationEmail'] = $event->getEmail();
|
||||
$vars['revocationAlias'] = $event->getAlias();
|
||||
$vars['revocationLink'] = '/revocationform/order/uuid/' . $event->getOrder();
|
||||
try {
|
||||
$message = new TemplatedEmail()
|
||||
->subject($subject->render($vars))
|
||||
->from(new Address($from->render($vars), $fromName->render($vars)))
|
||||
->to(new Address($to->render($vars), $toName->render($vars)));
|
||||
if ($text) {
|
||||
$message->text($text->render($vars));
|
||||
}
|
||||
|
||||
if ($bcc) {
|
||||
$bccArray = explode(',', $bcc->render($vars));
|
||||
foreach ($bccArray as $bc) {
|
||||
if (trim($bc) != '') {
|
||||
$message->addBcc(trim($bc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($html) {
|
||||
$message->html($html->render(array_merge($vars, [
|
||||
'email' => new WrappedTemplatedEmail($this->_template, $message),
|
||||
])));
|
||||
}
|
||||
|
||||
foreach ($mailDoc->getFiles() as $file) {
|
||||
if ($file['name'] != '' && $file['content'] != '') {
|
||||
$fileContent = $this->_template->createTemplate($file['content']);
|
||||
$fileName = $this->_template->createTemplate($file['name']);
|
||||
$message->attach($fileContent->render($vars), $fileName->render($vars));
|
||||
}
|
||||
}
|
||||
$this->_logService->createLogEntry(
|
||||
$templateVars->getOrder()->getShop(),
|
||||
new Contact(),
|
||||
LogEntry::INFO,
|
||||
PSCShopQueueBundle::class,
|
||||
$queue->getName(),
|
||||
'Revocation Request Mail send',
|
||||
[
|
||||
'message' => $message->getTextBody(),
|
||||
'from' => $from->render($vars),
|
||||
'to' => $to->render($vars),
|
||||
'subject' => $subject->render($vars),
|
||||
],
|
||||
);
|
||||
$this->sendMail($message);
|
||||
} catch (\Exception $e) {
|
||||
$this->_logService->createLogEntry(
|
||||
$templateVars->getOrder()->getShop(),
|
||||
new Contact(),
|
||||
LogEntry::ERROR,
|
||||
PSCShopQueueBundle::class,
|
||||
$queue->getName(),
|
||||
'Revocation Request Mail error',
|
||||
[
|
||||
'error' => $e->getMessage(),
|
||||
],
|
||||
);
|
||||
$this->_error = $e->getMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
if ($event instanceof RevocationPositionRequest) {
|
||||
$templateVars->loadOrder($event->getOrder());
|
||||
$vars = $templateVars->getPosTwigVars($event->getPosition());
|
||||
try {
|
||||
$message = new TemplatedEmail()
|
||||
->subject($subject->render($vars))
|
||||
->from(
|
||||
new Address(
|
||||
$from->render($templateVars->getTwigVars()),
|
||||
$fromName->render($templateVars->getTwigVars()),
|
||||
),
|
||||
)
|
||||
->to(
|
||||
new Address(
|
||||
$to->render($templateVars->getTwigVars()),
|
||||
$toName->render($templateVars->getTwigVars()),
|
||||
),
|
||||
);
|
||||
if ($text) {
|
||||
$message->text($text->render($vars));
|
||||
}
|
||||
|
||||
if ($bcc) {
|
||||
$bccArray = explode(',', $bcc->render($vars));
|
||||
foreach ($bccArray as $bc) {
|
||||
if (trim($bc) != '') {
|
||||
$message->addBcc(trim($bc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($html) {
|
||||
$message->html($html->render(array_merge($vars, [
|
||||
'email' => new WrappedTemplatedEmail($this->_template, $message),
|
||||
])));
|
||||
}
|
||||
|
||||
foreach ($mailDoc->getFiles() as $file) {
|
||||
if ($file['name'] != '' && $file['content'] != '') {
|
||||
$fileContent = $this->_template->createTemplate($file['content']);
|
||||
$fileName = $this->_template->createTemplate($file['name']);
|
||||
$message->attach($fileContent->render($vars), $fileName->render($vars));
|
||||
}
|
||||
}
|
||||
$this->_logService->createLogEntry(
|
||||
$templateVars->getOrder()->getShop(),
|
||||
new Contact(),
|
||||
LogEntry::INFO,
|
||||
PSCShopQueueBundle::class,
|
||||
$queue->getName(),
|
||||
'Revocation Position Request Mail send',
|
||||
[
|
||||
'message' => $message->getTextBody(),
|
||||
'from' => $from->render($templateVars->getTwigVars()),
|
||||
'to' => $to->render($templateVars->getTwigVars()),
|
||||
'subject' => $subject->render($vars),
|
||||
],
|
||||
);
|
||||
$this->sendMail($message);
|
||||
} catch (\Exception $e) {
|
||||
$this->_logService->createLogEntry(
|
||||
$templateVars->getOrder()->getShop(),
|
||||
new Contact(),
|
||||
LogEntry::ERROR,
|
||||
PSCShopQueueBundle::class,
|
||||
$queue->getName(),
|
||||
'Revocation Position Request Mail error',
|
||||
[
|
||||
'error' => $e->getMessage(),
|
||||
],
|
||||
);
|
||||
$this->_error = $e->getMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,20 @@
|
||||
info:
|
||||
datum: 10.06.2026
|
||||
release: 2.3.6
|
||||
datum: 23.06.2026
|
||||
release: 2.3.7
|
||||
|
||||
changelog:
|
||||
- version: 2.3.7
|
||||
datum: 23.06.2026
|
||||
changes:
|
||||
- "Dashboard: Speicherverbrauch von System- und Daten-Volume mit Icons"
|
||||
- "Produkt: Option \"Widerrufsbutton aktivieren\" (pro Produkt)"
|
||||
- "Auftragsdetails: Positionen-Ansicht überarbeitet (Spalten Widerruf/Status, Preise, Aktionen; Vorschaubilder wie in der Auftragsliste)"
|
||||
- "Auftragsposition: Widerruf-Status mit Datum (ob/wann widerrufen) inkl. Anzeige im Backend"
|
||||
- "Widerrufsformular im Shop unter /revocationform (Bestellnummer + E-Mail + Captcha)"
|
||||
- "Deep-Link /revocationform/order/uuid/<uuid>: Kunde kann pro Position widerrufen (Flag + Zeitpunkt werden gesetzt)"
|
||||
- "Neue Events für die Mail-Queue: order_revocation_request (Widerruf angefordert) und order_revocation_position_request (Position widerrufen)"
|
||||
- "Mail-Variablen order_revocation_request: order, shop, contact, revocationEmail, revocationAlias, revocationLink (Deep-Link-Pfad, z.B. https://{Shop-Domain}{{ revocationLink }})"
|
||||
- "Mail-Variablen order_revocation_position_request: order, position, shop, contact"
|
||||
- version: 2.3.6
|
||||
datum: 10.06.2026
|
||||
changes:
|
||||
|
||||
@ -124,6 +124,8 @@ abstract class BaseArticle extends Doctrine_Record
|
||||
|
||||
$this->hasColumn('not_buy', 'boolean');
|
||||
|
||||
$this->hasColumn('revoke_button_enable', 'boolean', 1);
|
||||
|
||||
$this->hasColumn('file', 'string', 255, array('type' => 'string', 'length' => '255'));
|
||||
$this->hasColumn('file1', 'string', 255, array('type' => 'string', 'length' => '255'));
|
||||
$this->hasColumn('file2', 'string', 255, array('type' => 'string', 'length' => '255'));
|
||||
|
||||
@ -103,6 +103,9 @@ abstract class BaseOrderspos extends Doctrine_Record
|
||||
|
||||
$this->hasColumn('ref', 'string', 255);
|
||||
$this->hasColumn('kst', 'string', 255);
|
||||
|
||||
$this->hasColumn('revoked', 'boolean', 1);
|
||||
$this->hasColumn('revoked_at', 'timestamp');
|
||||
}
|
||||
|
||||
public function setUp()
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
[revocation]
|
||||
; general form metainformation
|
||||
global.class ="form-horizontal"
|
||||
|
||||
user.revocation.action = "/revocationform"
|
||||
user.revocation.method = "post"
|
||||
|
||||
user.revocation.legend = "Widerruf"
|
||||
|
||||
; Bestellnummer
|
||||
user.revocation.elements.ordernumber.type = "text"
|
||||
user.revocation.elements.ordernumber.options.label = "Bestellnummer"
|
||||
user.revocation.elements.ordernumber.options.required = true
|
||||
|
||||
; Email
|
||||
user.revocation.elements.self_email.type = "text"
|
||||
user.revocation.elements.self_email.options.label = "Email"
|
||||
user.revocation.elements.self_email.options.required = true
|
||||
user.revocation.elements.self_email.options.validators.email.validator = "EmailAddress"
|
||||
|
||||
; Captcha
|
||||
user.revocation.elements.cp.type = "captcha"
|
||||
user.revocation.elements.cp.options.label = ""
|
||||
user.revocation.elements.cp.options.captcha.captcha = "Image"
|
||||
|
||||
user.revocation.elements.submit.type = "submit"
|
||||
user.revocation.elements.submit.options.class = "submit btn btn-success btn-large"
|
||||
user.revocation.elements.submit.options.label = "Widerruf absenden"
|
||||
@ -0,0 +1,17 @@
|
||||
<div class="row">
|
||||
|
||||
<div class="col-xs-12">
|
||||
|
||||
<br>
|
||||
|
||||
<h1><?php echo $this->translate('Widerruf erhalten') ?></h1>
|
||||
|
||||
<p>
|
||||
<?php echo $this->translate('Wir haben Ihren Widerruf erhalten und werden ihn bearbeiten.')?>
|
||||
</p>
|
||||
|
||||
<br>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -0,0 +1,52 @@
|
||||
<div class="row">
|
||||
|
||||
<div class="col-xs-12">
|
||||
|
||||
<h1><?php echo $this->translate('Widerruf') ?></h1>
|
||||
|
||||
<p><strong><?php echo $this->translate('Sie möchten eine Bestellung widerrufen?')?></strong></p>
|
||||
|
||||
<br>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
|
||||
<p>
|
||||
<?php echo $this->translate('Geben Sie bitte Ihre Bestellnummer und die E-Mail-Adresse Ihrer Bestellung an und fahren Sie mit "Widerruf absenden" fort.')?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="well" style="padding: 3em">
|
||||
<?php
|
||||
// Manuelles Rendern (wie bei den resale-Formularen), damit das Image-Captcha
|
||||
// in bootstrap4_api zuverlässig erscheint. Der EasyBib-BOOTSTRAP-Dekorator
|
||||
// rendert für Captcha-Elemente kein Bild/Eingabefeld.
|
||||
?>
|
||||
<form method="post" action="/revocationform" class="niceform form-horizontal" id="revocationform" enctype="application/x-www-form-urlencoded">
|
||||
|
||||
<div class="control-group form-group">
|
||||
<label class="control-label form-label" for="ordernumber"><?php echo $this->translate('Bestellnummer') ?></label>
|
||||
<div class="controls form-controls">
|
||||
<input type="text" name="ordernumber" id="ordernumber" class="form-control required" value="<?php echo $this->escape($this->form->ordernumber->getValue()) ?>" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group form-group">
|
||||
<label class="control-label form-label" for="self_email"><?php echo $this->translate('Email') ?></label>
|
||||
<div class="controls form-controls">
|
||||
<input type="text" name="self_email" id="self_email" class="form-control required" value="<?php echo $this->escape($this->form->self_email->getValue()) ?>" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="captcha" class="control-group form-group">
|
||||
<?php echo $this->form->cp ?>
|
||||
</div>
|
||||
|
||||
<input type="submit" class="btn btn-success btn-large" value="<?php echo $this->translate('Widerruf absenden') ?>" />
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -0,0 +1,41 @@
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<h1><?php echo $this->translate('Widerruf') ?> – <?php echo $this->escape($this->order->alias) ?></h1>
|
||||
<p><?php echo $this->translate('Wählen Sie die Positionen aus, die Sie widerrufen möchten.')?></p>
|
||||
<br>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php echo $this->translate('Pos') ?></th>
|
||||
<th><?php echo $this->translate('Produkt') ?></th>
|
||||
<th><?php echo $this->translate('Auflage') ?></th>
|
||||
<th><?php echo $this->translate('Widerruf') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($this->positions as $pos): ?>
|
||||
<tr>
|
||||
<td><?php echo $this->escape($pos->pos) ?></td>
|
||||
<td><?php echo $this->escape($pos->Article->title) ?></td>
|
||||
<td><?php echo $this->escape($pos->count) ?></td>
|
||||
<td>
|
||||
<?php if ($pos->revoked): ?>
|
||||
<span class="label label-info"><?php echo $this->translate('Widerrufen am') ?> <?php echo $this->escape($pos->revoked_at) ?></span>
|
||||
<?php elseif ($pos->Article->revoke_button_enable): ?>
|
||||
<form method="post" action="/revocationform/order/uuid/<?php echo $this->escape($this->order->uuid) ?>" style="margin:0">
|
||||
<input type="hidden" name="pos" value="<?php echo $this->escape($pos->uuid) ?>" />
|
||||
<button type="submit" class="btn btn-warning btn-sm"><?php echo $this->translate('Widerrufen') ?></button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<span class="text-muted"><?php echo $this->translate('Widerruf nicht möglich') ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,28 @@
|
||||
[revocation]
|
||||
; general form metainformation
|
||||
global.class ="form-horizontal"
|
||||
|
||||
user.revocation.action = "/revocationform"
|
||||
user.revocation.method = "post"
|
||||
|
||||
user.revocation.legend = "Widerruf"
|
||||
|
||||
; Bestellnummer
|
||||
user.revocation.elements.ordernumber.type = "text"
|
||||
user.revocation.elements.ordernumber.options.label = "Bestellnummer"
|
||||
user.revocation.elements.ordernumber.options.required = true
|
||||
|
||||
; Email
|
||||
user.revocation.elements.self_email.type = "text"
|
||||
user.revocation.elements.self_email.options.label = "Email"
|
||||
user.revocation.elements.self_email.options.required = true
|
||||
user.revocation.elements.self_email.options.validators.email.validator = "EmailAddress"
|
||||
|
||||
; Captcha
|
||||
user.revocation.elements.cp.type = "captcha"
|
||||
user.revocation.elements.cp.options.label = ""
|
||||
user.revocation.elements.cp.options.captcha.captcha = "Image"
|
||||
|
||||
user.revocation.elements.submit.type = "submit"
|
||||
user.revocation.elements.submit.options.class = "submit btn btn-success btn-large"
|
||||
user.revocation.elements.submit.options.label = "Widerruf absenden"
|
||||
@ -0,0 +1,7 @@
|
||||
<div class="md:w-2/4 w-3/4 m-auto mt-5">
|
||||
|
||||
<h1 class="text-lg mb-2"><?php echo $this->translate('Widerruf erhalten') ?></h1>
|
||||
|
||||
<p class="mb-2"><?php echo $this->translate('Wir haben Ihren Widerruf erhalten und werden ihn bearbeiten.')?></p>
|
||||
|
||||
</div>
|
||||
@ -0,0 +1,13 @@
|
||||
<div class="md:w-2/4 w-11/12 m-auto mt-8 mb-10">
|
||||
|
||||
<h1 class="text-2xl font-semibold mb-2"><?php echo $this->translate('Widerruf') ?></h1>
|
||||
|
||||
<p class="mb-1"><strong><?php echo $this->translate('Sie möchten eine Bestellung widerrufen?')?></strong></p>
|
||||
|
||||
<p class="mb-6 opacity-80"><?php echo $this->translate('Geben Sie bitte Ihre Bestellnummer und die E-Mail-Adresse Ihrer Bestellung an und fahren Sie mit "Widerruf absenden" fort.')?></p>
|
||||
|
||||
<div class="bg-middleBase text-altMiddleBase rounded-lg shadow-md p-6">
|
||||
<?= $this->partial('completeform.phtml', array('buttonName' => 'Widerruf absenden', 'buttonClass' => '', 'form' => $this->form)) ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -0,0 +1,46 @@
|
||||
<div class="md:w-3/4 w-11/12 m-auto mt-8 mb-10">
|
||||
|
||||
<h1 class="text-2xl font-semibold mb-1"><?php echo $this->translate('Widerruf') ?></h1>
|
||||
<p class="opacity-80 mb-6"><?php echo $this->translate('Auftrag') ?>: <strong><?php echo $this->escape($this->order->alias) ?></strong> · <?php echo $this->translate('Wählen Sie die Positionen aus, die Sie widerrufen möchten.')?></p>
|
||||
|
||||
<div class="bg-middleBase text-altMiddleBase rounded-lg shadow-md overflow-hidden">
|
||||
<table class="w-full text-sm">
|
||||
<thead>
|
||||
<tr class="bg-headerFooter text-altHeaderFooter">
|
||||
<th class="text-left font-medium py-3 px-4 w-12"><?php echo $this->translate('Pos') ?></th>
|
||||
<th class="text-left font-medium py-3 px-4"><?php echo $this->translate('Produkt') ?></th>
|
||||
<th class="text-left font-medium py-3 px-4 w-24"><?php echo $this->translate('Auflage') ?></th>
|
||||
<th class="text-left font-medium py-3 px-4 w-64"><?php echo $this->translate('Widerruf') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($this->positions as $pos): ?>
|
||||
<tr class="border-t border-base/40">
|
||||
<td class="py-3 px-4 align-top font-medium"><?php echo $this->escape($pos->pos) ?></td>
|
||||
<td class="py-3 px-4 align-top"><?php echo $this->escape($pos->Article->title) ?></td>
|
||||
<td class="py-3 px-4 align-top"><?php echo $this->escape($pos->count) ?></td>
|
||||
<td class="py-3 px-4 align-top">
|
||||
<?php if ($pos->revoked): ?>
|
||||
<span class="inline-flex items-center gap-1 rounded-md bg-sky-50 text-sky-800 border border-sky-200 px-2 py-1 text-xs">
|
||||
<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="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" /></svg>
|
||||
<?php echo $this->translate('Widerrufen am') ?> <?php echo $this->escape($pos->revoked_at) ?>
|
||||
</span>
|
||||
<?php elseif ($pos->Article->revoke_button_enable): ?>
|
||||
<form method="post" action="/revocationform/order/uuid/<?php echo $this->escape($this->order->uuid) ?>">
|
||||
<input type="hidden" name="pos" value="<?php echo $this->escape($pos->uuid) ?>" />
|
||||
<button type="submit" class="border bg-highlight text-altHighlight py-1.5 px-4 rounded-md hover:bg-white hover:text-black transition"><?php echo $this->translate('Widerrufen') ?></button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<span class="inline-flex items-center gap-1 text-xs opacity-60">
|
||||
<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="M9.75 9.75l4.5 4.5m0-4.5l-4.5 4.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
||||
<?php echo $this->translate('Widerruf nicht möglich') ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -0,0 +1,28 @@
|
||||
[revocation]
|
||||
; general form metainformation
|
||||
global.class ="form-horizontal"
|
||||
|
||||
user.revocation.action = "/revocationform"
|
||||
user.revocation.method = "post"
|
||||
|
||||
user.revocation.legend = "Widerruf"
|
||||
|
||||
; Bestellnummer
|
||||
user.revocation.elements.ordernumber.type = "text"
|
||||
user.revocation.elements.ordernumber.options.label = "Bestellnummer"
|
||||
user.revocation.elements.ordernumber.options.required = true
|
||||
|
||||
; Email
|
||||
user.revocation.elements.self_email.type = "text"
|
||||
user.revocation.elements.self_email.options.label = "Email"
|
||||
user.revocation.elements.self_email.options.required = true
|
||||
user.revocation.elements.self_email.options.validators.email.validator = "EmailAddress"
|
||||
|
||||
; Captcha
|
||||
user.revocation.elements.cp.type = "captcha"
|
||||
user.revocation.elements.cp.options.label = ""
|
||||
user.revocation.elements.cp.options.captcha.captcha = "Image"
|
||||
|
||||
user.revocation.elements.submit.type = "submit"
|
||||
user.revocation.elements.submit.options.class = "submit btn btn-success btn-large"
|
||||
user.revocation.elements.submit.options.label = "Widerruf absenden"
|
||||
@ -0,0 +1,7 @@
|
||||
<div class="md:w-2/4 w-3/4 m-auto mt-5">
|
||||
|
||||
<h1 class="text-lg mb-2"><?php echo $this->translate('Widerruf erhalten') ?></h1>
|
||||
|
||||
<p class="mb-2"><?php echo $this->translate('Wir haben Ihren Widerruf erhalten und werden ihn bearbeiten.')?></p>
|
||||
|
||||
</div>
|
||||
@ -0,0 +1,13 @@
|
||||
<div class="md:w-2/4 w-11/12 m-auto mt-8 mb-10">
|
||||
|
||||
<h1 class="text-2xl font-semibold mb-2"><?php echo $this->translate('Widerruf') ?></h1>
|
||||
|
||||
<p class="mb-1"><strong><?php echo $this->translate('Sie möchten eine Bestellung widerrufen?')?></strong></p>
|
||||
|
||||
<p class="mb-6 opacity-80"><?php echo $this->translate('Geben Sie bitte Ihre Bestellnummer und die E-Mail-Adresse Ihrer Bestellung an und fahren Sie mit "Widerruf absenden" fort.')?></p>
|
||||
|
||||
<div class="bg-middleBase text-altMiddleBase rounded-lg shadow-md p-6">
|
||||
<?= $this->partial('completeform.phtml', array('buttonName' => 'Widerruf absenden', 'buttonClass' => '', 'form' => $this->form)) ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -0,0 +1,46 @@
|
||||
<div class="md:w-3/4 w-11/12 m-auto mt-8 mb-10">
|
||||
|
||||
<h1 class="text-2xl font-semibold mb-1"><?php echo $this->translate('Widerruf') ?></h1>
|
||||
<p class="opacity-80 mb-6"><?php echo $this->translate('Auftrag') ?>: <strong><?php echo $this->escape($this->order->alias) ?></strong> · <?php echo $this->translate('Wählen Sie die Positionen aus, die Sie widerrufen möchten.')?></p>
|
||||
|
||||
<div class="bg-middleBase text-altMiddleBase rounded-lg shadow-md overflow-hidden">
|
||||
<table class="w-full text-sm">
|
||||
<thead>
|
||||
<tr class="bg-headerFooter text-altHeaderFooter">
|
||||
<th class="text-left font-medium py-3 px-4 w-12"><?php echo $this->translate('Pos') ?></th>
|
||||
<th class="text-left font-medium py-3 px-4"><?php echo $this->translate('Produkt') ?></th>
|
||||
<th class="text-left font-medium py-3 px-4 w-24"><?php echo $this->translate('Auflage') ?></th>
|
||||
<th class="text-left font-medium py-3 px-4 w-64"><?php echo $this->translate('Widerruf') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($this->positions as $pos): ?>
|
||||
<tr class="border-t border-base/40">
|
||||
<td class="py-3 px-4 align-top font-medium"><?php echo $this->escape($pos->pos) ?></td>
|
||||
<td class="py-3 px-4 align-top"><?php echo $this->escape($pos->Article->title) ?></td>
|
||||
<td class="py-3 px-4 align-top"><?php echo $this->escape($pos->count) ?></td>
|
||||
<td class="py-3 px-4 align-top">
|
||||
<?php if ($pos->revoked): ?>
|
||||
<span class="inline-flex items-center gap-1 rounded-md bg-sky-50 text-sky-800 border border-sky-200 px-2 py-1 text-xs">
|
||||
<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="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" /></svg>
|
||||
<?php echo $this->translate('Widerrufen am') ?> <?php echo $this->escape($pos->revoked_at) ?>
|
||||
</span>
|
||||
<?php elseif ($pos->Article->revoke_button_enable): ?>
|
||||
<form method="post" action="/revocationform/order/uuid/<?php echo $this->escape($this->order->uuid) ?>">
|
||||
<input type="hidden" name="pos" value="<?php echo $this->escape($pos->uuid) ?>" />
|
||||
<button type="submit" class="border bg-highlight text-altHighlight py-1.5 px-4 rounded-md hover:bg-white hover:text-black transition"><?php echo $this->translate('Widerrufen') ?></button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<span class="inline-flex items-center gap-1 text-xs opacity-60">
|
||||
<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="M9.75 9.75l4.5 4.5m0-4.5l-4.5 4.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
||||
<?php echo $this->translate('Widerruf nicht möglich') ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Widerrufsformular für Kunden.
|
||||
*
|
||||
* Öffentlich erreichbar unter /revocationform. Der Kunde gibt Bestellnummer und
|
||||
* E-Mail-Adresse ein (mit Captcha). Existiert ein passender Auftrag, wird – analog
|
||||
* zum "Passwort vergessen"-Flow – ein Event in die Mongo-Job-Collection geschrieben,
|
||||
* das die weitere Verarbeitung (z.B. Benachrichtigung) anstößt.
|
||||
*/
|
||||
class RevocationformController extends TP_Controller_Action
|
||||
{
|
||||
public function indexAction()
|
||||
{
|
||||
$config = new Zend_Config_Ini($this->_configPath . '/revocationform.ini', 'revocation');
|
||||
|
||||
if ($config->global) {
|
||||
$form = new EasyBib_Form($config->user->revocation);
|
||||
$form->addAttribs(array('class' => $config->global->class, 'id' => 'revocationform'));
|
||||
} else {
|
||||
$form = new Zend_Form($config->user->revocation);
|
||||
$form->addAttribs(array('class' => 'niceform', 'id' => 'revocationform'));
|
||||
}
|
||||
|
||||
if (isset($form->cp)) {
|
||||
$form->cp->setOptions(array(
|
||||
'captcha' => array(
|
||||
'captcha' => 'Image',
|
||||
'font' => APPLICATION_PATH . '/fonts/verdana.ttf',
|
||||
'imgDir' => PUBLIC_PATH . '/temp/thumb/',
|
||||
'imgUrl' => '/temp/thumb/',
|
||||
'wordLen' => '4',
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
if ($this->getRequest()->isPost() && $form->isValid($this->getRequest()->getPost())) {
|
||||
$order = Doctrine_Query::create()
|
||||
->from('Orders o')
|
||||
->leftJoin('o.Contact c')
|
||||
->where('o.shop_id = ? AND o.alias = ? AND c.self_email = ? AND o.enable = 1', array(
|
||||
$this->shop->id,
|
||||
$this->_getParam('ordernumber'),
|
||||
$this->_getParam('self_email'),
|
||||
))
|
||||
->fetchOne();
|
||||
|
||||
if ($order) {
|
||||
$dbMongo = TP_Mongo::getInstance();
|
||||
$dbMongo->Job->insertOne(array(
|
||||
'shop' => $this->shop->id,
|
||||
'event' => 'order_revocation_request',
|
||||
'data' => array(
|
||||
'order' => $order->uuid,
|
||||
'alias' => $order->alias,
|
||||
'email' => $this->_getParam('self_email'),
|
||||
),
|
||||
'created' => new MongoDB\BSON\UTCDateTime(),
|
||||
'updated' => new MongoDB\BSON\UTCDateTime(),
|
||||
));
|
||||
|
||||
$this->view->priorityMessenger('Ihr Widerruf wurde erfolgreich übermittelt', 'success');
|
||||
$this->redirectSpeak('/revocationform/done');
|
||||
} else {
|
||||
$this->view->priorityMessenger('Es wurde kein passender Auftrag gefunden', 'error');
|
||||
$this->redirectSpeak('/revocationform');
|
||||
}
|
||||
}
|
||||
|
||||
$this->view->form = $form;
|
||||
|
||||
if ($this->shop->private && !Zend_Auth::getInstance()->hasIdentity()) {
|
||||
$this->_helper->layout->setLayout('private');
|
||||
} else {
|
||||
$this->_helper->layout->setLayout('default');
|
||||
}
|
||||
}
|
||||
|
||||
public function doneAction()
|
||||
{
|
||||
if ($this->shop->private && !Zend_Auth::getInstance()->hasIdentity()) {
|
||||
$this->_helper->layout->setLayout('private');
|
||||
} else {
|
||||
$this->_helper->layout->setLayout('default');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deep-Link auf einen konkreten Auftrag (per UUID). Hier kann der Kunde
|
||||
* final pro Position widerrufen. Beim Widerruf werden das Flag und der
|
||||
* Zeitpunkt auf der Position gesetzt und das Event
|
||||
* order_revocation_position_request ausgelöst.
|
||||
*/
|
||||
public function orderAction()
|
||||
{
|
||||
$uuid = $this->_getParam('uuid');
|
||||
|
||||
$order = Doctrine_Query::create()
|
||||
->from('Orders o')
|
||||
->where('o.shop_id = ? AND o.uuid = ? AND o.enable = 1', array($this->shop->id, $uuid))
|
||||
->fetchOne();
|
||||
|
||||
if (!$order) {
|
||||
$this->view->priorityMessenger('Es wurde kein passender Auftrag gefunden', 'error');
|
||||
$this->redirectSpeak('/revocationform');
|
||||
return;
|
||||
}
|
||||
|
||||
// Eine Position widerrufen
|
||||
if ($this->getRequest()->isPost() && $this->_getParam('pos')) {
|
||||
/** @var Orderspos $pos */
|
||||
$pos = Doctrine_Query::create()
|
||||
->from('Orderspos p')
|
||||
->leftJoin('p.Article a')
|
||||
->where('p.uuid = ? AND p.orders_id = ?', array($this->_getParam('pos'), $order->id))
|
||||
->fetchOne();
|
||||
|
||||
if ($pos && $pos->Article && $pos->Article->revoke_button_enable && !$pos->revoked) {
|
||||
$pos->revoked = 1;
|
||||
$pos->revoked_at = date('Y-m-d H:i:s');
|
||||
$pos->save();
|
||||
|
||||
$dbMongo = TP_Mongo::getInstance();
|
||||
$dbMongo->Job->insertOne(array(
|
||||
'shop' => $this->shop->id,
|
||||
'event' => 'order_revocation_position_request',
|
||||
'data' => array(
|
||||
'order' => $order->uuid,
|
||||
'position' => $pos->uuid,
|
||||
),
|
||||
'created' => new MongoDB\BSON\UTCDateTime(),
|
||||
'updated' => new MongoDB\BSON\UTCDateTime(),
|
||||
));
|
||||
|
||||
$this->view->priorityMessenger('Die Position wurde erfolgreich widerrufen', 'success');
|
||||
} else {
|
||||
$this->view->priorityMessenger('Für diese Position ist kein Widerruf möglich', 'error');
|
||||
}
|
||||
|
||||
$this->redirectSpeak('/revocationform/order/uuid/' . $order->uuid);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->view->order = $order;
|
||||
$this->view->positions = $order->Orderspos;
|
||||
|
||||
if ($this->shop->private && !Zend_Auth::getInstance()->hasIdentity()) {
|
||||
$this->_helper->layout->setLayout('private');
|
||||
} else {
|
||||
$this->_helper->layout->setLayout('default');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -523,6 +523,7 @@ class TP_Controller_Action extends Zend_Controller_Action
|
||||
!Zend_Auth::getInstance()->hasIdentity() &&
|
||||
$this->getRequest()->getParam('controller') != 'user' &&
|
||||
$this->getRequest()->getParam('controller') != 'cms' &&
|
||||
$this->getRequest()->getParam('controller') != 'revocationform' &&
|
||||
$this->getRequest()->getParam('action') != 'login'
|
||||
) {
|
||||
$this->_redirect('/user/login');
|
||||
|
||||
@ -59,6 +59,13 @@ class TP_Plugin_Auth extends Zend_Controller_Plugin_Abstract
|
||||
|
||||
$resource = $controller;
|
||||
|
||||
// Öffentlich zugängliche Controller, die (noch) keinen ACL-Eintrag in der
|
||||
// Datenbank besitzen. Das Widerrufsformular ist für nicht eingeloggte
|
||||
// Kunden gedacht und wird daher hier freigegeben.
|
||||
if ($module == 'default' && $controller == 'revocationform') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->_acl->has($module.'_'.$resource)) {
|
||||
$this->_request->setModuleName($this->_nosite['module']);
|
||||
$this->_request->setControllerName($this->_nosite['controller']);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user