arc/docs/quick-sales-customer-field-behavior.md

66 lines
8.1 KiB
Markdown

# رفتار فیلد مشتری در فروش سریع
این سند رفتار جست‌وجو، انتخاب و ثبت سریع مشتری در صفحهٔ فروش سریع را تعریف می‌کند. ثبت سریع با `enableQuickCreateOnSubmit` فقط برای نمونه‌های این فیلد در فروش سریع فعال است؛ سایر مصرف‌کنندگان `CustomerComboboxWidget` بدون درخواست صریح مشتری جدید ایجاد نمی‌کنند.
## رفتار Enter
ترتیب تصمیم‌گیری پس از زدن Enter به شکل زیر است:
1. اگر ورودی موبایل داشته باشد و کاربر ردیفی را با جهت‌نما مشخص نکرده باشد، ورودی مستقیماً برای تطبیق یا ثبت بر اساس موبایل به API ارسال می‌شود؛ نتیجهٔ جست‌وجوی عمومی مانع این کار نیست.
2. اگر ورودی فقط نام داشته باشد و نتایج متن فعلی هنوز بارگذاری نشده‌اند، ابتدا جست‌وجو کامل می‌شود.
3. اگر دقیقاً یک نتیجه وجود داشته باشد، همان مشتری انتخاب می‌شود.
4. اگر چند نتیجه وجود داشته باشد و کاربر با جهت‌نما ردیفی را مشخص کرده باشد، همان ردیف انتخاب می‌شود.
5. اگر چند نتیجه وجود داشته باشد و ردیفی صریحاً مشخص نشده باشد، API تطبیق دقیق و نتایج مشابه را بررسی می‌کند؛ نتیجه‌های مشابه در همان منوی شناور می‌مانند تا کاربر با جهت‌نما و Enter یا موس انتخاب کند.
6. اگر نتیجه‌ای وجود نداشته باشد، ورودی برای یافتن یا ساختن سریع مشتری به API ارسال می‌شود.
پاسخ جست‌وجوی قدیمی اجازه ندارد نتایج متن جدید را جایگزین کند. اولین ردیف نیز صرفاً به‌دلیل قرارگرفتن در ابتدای فهرست، انتخاب‌شده محسوب نمی‌شود.
## فوکوس و متن موقت
با اولین فوکوس روی فیلد، کل نام مشتری فعلی انتخاب می‌شود تا اولین حرف یا رقم، متن قبلی را جایگزین کند. کلیک بعدی در همان وضعیت فوکوس همچنان اجازه می‌دهد مکان‌نما در نقطه دلخواه قرار بگیرد.
متنی که کاربر تایپ می‌کند تا زمان انتخاب یا ثبت سریع، پیش‌نویس محلی است. تایپ عادی مشتری فعلی فاکتور را به مشتری ناشناس تغییر نمی‌دهد. تنها انتخاب صریح از فهرست یا پاسخ موفق ثبت سریع، مشتری فاکتور را تغییر می‌دهد.
Enter هنگام ثبت سریع فوکوس فیلد را تا دریافت پاسخ API نگه می‌دارد. اگر کاربر در این فاصله متن را تغییر ندهد یا مشتری دیگری انتخاب نکند، پاسخ موفق حتی در صورت خروج فوکوس نیز معتبر است و مشتری ساخته‌شده را روی فاکتور قرار می‌دهد. به این ترتیب بازگردانی متن مشتری قبلی نمی‌تواند نتیجهٔ ثبت موفق را خنثی کند.
## قالب‌های ورودی ثبت سریع
ورودی می‌تواند شامل نام، موبایل یا هر دو باشد. ترتیب نام و موبایل مهم نیست و تمام بخش نام به‌صورت یکپارچه در `alias_name` قرار می‌گیرد.
| ورودی | نام مستعار | موبایل |
|---|---|---|
| `علی رضایی` | `علی رضایی` | خالی |
| `09121234567` | `09121234567` | `09121234567` |
| `09121234567 سید محمد مهدی رضوی` | `سید محمد مهدی رضوی` | `09121234567` |
| `زهرا سادات موسوی +989121234567` | `زهرا سادات موسوی` | `09121234567` |
| `۰۹۱۲۱۲۳۴۵۶۷ کاظمی` | `کاظمی` | `09121234567` |
اعداد فارسی و عربی به انگلیسی تبدیل می‌شوند. قالب‌های `09xxxxxxxxx`، `9xxxxxxxxx`، `+989xxxxxxxxx`، `989xxxxxxxxx` و `00989xxxxxxxxx` پشتیبانی می‌شوند. فاصله و خط تیره داخل شماره نیز پذیرفته می‌شود. وجود بیش از یک موبایل معتبر، ورودی را مبهم می‌کند و ثبت خودکار انجام نمی‌شود.
در ورودی فقط موبایل، به‌دلیل الزامی‌بودن نام مستعار شخص، موبایل استانداردشده به‌عنوان نام مستعار نیز ذخیره می‌شود.
## جلوگیری از ثبت تکراری
API پیش از ایجاد شخص، کاندیداهای همان کسب‌وکار را با فیلتر موبایل/نام (با درنظرگرفتن حروف عربی/فارسی) از دیتابیس می‌گیرد و سپس دقیق تطبیق می‌دهد:
- موبایل پس از استانداردسازی با فیلدهای موبایل، موبایل دوم، موبایل سوم و تلفن مقایسه می‌شود.
- نام با یکسان‌سازی فاصله‌ها، نیم‌فاصله و حروف عربی/فارسی مقایسه می‌شود.
- نام مستعار، نام، نام خانوادگی، نام شرکت و ترکیب نام و نام خانوادگی در بررسی تشابه شرکت دارند.
- اگر ورودی موبایل داشته باشد، فقط همان موبایل استانداردشده معیار تکراری‌بودن است؛ نام یکسان یا مشابه بررسی نمی‌شود.
- اگر همان موبایل در هیچ‌یک از فیلدهای موبایل، موبایل دوم، موبایل سوم یا تلفن پیدا نشود، مشتری جدید حتی با نام کاملاً یکسان بدون هشدار ساخته می‌شود.
- اگر یک رکورد با همان موبایل پیدا شود، همان مشتری انتخاب می‌شود. چند رکورد با موبایل یکسان در فهرست می‌مانند تا کاربر انتخاب کند.
- در ورودی فقط نام، نام یکسان یا مشابه می‌تواند شخص موجود را برگرداند یا چند گزینه برای انتخاب نمایش دهد.
- در PostgreSQL، بررسی و ایجاد سریع برای هر کسب‌وکار با قفل تراکنشی سریالی می‌شود تا دو درخواست هم‌زمان رکورد تکراری نسازند.
- endpoint فقط برای اعضای همان کسب‌وکار مجاز است (`can_access_business`).
شخصی که واقعاً جدید باشد با نوع «مشتری» ساخته می‌شود و بدون بازشدن فرم شخص، برای فاکتور جاری انتخاب می‌شود.
در پیش‌نمایش وب محلی، اگر `API_BASE_URL` صریحاً تنظیم نشده باشد، درخواست‌ها به پورت `8000` همان میزبان ارسال می‌شوند؛ برای نمونه، رابط `192.168.50.101:8080` از API آدرس `192.168.50.101:8000` استفاده می‌کند. این fallback مانع ارسال اشتباه درخواست‌ها به وب‌سرور Flutter روی پورت ۸۰۸۰ و دریافت خطای `405 Method Not Allowed` می‌شود. در محیط‌های غیرمحلی، همان origin و reverse proxy برنامه استفاده می‌شود.
## مسیرهای پیاده‌سازی
- رابط و رفتار صفحه‌کلید: `hesabixUI/hesabix_ui/lib/widgets/invoice/customer_combobox_widget.dart`
- تجزیهٔ نام و موبایل: `hesabixUI/hesabix_ui/lib/utils/customer_quick_entry.dart`
- فراخوانی API: `hesabixUI/hesabix_ui/lib/services/customer_service.dart`
- endpoint: `POST /api/v1/customers/quick-resolve`
- منطق تطبیق و ایجاد: `hesabixAPI/app/services/customer_quick_entry_service.py`