feat: Add tagging system for SMS logs and templates

- Introduced a `tag` field in the `SmsLog` entity to categorize SMS messages.
- Updated the `SmsService` to handle the new `tag` parameter during SMS dispatch.
- Implemented a `SmsTextResolver` service to resolve SMS message templates based on tags.
- Created a new `SmsMessageTemplate` entity for editable SMS templates with placeholders.
- Added endpoints for managing SMS message templates in the admin panel.
- Enhanced existing SMS dispatching methods across various controllers to utilize the tagging system.
- Migrated the database to include the new `tag` field and created a seeding command for default SMS templates.
- Updated admin API to filter SMS logs by tag and include tag information in responses.
This commit is contained in:
hamed
2026-06-19 20:42:04 +03:30
parent da57c554c1
commit fa332f7fa1
22 changed files with 846 additions and 35 deletions
+96
View File
@@ -0,0 +1,96 @@
<?php
namespace App\Sms\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* متن ویرایش‌پذیرِ پیامک‌های سیستمی، کلیددار با تگ (SmsLog::TAG_*).
* body شامل placeholderهای {key} است که هنگام ارسال جایگزین می‌شوند.
*/
#[ORM\Entity]
#[ORM\Table(name: 'sms_message_templates')]
class SmsMessageTemplate
{
/**
* متن و متادیتای پیش‌فرض هر تگ — مرجع برای seed و fallback.
* @var array<string, array{title: string, body: string, variables: string[]}>
*/
public const DEFAULTS = [
SmsLog::TAG_OTP => [
'title' => 'کد تأیید ورود',
'body' => 'کد تأیید شما: {code}',
'variables' => ['code'],
],
SmsLog::TAG_PAYMENT => [
'title' => 'تأیید پرداخت و نوبت',
'body' => 'نوبت شما با {doctor} در تاریخ {date} ثبت و تأیید شد.',
'variables' => ['doctor', 'date'],
],
SmsLog::TAG_CLINIC_INVITATION => [
'title' => 'دعوت پزشک به کلینیک',
'body' => "دکتر گرامی، کلینیک {clinic} شما را برای همکاری دعوت کرده است.\nبرای بررسی: {link}\nاین لینک تا ۷۲ ساعت معتبر است.",
'variables' => ['clinic', 'link'],
],
SmsLog::TAG_PRE_REGISTRATION => [
'title' => 'پیش‌ثبت‌نام',
'body' => 'به کلینیک پرو خوش آمدید! شماره‌کاربری: {username} | رمز عبور: {password} | لینک ورود: {link}',
'variables' => ['username', 'password', 'link'],
],
SmsLog::TAG_NOTIFICATION_MOBILE => [
'title' => 'تأیید شماره اعلان',
'body' => "کد تأیید شماره اعلان شما: {code}\nاعتبار: ۵ دقیقه",
'variables' => ['code'],
],
];
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private ?int $id = null;
#[ORM\Column(type: 'string', length: 30, unique: true)]
private string $tag;
#[ORM\Column(type: 'string', length: 100)]
private string $title;
#[ORM\Column(type: 'text')]
private string $body;
#[ORM\Column(type: 'json')]
private array $variables = [];
#[ORM\Column(name: 'updated_at', type: 'integer')]
private int $updatedAt;
public function __construct(string $tag, string $title, string $body, array $variables = [])
{
$this->tag = $tag;
$this->title = $title;
$this->body = $body;
$this->variables = $variables;
$this->updatedAt = time();
}
public function getId(): ?int { return $this->id; }
public function getTag(): string { return $this->tag; }
public function getTitle(): string { return $this->title; }
public function getBody(): string { return $this->body; }
public function getVariables(): array { return $this->variables; }
public function getUpdatedAt(): int { return $this->updatedAt; }
public function setTitle(string $v): self { $this->title = $v; $this->updatedAt = time(); return $this; }
public function setBody(string $v): self { $this->body = $v; $this->updatedAt = time(); return $this; }
public function toArray(): array
{
return [
'tag' => $this->tag,
'title' => $this->title,
'body' => $this->body,
'variables' => $this->variables,
'updated_at' => $this->updatedAt,
];
}
}