feat(16-automated-tasks): moduł zadań automatycznych — CRUD + watcher/executor

Reguły automatyzacji oparte na zdarzeniach (receipt.created) z warunkami
(integracja/kanał sprzedaży, AND logic) i akcjami (wyślij e-mail z 3 trybami
odbiorcy: klient / firma / klient+firma). Trigger w ReceiptController po
utworzeniu paragonu — błąd automatyzacji nie blokuje sukcesu paragonu.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-18 00:39:47 +01:00
parent a6512cbfa4
commit b9f639e037
24 changed files with 4997 additions and 32 deletions

View File

@@ -28,7 +28,7 @@ final class EmailSendingService
/**
* @return array{success: bool, error: ?string, log_id: int}
*/
public function send(int $orderId, int $templateId, ?int $mailboxId = null, ?string $actorName = null): array
public function send(int $orderId, int $templateId, ?int $mailboxId = null, ?string $actorName = null, ?string $recipientEmailOverride = null, ?string $recipientNameOverride = null): array
{
$details = $this->orders->findDetails($orderId);
if ($details === null) {
@@ -48,12 +48,16 @@ final class EmailSendingService
return ['success' => false, 'error' => 'Brak skonfigurowanej skrzynki SMTP', 'log_id' => 0];
}
$recipientEmail = $this->findRecipientEmail($addresses);
$recipientEmail = $recipientEmailOverride !== null && $recipientEmailOverride !== ''
? $recipientEmailOverride
: $this->findRecipientEmail($addresses);
if ($recipientEmail === '') {
return ['success' => false, 'error' => 'Brak adresu e-mail kupujacego', 'log_id' => 0];
return ['success' => false, 'error' => 'Brak adresu e-mail odbiorcy', 'log_id' => 0];
}
$recipientName = $this->findRecipientName($addresses);
$recipientName = $recipientNameOverride !== null && $recipientNameOverride !== ''
? $recipientNameOverride
: $this->findRecipientName($addresses);
$companySettings = $this->loadCompanySettings();
$variableMap = $this->variableResolver->buildVariableMap($order, $addresses, $companySettings);