# پایگاه داده — تسک ۱۴: پنل پیامکی ## جدول: sms_wallets | ستون | نوع | توضیح | |------|-----|-------| | id | INT UNSIGNED AUTO_INCREMENT PK | | | entity_type | VARCHAR(10) NOT NULL | `'doctor'` \| `'clinic'` | | entity_id | INT NOT NULL | | | balance_rials | INT NOT NULL DEFAULT 0 | موجودی فعلی | | created_at | INT NOT NULL | | | updated_at | INT NOT NULL | | | UNIQUE | (entity_type, entity_id) | یک wallet به ازای هر entity | ## جدول: sms_wallet_transactions | ستون | نوع | توضیح | |------|-----|-------| | id | INT UNSIGNED AUTO_INCREMENT PK | | | uuid | CHAR(36) UNIQUE NOT NULL | | | sms_wallet_id | INT NOT NULL FK→sms_wallets.id ON DELETE CASCADE | | | type | VARCHAR(10) NOT NULL | `'credit'` \| `'debit'` | | amount_rials | INT NOT NULL | مبلغ (همیشه مثبت) | | description | VARCHAR(255) NULL | توضیح | | payment_id | INT NULL FK→payments.id ON DELETE SET NULL | برای شارژ | | created_at | INT NOT NULL | | ایندکس: ```sql INDEX idx_sms_wallet_tx ON sms_wallet_transactions(sms_wallet_id, created_at) ``` ## جدول: sms_settings | ستون | نوع | توضیح | |------|-----|-------| | id | INT UNSIGNED AUTO_INCREMENT PK | | | entity_type | VARCHAR(10) NOT NULL | | | entity_id | INT NOT NULL | | | reminder_enabled | TINYINT(1) NOT NULL DEFAULT 0 | | | reminder_hours_before | TINYINT NOT NULL DEFAULT 2 | چند ساعت قبل از نوبت | | post_visit_enabled | TINYINT(1) NOT NULL DEFAULT 0 | | | post_visit_text | TEXT NULL | متن پیامک بعد از ویزیت | | updated_at | INT NOT NULL | | | UNIQUE | (entity_type, entity_id) | | ## SiteConfig key جدید | کلید | نوع | مقدار پیش‌فرض | توضیح | |------|-----|--------------|-------| | `sms_price_rials` | string | `'250'` | قیمت هر پیامک — ادمین تنظیم می‌کند | ## Migration نمونه ```sql CREATE TABLE sms_wallets ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, entity_type VARCHAR(10) NOT NULL, entity_id INT NOT NULL, balance_rials INT NOT NULL DEFAULT 0, created_at INT NOT NULL, updated_at INT NOT NULL, UNIQUE KEY uniq_sms_wallet_entity (entity_type, entity_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE sms_wallet_transactions ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, uuid CHAR(36) NOT NULL UNIQUE, sms_wallet_id INT NOT NULL, type VARCHAR(10) NOT NULL, amount_rials INT NOT NULL, description VARCHAR(255) NULL, payment_id INT NULL, created_at INT NOT NULL, FOREIGN KEY (sms_wallet_id) REFERENCES sms_wallets(id) ON DELETE CASCADE, FOREIGN KEY (payment_id) REFERENCES payments(id) ON DELETE SET NULL, INDEX idx_sms_wallet_tx (sms_wallet_id, created_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE sms_settings ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, entity_type VARCHAR(10) NOT NULL, entity_id INT NOT NULL, reminder_enabled TINYINT(1) NOT NULL DEFAULT 0, reminder_hours_before TINYINT NOT NULL DEFAULT 2, post_visit_enabled TINYINT(1) NOT NULL DEFAULT 0, post_visit_text TEXT NULL, updated_at INT NOT NULL, UNIQUE KEY uniq_sms_settings_entity (entity_type, entity_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``` ## نکات مهم - `balance_rials` هرگز منفی نمی‌شود — در `SmsWalletService::deduct()` چک می‌شود - `sms_wallet_transactions` لاگ کامل تمام تراکنش‌ها است — حذف نمی‌شود - `sms_settings` با UPSERT ذخیره می‌شود (اگر وجود نداشت INSERT، وگرنه UPDATE)