Files
CRM_Montzar/docs/MONTACT_CRM_INTEGRATION.md
T

439 lines
17 KiB
Markdown
Raw Normal View History

# راهنمای اتصال CRM (MONTACT) به Montify — نسخه کامل v2
## ۱. خلاصه و دیاگرام جریان
این سند مشخصات اتصال سامانه **Montact CRM** به زیرسیستم‌های فروشگاهی (مانند Montify) را تعریف می‌کند. هر فروشگاه یک `Base URL` و یک `Token` اختصاصی دارد.
```
[فروشنده/Store] → [پنل Montify] → [صدور Token] → [سرور CRM]
│
▼
GET {Base URL}/montact/customers
│
▼
پاسخ JSON (لیست مشتریان)
│
▼
GET {Base URL}/montact/customers/:id/orders
│
▼
پاسخ JSON (سفارش‌های مشتری)
```
## ۲. دریافت اطلاعات اتصال از فروشنده
1. فروشنده وارد پنل Montify می‌شود.
2. از مسیر «تنظیمات → یکپارچه‌سازی‌ها → CRM» وارد بخش Montact می‌شود.
3. دکمه «صدور Token» را می‌زند و مقادیر زیر را در اختیار تیم CRM قرار می‌دهد:
| فیلد | مقدار نمونه | توضیح |
|---|---|---|
| Base URL | `https://store1.montify.com/api/v1` | آدرس پایه API فروشگاه |
| Token | `mk_live_8f3a1c9d2e...` | توکن احراز هویت Bearer |
| Store ID | `b2f1e4a0-...` | شناسه فروشگاه |
> **نکته:** توکن‌ها می‌توانند منقضی شوند (`expires_at`). در صورت دریافت خطای ۴۰۱، باید توکن جدید از فروشنده درخواست شود. توکن هرگز نباید در فرانت‌اند ذخیره یا افشا شود؛ تنها باید در سرور CRM نگهداری گردد.
## ۳. احراز هویت
تمام درخواست‌ها باید هدرهای زیر را داشته باشند:
```http
Authorization: Bearer {Token}
Content-Type: application/json
Accept: application/json
```
## ۴. فهرست کامل APIها
| Method | Path | توضیح |
|---|---|---|
| GET | `/montact/customers` | لیست مشتریان (پشتیبانی از `page`, `limit`, `updated_after`) |
| POST | `/montact/customers` | ثبت/همگام‌سازی مشتری از سمت CRM (اختیاری) |
| GET | `/montact/customers/:id` | جزئیات کامل یک مشتری |
| GET | `/montact/customers/:id/orders` | لیست سفارش‌های مشتری (پشتیبانی از `updated_after`) |
| POST | `/montact/customers/:id/orders` | ثبت سفارش از CRM (اختیاری، در صورت فعال بودن) |
| GET | `/montact/customers/:id/addresses` | لیست آدرس‌های مشتری |
| GET | `/montact/customers/:id/transactions` | لیست تراکنش‌های مالی مشتری |
| GET | `/montact/customers/:id/engagement` | داده‌های تعاملی (`saved`, `likes`, `comments`) |
| GET | `/montact/orders/:orderId` | جزئیات یک سفارش خاص |
| POST | `/montact/webhooks/register` | ثبت Webhook برای رویدادهای بلادرنگ (فاز ۳) |
| GET | `/montact/webhooks/:id` | مشاهده جزئیات یک Webhook ثبت‌شده |
| DELETE | `/montact/webhooks/:id` | حذف Webhook |
> پارامتر `updated_after` یک مقدار ISO 8601 است (مثلاً `2026-07-01T00:00:00Z`) و فقط رکوردهای تغییر یافته بعد از آن زمان را برمی‌گرداند (برای Incremental Sync).
### نمونه‌های curl
```bash
BASE="https://store1.montify.com/api/v1"
TOKEN="mk_live_8f3a1c9d2e..."
# لیست مشتریان
curl -X GET "$BASE/montact/customers?page=1&limit=50" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json"
# لیست مشتریان تغییریافته بعد از یک زمان خاص (Incremental Sync)
curl -X GET "$BASE/montact/customers?updated_after=2026-07-01T00:00:00Z" \
-H "Authorization: Bearer $TOKEN"
# جزئیات یک مشتری
curl -X GET "$BASE/montact/customers/123" \
-H "Authorization: Bearer $TOKEN"
# سفارش‌های یک مشتری
curl -X GET "$BASE/montact/customers/123/orders?updated_after=2026-07-01T00:00:00Z" \
-H "Authorization: Bearer $TOKEN"
# آدرس‌های مشتری
curl -X GET "$BASE/montact/customers/123/addresses" \
-H "Authorization: Bearer $TOKEN"
# تراکنش‌های مشتری
curl -X GET "$BASE/montact/customers/123/transactions" \
-H "Authorization: Bearer $TOKEN"
# داده‌های تعاملی مشتری
curl -X GET "$BASE/montact/customers/123/engagement" \
-H "Authorization: Bearer $TOKEN"
# جزئیات یک سفارش خاص
curl -X GET "$BASE/montact/orders/4567" \
-H "Authorization: Bearer $TOKEN"
# ثبت Webhook (فاز ۳)
curl -X POST "$BASE/montact/webhooks/register" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"url":"https://crm.montact.com/webhooks/montify","events":["order.created","order.paid"]}'
```
## ۵. ساختار پاسخ کامل
### ۵.۱ فیلدهای مشتری (Customer)
| فیلد | نوع | توضیح |
|---|---|---|
| id | integer | شناسه مشتری |
| name | string | نام کامل |
| first_name | string | نام |
| last_name | string | نام خانوادگی |
| phone | string | شماره موبایل |
| email | string\|null | ایمیل |
| username | string | نام کاربری |
| avatar | string\|null | URL آواتار |
| birthday | date\|null | تاریخ تولد |
| gender | string\|null | جنسیت |
| type | string | نوع مشتری (حقیقی/حقوقی) |
| store_id | integer | شناسه فروشگاه |
| created_at | datetime | تاریخ ایجاد |
| updated_at | datetime | آخرین بروزرسانی |
| description | string\|null | توضیحات |
| bio | string\|null | بیوگرافی |
| job | string\|null | شغل |
| cash_balance | number | موجودی نقدی |
| gold_balance | number | موجودی طلا (گرم) |
| orders | array | لیست سفارش‌ها |
| summary | object | خلاصه آماری مشتری |
| addresses | array | لیست آدرس‌ها |
| transactions | array | لیست تراکنش‌ها |
| engagement | object | داده‌های تعاملی |
### ۵.۲ فیلدهای سفارش (Order)
| فیلد | نوع | توضیح |
|---|---|---|
| id | integer | شناسه سفارش |
| user_id | integer | شناسه مشتری |
| store_id | integer | شناسه فروشگاه |
| code | string | کد پیگیری سفارش |
| sts | string | وضعیت سفارش |
| payment_sts | string | وضعیت پرداخت |
| payment_type | string | نوع پرداخت |
| total_price | number | قیمت کل |
| discount_total_price | number | قیمت پس از تخفیف |
| total_discounts | number | مجموع تخفیف‌ها |
| total_tax | number | مجموع مالیات |
| total_qty | integer | تعداد کل اقلام |
| profit | number | سود |
| percent_profit | number | درصد سود |
| sum_gold | number | مجموع وزن طلا |
| sum_silver | number | مجموع وزن نقره |
| address | object | آدرس ارسال |
| address_id | integer | شناسه آدرس |
| note | string\|null | یادداشت |
| cancel_reason | string\|null | دلیل لغو |
| cancelled_at | datetime\|null | تاریخ لغو |
| closed_at | datetime\|null | تاریخ بستن سفارش |
| transaction_id | integer\|null | شناسه تراکنش مرتبط |
| code_discount | string\|null | کد تخفیف |
| discount_code_id | integer\|null | شناسه کد تخفیف |
| created_at | datetime | تاریخ ایجاد |
| updated_at | datetime | آخرین بروزرسانی |
| deleted_at | datetime\|null | تاریخ حذف نرم |
| order_items | array | اقلام سفارش |
| user | object | اطلاعات خلاصه مشتری |
| store | object | اطلاعات خلاصه فروشگاه |
### ۵.۳ اقلام سفارش (Order Items)
| فیلد | نوع | توضیح |
|---|---|---|
| id | integer | شناسه قلم سفارش |
| order_id | integer | شناسه سفارش |
| product_id | integer | شناسه محصول |
| product_name | string | نام محصول |
| qty | integer | تعداد |
| price | number | قیمت واحد |
| weight | number | وزن (گرم) |
| total_price | number | قیمت کل قلم |
### ۵.۴ آدرس‌ها (Addresses)
| فیلد | نوع | توضیح |
|---|---|---|
| id | integer | شناسه آدرس |
| user_id | integer | شناسه مشتری |
| province | string | استان |
| city | string | شهر |
| address | string | متن آدرس |
| postal_code | string | کد پستی |
| receiver_name | string | نام گیرنده |
| receiver_phone | string | شماره گیرنده |
| is_default | boolean | آدرس پیش‌فرض |
### ۵.۵ تراکنش‌ها (Transactions)
| فیلد | نوع | توضیح |
|---|---|---|
| id | integer | شناسه تراکنش |
| user_id | integer | شناسه مشتری |
| type | string | نوع تراکنش (واریز/برداشت) |
| amount | number | مقدار |
| currency | string | واحد (ریال/گرم طلا) |
| status | string | وضعیت تراکنش |
| reference_code | string | کد پیگیری بانکی |
| created_at | datetime | تاریخ ثبت |
### ۵.۶ داده‌های تعاملی (Engagement)
مسیر: `GET /montact/customers/:id/engagement`
```json
{
"saved": [
{ "product_id": 55, "product_name": "سکه بهار آزادی", "saved_at": "2026-06-10T11:22:00Z" }
],
"likes": [
{ "product_id": 78, "liked_at": "2026-06-15T09:00:00Z" }
],
"comments": [
{
"id": 301,
"product_id": 78,
"text": "کیفیت عالی بود",
"rating": 5,
"created_at": "2026-06-16T08:30:00Z"
}
]
}
```
### ۵.۷ نمونه پاسخ JSON کامل لیست مشتریان
```json
{
"data": [
{
"id": 123,
"name": "علی رضایی",
"first_name": "علی",
"last_name": "رضایی",
"phone": "09121234567",
"email": "ali@example.com",
"username": "ali_r",
"avatar": "https://cdn.montify.com/avatars/123.png",
"birthday": "1990-05-12",
"gender": "male",
"type": "individual",
"store_id": 10,
"created_at": "2025-01-10T08:00:00Z",
"updated_at": "2026-07-01T10:15:00Z",
"description": null,
"bio": null,
"job": "مهندس",
"cash_balance": 1500000,
"gold_balance": 2.35,
"orders": [],
"summary": { "total_orders": 12, "total_spent": 85000000 },
"addresses": [],
"transactions": [],
"engagement": { "saved": [], "likes": [], "comments": [] }
}
],
"meta": {
"current_page": 1,
"per_page": 50,
"total": 532,
"last_page": 11
}
}
```
## ۶. قوانین نگاشت پیشنهادی در CRM
| فیلد Montify | فیلد معادل در CRM |
|---|---|
| id | external_customer_id |
| name | full_name |
| phone | mobile |
| cash_balance | wallet_balance |
| gold_balance | gold_wallet_balance |
| orders[].code | order_reference |
| orders[].sts | order_status |
**استراتژی Sync گام به گام:**
1. دریافت لیست مشتریان صفحه‌بندی‌شده و Upsert در جدول مشتریان CRM بر اساس `id`.
2. برای هر مشتری، دریافت سفارش‌ها، آدرس‌ها و تراکنش‌ها به‌صورت جداگانه و Upsert در جداول مرتبط.
3. ذخیره `updated_at` هر رکورد برای استفاده در Sync افزایشی بعدی.
## ۷. استراتژی Sync سه‌فازی
### فاز ۱ — Polling ساده
- فراخوانی دوره‌ای `/montact/customers` با `page` و `limit`.
- فاصله پیشنهادی: هر ۵ تا ۱۵ دقیقه (بسته به حجم داده فروشگاه).
- در صورت دریافت `429 Too Many Requests`، باید بر اساس هدر `Retry-After` صبر و تلاش مجدد شود.
### فاز ۲ — Incremental Sync
- استفاده از `updated_after=<ISO8601>` روی `/montact/customers` و `/montact/customers/:id/orders`.
- CRM باید مقدار `last_sync_timestamp` را پس از هر Sync موفق ذخیره کند و در فراخوانی بعدی به‌عنوان `updated_after` ارسال کند.
```bash
curl -X GET "$BASE/montact/customers?updated_after=2026-07-10T12:00:00Z" \
-H "Authorization: Bearer $TOKEN"
```
### فاز ۳ — Webhook (Push-based، بلادرنگ)
برای دریافت رویدادها بدون تأخیر Polling، CRM باید یک Endpoint عمومی HTTPS در اختیار Montify قرار دهد:
```bash
curl -X POST "$BASE/montact/webhooks/register" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://crm.montact.com/webhooks/montify",
"events": ["customer.created", "customer.updated", "order.created", "order.updated", "order.paid", "order.cancelled"]
}'
```
**رویدادهای پشتیبانی‌شده:**
| رویداد | توضیح |
|---|---|
| customer.created | ایجاد مشتری جدید |
| customer.updated | بروزرسانی اطلاعات مشتری |
| order.created | ثبت سفارش جدید |
| order.updated | تغییر در سفارش |
| order.paid | پرداخت سفارش |
| order.cancelled | لغو سفارش |
**نمونه Payload برای `order.created`:**
```json
{
"event": "order.created",
"delivery_id": "d2f1c9e0-84a3-4b7f-9c1e-3a2b1c0d9e8f",
"store_id": 10,
"data": {
"id": 4567,
"user_id": 123,
"code": "ORD-2026-4567",
"sts": "pending",
"payment_sts": "unpaid",
"total_price": 12500000,
"total_qty": 2,
"created_at": "2026-07-10T12:05:00Z"
}
}
```
**هدرهای ارسالی Webhook:**
```http
X-Montact-Signature: sha256=3b4f9a1c7e8d2f...
X-Montact-Event: order.created
X-Montact-Delivery-Id: d2f1c9e0-84a3-4b7f-9c1e-3a2b1c0d9e8f
Content-Type: application/json
```
**وریفای امضا (Node.js):**
```javascript
const crypto = require('crypto');
function verifySignature(rawBody, signatureHeader, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
const received = signatureHeader.replace('sha256=', '');
return crypto.timingSafeEqual(
Buffer.from(expected, 'hex'),
Buffer.from(received, 'hex')
);
}
```
**Retry Policy:**
- در صورت عدم دریافت پاسخ `2xx` ظرف ۱۰ ثانیه، تلاش مجدد با backoff نمایی انجام می‌شود.
- فاصله تلاش‌ها: `1s → 5s → 15s → 60s → 300s` (حداکثر ۵ بار).
- CRM باید سریعاً `200 OK` برگرداند و پردازش سنگین را به‌صورت async انجام دهد.
- Idempotency بر اساس `X-Montact-Delivery-Id` باید رعایت شود تا پردازش تکراری رخ ندهد.
## ۸. کدهای خطا
| کد HTTP | معنی | اقدام پیشنهادی |
|---|---|---|
| 200 | موفق | - |
| 400 | درخواست نامعتبر | بررسی پارامترها |
| 401 | توکن نامعتبر یا منقضی | درخواست توکن جدید از فروشنده |
| 403 | عدم دسترسی به منبع | بررسی scope توکن |
| 404 | منبع یافت نشد | بررسی شناسه ارسالی |
| 429 | تعداد درخواست بیش از حد مجاز | توجه به هدر `Retry-After` و کاهش نرخ درخواست |
| 500 | خطای سرور | تلاش مجدد بعد از فاصله زمانی |
## ۹. محدودیت‌ها و رفتار فعلی
- API برای داده‌های اصلی (مشتری، سفارش، آدرس، تراکنش) صرفاً **خواندنی (Read-only)** است؛ تنها استثنا ثبت/حذف Webhook است.
- فیلدهای حساس (مانند رمز عبور، هش‌های داخلی) از پاسخ‌ها حذف شده‌اند.
- CORS برای دامنه‌های مجاز CRM فعال است.
- نرخ مجاز درخواست پیشنهادی: **۱۰۰ درخواست در دقیقه به ازای هر Token**.
## ۱۰. چک‌لیست اتصال برنامه‌نویس CRM
- [ ] دریافت `Base URL`، `Token` و `Store ID` از فروشنده
- [ ] تست احراز هویت با `GET /montact/customers`
- [ ] پیاده‌سازی Polling فاز ۱
- [ ] پیاده‌سازی Incremental Sync با `updated_after` (فاز ۲)
- [ ] ثبت Webhook Endpoint و تست دریافت رویداد (فاز ۳)
- [ ] پیاده‌سازی وریفای امضای HMAC-SHA256
- [ ] تست Idempotency بر اساس `X-Montact-Delivery-Id`
- [ ] مدیریت خطاهای ۴۰۱/۴۲۹ و Retry مناسب
- [ ] ذخیره امن Token در سمت سرور (نه فرانت‌اند)
## ۱۱. پشتیبانی
برای ارسال تیکت پشتیبانی، اطلاعات زیر لازم است:
- `Store ID`
- زمان دقیق درخواست (UTC)
- کد خطای دریافتی
- `X-Montact-Delivery-Id` (در صورت مرتبط بودن به Webhook)
- نمونه Request/Response (بدون افشای Token کامل)