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>
278 lines
8.4 KiB
PHP
278 lines
8.4 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Modules\Automation;
|
|
|
|
use PDO;
|
|
use Throwable;
|
|
|
|
final class AutomationRepository
|
|
{
|
|
public function __construct(
|
|
private readonly PDO $pdo
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* @return list<array<string, mixed>>
|
|
*/
|
|
public function findAll(): array
|
|
{
|
|
$sql = '
|
|
SELECT r.id, r.name, r.event_type, r.is_active, r.created_at, r.updated_at,
|
|
(SELECT COUNT(*) FROM automation_conditions WHERE rule_id = r.id) AS conditions_count,
|
|
(SELECT COUNT(*) FROM automation_actions WHERE rule_id = r.id) AS actions_count
|
|
FROM automation_rules r
|
|
ORDER BY r.created_at DESC
|
|
';
|
|
$statement = $this->pdo->prepare($sql);
|
|
$statement->execute();
|
|
$rows = $statement->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
return is_array($rows) ? $rows : [];
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>|null
|
|
*/
|
|
public function findById(int $id): ?array
|
|
{
|
|
$statement = $this->pdo->prepare('SELECT * FROM automation_rules WHERE id = :id LIMIT 1');
|
|
$statement->execute(['id' => $id]);
|
|
$rule = $statement->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!is_array($rule)) {
|
|
return null;
|
|
}
|
|
|
|
$rule['conditions'] = $this->loadConditions($id);
|
|
$rule['actions'] = $this->loadActions($id);
|
|
|
|
return $rule;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $data
|
|
* @param list<array<string, mixed>> $conditions
|
|
* @param list<array<string, mixed>> $actions
|
|
*/
|
|
public function create(array $data, array $conditions, array $actions): int
|
|
{
|
|
$this->pdo->beginTransaction();
|
|
|
|
try {
|
|
$statement = $this->pdo->prepare(
|
|
'INSERT INTO automation_rules (name, event_type, is_active)
|
|
VALUES (:name, :event_type, :is_active)'
|
|
);
|
|
$statement->execute([
|
|
'name' => $data['name'],
|
|
'event_type' => $data['event_type'],
|
|
'is_active' => (int) ($data['is_active'] ?? 1),
|
|
]);
|
|
|
|
$ruleId = (int) $this->pdo->lastInsertId();
|
|
|
|
$this->insertConditions($ruleId, $conditions);
|
|
$this->insertActions($ruleId, $actions);
|
|
|
|
$this->pdo->commit();
|
|
|
|
return $ruleId;
|
|
} catch (Throwable $e) {
|
|
$this->pdo->rollBack();
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $data
|
|
* @param list<array<string, mixed>> $conditions
|
|
* @param list<array<string, mixed>> $actions
|
|
*/
|
|
public function update(int $id, array $data, array $conditions, array $actions): bool
|
|
{
|
|
$this->pdo->beginTransaction();
|
|
|
|
try {
|
|
$statement = $this->pdo->prepare(
|
|
'UPDATE automation_rules SET name = :name, event_type = :event_type, is_active = :is_active WHERE id = :id'
|
|
);
|
|
$statement->execute([
|
|
'id' => $id,
|
|
'name' => $data['name'],
|
|
'event_type' => $data['event_type'],
|
|
'is_active' => (int) ($data['is_active'] ?? 1),
|
|
]);
|
|
|
|
$this->pdo->prepare('DELETE FROM automation_conditions WHERE rule_id = :id')->execute(['id' => $id]);
|
|
$this->pdo->prepare('DELETE FROM automation_actions WHERE rule_id = :id')->execute(['id' => $id]);
|
|
|
|
$this->insertConditions($id, $conditions);
|
|
$this->insertActions($id, $actions);
|
|
|
|
$this->pdo->commit();
|
|
|
|
return true;
|
|
} catch (Throwable $e) {
|
|
$this->pdo->rollBack();
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
public function delete(int $id): void
|
|
{
|
|
$statement = $this->pdo->prepare('DELETE FROM automation_rules WHERE id = :id');
|
|
$statement->execute(['id' => $id]);
|
|
}
|
|
|
|
public function toggleActive(int $id): void
|
|
{
|
|
$statement = $this->pdo->prepare(
|
|
'UPDATE automation_rules SET is_active = NOT is_active WHERE id = :id'
|
|
);
|
|
$statement->execute(['id' => $id]);
|
|
}
|
|
|
|
/**
|
|
* @return list<array<string, mixed>>
|
|
*/
|
|
public function findActiveByEvent(string $eventType): array
|
|
{
|
|
$statement = $this->pdo->prepare(
|
|
'SELECT id, name, event_type FROM automation_rules WHERE event_type = :event_type AND is_active = 1'
|
|
);
|
|
$statement->execute(['event_type' => $eventType]);
|
|
$rules = $statement->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
if (!is_array($rules)) {
|
|
return [];
|
|
}
|
|
|
|
foreach ($rules as &$rule) {
|
|
$ruleId = (int) $rule['id'];
|
|
$rule['conditions'] = $this->loadConditions($ruleId);
|
|
$rule['actions'] = $this->loadActions($ruleId);
|
|
}
|
|
unset($rule);
|
|
|
|
return $rules;
|
|
}
|
|
|
|
/**
|
|
* @return list<array{id: int, type: string, name: string}>
|
|
*/
|
|
public function listOrderIntegrations(): array
|
|
{
|
|
$statement = $this->pdo->prepare(
|
|
"SELECT id, type, name FROM integrations WHERE type IN ('allegro', 'shoppro') AND is_active = 1 ORDER BY type, name"
|
|
);
|
|
$statement->execute();
|
|
$rows = $statement->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
return is_array($rows) ? $rows : [];
|
|
}
|
|
|
|
/**
|
|
* @return list<array{id: int, name: string}>
|
|
*/
|
|
public function listEmailTemplates(): array
|
|
{
|
|
$statement = $this->pdo->prepare(
|
|
'SELECT id, name FROM email_templates WHERE is_active = 1 ORDER BY name'
|
|
);
|
|
$statement->execute();
|
|
$rows = $statement->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
return is_array($rows) ? $rows : [];
|
|
}
|
|
|
|
/**
|
|
* @return list<array<string, mixed>>
|
|
*/
|
|
private function loadConditions(int $ruleId): array
|
|
{
|
|
$statement = $this->pdo->prepare(
|
|
'SELECT id, condition_type, condition_value, sort_order FROM automation_conditions WHERE rule_id = :rule_id ORDER BY sort_order'
|
|
);
|
|
$statement->execute(['rule_id' => $ruleId]);
|
|
$rows = $statement->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
if (!is_array($rows)) {
|
|
return [];
|
|
}
|
|
|
|
foreach ($rows as &$row) {
|
|
$decoded = json_decode((string) ($row['condition_value'] ?? '{}'), true);
|
|
$row['condition_value'] = is_array($decoded) ? $decoded : [];
|
|
}
|
|
unset($row);
|
|
|
|
return $rows;
|
|
}
|
|
|
|
/**
|
|
* @return list<array<string, mixed>>
|
|
*/
|
|
private function loadActions(int $ruleId): array
|
|
{
|
|
$statement = $this->pdo->prepare(
|
|
'SELECT id, action_type, action_config, sort_order FROM automation_actions WHERE rule_id = :rule_id ORDER BY sort_order'
|
|
);
|
|
$statement->execute(['rule_id' => $ruleId]);
|
|
$rows = $statement->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
if (!is_array($rows)) {
|
|
return [];
|
|
}
|
|
|
|
foreach ($rows as &$row) {
|
|
$decoded = json_decode((string) ($row['action_config'] ?? '{}'), true);
|
|
$row['action_config'] = is_array($decoded) ? $decoded : [];
|
|
}
|
|
unset($row);
|
|
|
|
return $rows;
|
|
}
|
|
|
|
/**
|
|
* @param list<array<string, mixed>> $conditions
|
|
*/
|
|
private function insertConditions(int $ruleId, array $conditions): void
|
|
{
|
|
$statement = $this->pdo->prepare(
|
|
'INSERT INTO automation_conditions (rule_id, condition_type, condition_value, sort_order)
|
|
VALUES (:rule_id, :condition_type, :condition_value, :sort_order)'
|
|
);
|
|
|
|
foreach ($conditions as $index => $condition) {
|
|
$statement->execute([
|
|
'rule_id' => $ruleId,
|
|
'condition_type' => $condition['type'],
|
|
'condition_value' => json_encode($condition['value'], JSON_UNESCAPED_UNICODE),
|
|
'sort_order' => $index,
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param list<array<string, mixed>> $actions
|
|
*/
|
|
private function insertActions(int $ruleId, array $actions): void
|
|
{
|
|
$statement = $this->pdo->prepare(
|
|
'INSERT INTO automation_actions (rule_id, action_type, action_config, sort_order)
|
|
VALUES (:rule_id, :action_type, :action_config, :sort_order)'
|
|
);
|
|
|
|
foreach ($actions as $index => $action) {
|
|
$statement->execute([
|
|
'rule_id' => $ruleId,
|
|
'action_type' => $action['type'],
|
|
'action_config' => json_encode($action['config'], JSON_UNESCAPED_UNICODE),
|
|
'sort_order' => $index,
|
|
]);
|
|
}
|
|
}
|
|
}
|