# پایگاه داده — تسک ۱۸: تسویه نماینده ## جدول: wallet_transactions (تراکنش‌های کیف پول) | ستون | نوع | توضیح | |------|-----|-------| | id | INT UNSIGNED AUTO_INCREMENT PK | | | uuid | CHAR(36) UNIQUE NOT NULL | | | representation_id | INT FK → representations.id NOT NULL | نماینده | | type | VARCHAR(10) NOT NULL | `credit` (واریز) یا `debit` (برداشت) | | amount | INT NOT NULL | مبلغ به ریال | | source | VARCHAR(20) NOT NULL | `appointment` یا `subscription` یا `settlement` | | source_id | INT NULL | FK به payments.id یا subscription_payments.id یا settlements.id | | description | VARCHAR(255) NULL | توضیح تراکنش | | created_at | INT NOT NULL | Unix timestamp | ```sql CREATE INDEX idx_wallet_representation ON wallet_transactions(representation_id); CREATE INDEX idx_wallet_type ON wallet_transactions(representation_id, type); CREATE INDEX idx_wallet_source ON wallet_transactions(source, source_id); ``` --- ## جدول: settlements (درخواست‌های تسویه) | ستون | نوع | توضیح | |------|-----|-------| | id | INT UNSIGNED AUTO_INCREMENT PK | | | uuid | CHAR(36) UNIQUE NOT NULL | | | representation_id | INT FK → representations.id NOT NULL | نماینده درخواست‌دهنده | | amount | INT NOT NULL | مبلغ درخواستی (ریال) | | card_number | VARCHAR(25) NOT NULL | شماره کارت بانکی برداشت | | bank_name | VARCHAR(50) NOT NULL | نام بانک | | status | VARCHAR(10) DEFAULT 'pending' | `pending` / `approved` / `rejected` | | description | VARCHAR(255) NULL | توضیح نماینده | | admin_note | VARCHAR(255) NULL | یادداشت ادمین هنگام تأیید/رد | | requested_at | INT NOT NULL | Unix timestamp — زمان درخواست | | resolved_at | INT NULL | Unix timestamp — زمان تأیید/رد | | created_at | INT NOT NULL | Unix timestamp | | updated_at | INT NOT NULL | Unix timestamp | ```sql CREATE INDEX idx_settlements_representation ON settlements(representation_id); CREATE INDEX idx_settlements_status ON settlements(status); CREATE UNIQUE INDEX idx_settlements_pending ON settlements(representation_id, status) WHERE status = 'pending'; -- این index یکتایی یک pending در هر زمان را enforce می‌کند ``` --- ## فیلد balance در representations جدول `representations` باید یک فیلد `balance` داشته باشد: | ستون | نوع | توضیح | |------|-----|-------| | balance | INT DEFAULT 0 | موجودی کیف پول (ریال) — همیشه sync با wallet_transactions | > **نکته:** `balance` باید همزمان با هر تراکنش در wallet_transactions آپدیت شود > تا query موجودی سریع باشد (بدون SUM روی wallet_transactions). --- ## فلوی واریز کمیسیون (هنگام پرداخت موفق) ``` payments.status → 'received' ↓ commission = payments.amount × (representation.commission_percent / 100) ↓ INSERT INTO wallet_transactions (representation_id, type='credit', amount=commission, source='appointment', source_id=payment.id) ↓ UPDATE representations SET balance = balance + commission WHERE id = representation_id ``` ## فلوی تسویه (هنگام تأیید ادمین) ``` PATCH /api/v1/settlement/{uuid}/approve ↓ بررسی: representations.balance >= settlements.amount ↓ INSERT INTO wallet_transactions (type='debit', amount=settlement.amount, source='settlement', source_id=settlement.id) ↓ UPDATE representations SET balance = balance - settlement.amount ↓ UPDATE settlements SET status='approved', resolved_at=NOW(), admin_note=... ```