Watch
1
0
Fork
You've already forked Seyyed_arc
0
forked from hesabix/arc
Seyyed_arc/hesabixAPI/docs/WAREHOUSE_MIGRATION_ANALYSIS.md
2026-04-14 19:34:55 +03:30

346 lines
14 KiB
Markdown
Executable file

# تحلیل انتقال بخش انبارها
## 1. بررسی ساختار جداول
### 1.1. دیتابیس قدیمی (hesabixOld)
#### جدول `storeroom` (انبارها)
- **id**: شناسه انبار
- **bid_id**: شناسه کسب و کار
- **name**: نام انبار
- **manager**: نام انباردار
- **adr**: آدرس
- **tel**: تلفن
- **active**: فعال/غیرفعال
**آمار:**
- تعداد کل انبارها: **1,185**
- تعداد کسب و کارهای دارای انبار: **924**
#### جدول `storeroom_ticket` (اسناد انبار)
- **id**: شناسه سند
- **bid_id**: شناسه کسب و کار
- **submitter_id**: شناسه کاربر ایجادکننده
- **person_id**: شناسه شخص (مشتری/تامین‌کننده)
- **doc_id**: شناسه فاکتور مرتبط
- **year_id**: شناسه سال مالی
- **storeroom_id**: شناسه انبار
- **transfer_type_id**: شناسه نوع انتقال (ارجاع به `storeroom_transfer_type`)
- **date**: تاریخ سند (فرمت: 1402/08/27)
- **date_submit**: تاریخ ثبت (timestamp)
- **transfer**: نام انتقال‌دهنده
- **receiver**: نام دریافت‌کننده
- **code**: کد سند
- **type**: نوع سند (`input` یا `output`)
- **referral**: ارجاع
- **type_string**: نوع سند به فارسی (مثل "حواله ورود"، "حواله خروج")
- **des**: توضیحات
- **sender_tel**: تلفن فرستنده
- **can_share**: قابل اشتراک‌گذاری
- **import_workflow_code**: کد workflow واردات
- **activation_code**: کد فعال‌سازی
- **is_preview**: پیش‌نمایش
- **is_approved**: تایید شده
- **completed**: تکمیل شده
- **completed_at**: تاریخ تکمیل
- **approved_by_id**: شناسه تاییدکننده
- **completed_by_id**: شناسه تکمیل‌کننده
**آمار:**
- تعداد کل اسناد: **4,564**
- `input`: 1,511
- `output`: 3,053
#### جدول `storeroom_item` (آیتم‌های سند انبار)
- **id**: شناسه آیتم
- **ticket_id**: شناسه سند انبار
- **commodity_id**: شناسه کالا
- **bid_id**: شناسه کسب و کار
- **storeroom_id**: شناسه انبار
- **type**: نوع (`input` یا `output`)
- **count**: تعداد (varchar)
- **des**: توضیحات
- **referal**: ارجاع
**آمار:**
- تعداد کل آیتم‌ها: **12,645**
- `input`: 5,359
- `output`: 7,286
#### جدول `storeroom_transfer_type` (نوع انتقال)
- **id**: شناسه
- **name**: نام (مثل "تحویل درب انبار"، "پست عادی"، "پست پیشتاز"، "باربری"، "اتوبوس"، "تیپاکس"، "پیک")
### 1.2. دیتابیس جدید (hesabixpy)
#### جدول `warehouses` (انبارها)
- **id**: شناسه انبار
- **business_id**: شناسه کسب و کار
- **code**: کد یکتا در هر کسب و کار (varchar(64))
- **name**: نام انبار (varchar(255))
- **description**: توضیحات (text)
- **warehouse_keeper**: نام انباردار (varchar(255))
- **phone**: تلفن (varchar(32))
- **address**: آدرس (text)
- **postal_code**: کد پستی (varchar(16))
- **is_default**: انبار پیش‌فرض (boolean)
- **created_at**: تاریخ ایجاد
- **updated_at**: تاریخ به‌روزرسانی
**محدودیت‌ها:**
- `UNIQUE(business_id, code)`: کد باید در هر کسب و کار یکتا باشد
#### جدول `warehouse_documents` (اسناد انبار)
- **id**: شناسه سند
- **business_id**: شناسه کسب و کار
- **fiscal_year_id**: شناسه سال مالی
- **code**: کد سند (varchar(64), UNIQUE)
- **document_date**: تاریخ سند (date)
- **status**: وضعیت (`draft`|`posted`|`cancelled`)
- **doc_type**: نوع سند (`receipt`|`issue`|`transfer`|`production_in`|`production_out`|`adjustment`)
- **warehouse_id_from**: شناسه انبار مبدا (برای transfer)
- **warehouse_id_to**: شناسه انبار مقصد (برای transfer)
- **source_type**: نوع منبع (`invoice`|`manual`|`api`)
- **source_document_id**: شناسه سند منبع
- **extra_info**: اطلاعات اضافی (JSON)
- **created_by_user_id**: شناسه کاربر ایجادکننده
- **created_at**: تاریخ ایجاد
- **updated_at**: تاریخ به‌روزرسانی
#### جدول `warehouse_document_lines` (خطوط سند انبار)
- **id**: شناسه خط
- **warehouse_document_id**: شناسه سند انبار
- **product_id**: شناسه کالا
- **warehouse_id**: شناسه انبار
- **movement**: نوع حرکت (`in`|`out`)
- **quantity**: تعداد (decimal(18,6))
- **cost_price**: قیمت تمام شده (decimal(18,6))
- **cogs_amount**: مبلغ COGS (decimal(18,6))
- **extra_info**: اطلاعات اضافی (JSON)
- **instance_ids**: لیست ID کالاهای یونیک (JSON)
## 2. نگاشت فیلدها
### 2.1. انبارها (storeroom → warehouses)
| فیلد قدیمی | فیلد جدید | توضیحات |
|------------|-----------|---------|
| `id` | - | استفاده نمی‌شود (ایجاد جدید) |
| `bid_id` | `business_id` | نیاز به mapping |
| `name` | `name` | مستقیم |
| `manager` | `warehouse_keeper` | مستقیم |
| `adr` | `address` | مستقیم |
| `tel` | `phone` | مستقیم |
| `active` | - | فقط انبارهای active منتقل می‌شوند |
| - | `code` | باید تولید شود (مثلاً از name یا id) |
| - | `description` | می‌تواند از name یا address استفاده کند |
| - | `postal_code` | NULL |
| - | `is_default` | اولین انبار هر کسب و کار = true |
### 2.2. اسناد انبار (storeroom_ticket → warehouse_documents)
| فیلد قدیمی | فیلد جدید | توضیحات |
|------------|-----------|---------|
| `id` | - | استفاده نمی‌شود |
| `bid_id` | `business_id` | نیاز به mapping |
| `submitter_id` | `created_by_user_id` | نیاز به mapping |
| `person_id` | - | در `extra_info` ذخیره می‌شود |
| `doc_id` | `source_document_id` | نیاز به mapping (اگر فاکتور مرتبط باشد) |
| `year_id` | `fiscal_year_id` | نیاز به mapping |
| `storeroom_id` | `warehouse_id_from` یا `warehouse_id_to` | بستگی به `type` دارد |
| `transfer_type_id` | - | در `extra_info` ذخیره می‌شود |
| `date` | `document_date` | تبدیل از شمسی به میلادی |
| `date_submit` | `created_at` | تبدیل از timestamp به datetime |
| `code` | `code` | مستقیم (با بررسی یکتایی) |
| `type` | `doc_type` | تبدیل: `input` → `receipt`, `output` → `issue` |
| `type_string` | - | در `extra_info` ذخیره می‌شود |
| `des` | - | در `extra_info` ذخیره می‌شود |
| `transfer` | - | در `extra_info` ذخیره می‌شود |
| `receiver` | - | در `extra_info` ذخیره می‌شود |
| `sender_tel` | - | در `extra_info` ذخیره می‌شود |
| `referral` | - | در `extra_info` ذخیره می‌شود |
| - | `status` | بر اساس `completed` و `is_approved`: `completed=1` → `posted`, در غیر این صورت `draft` |
| - | `warehouse_id_from` | برای `transfer` (اگر `type_string` شامل "انتقال" باشد) |
| - | `warehouse_id_to` | برای `transfer` |
| - | `source_type` | اگر `doc_id` وجود داشته باشد → `invoice`, در غیر این صورت `manual` |
### 2.3. آیتم‌های سند (storeroom_item → warehouse_document_lines)
| فیلد قدیمی | فیلد جدید | توضیحات |
|------------|-----------|---------|
| `id` | - | استفاده نمی‌شود |
| `ticket_id` | `warehouse_document_id` | نیاز به mapping |
| `commodity_id` | `product_id` | نیاز به mapping |
| `storeroom_id` | `warehouse_id` | نیاز به mapping |
| `type` | `movement` | تبدیل: `input` → `in`, `output` → `out` |
| `count` | `quantity` | تبدیل از varchar به decimal |
| `des` | - | در `extra_info` ذخیره می‌شود |
| `referal` | - | در `extra_info` ذخیره می‌شود |
| - | `cost_price` | NULL (می‌تواند از قیمت کالا محاسبه شود) |
| - | `cogs_amount` | NULL |
| - | `instance_ids` | NULL |
## 3. تبدیل‌های مورد نیاز
### 3.1. تبدیل نوع سند (type → doc_type)
```python
def convert_doc_type(old_type: str, type_string: str | None) -> str:
"""
تبدیل type قدیمی به doc_type جدید
Args:
old_type: 'input' یا 'output'
type_string: نوع سند به فارسی (مثل "حواله ورود")
Returns:
doc_type جدید: 'receipt'|'issue'|'transfer'|'production_in'|'production_out'|'adjustment'
"""
if old_type == "input":
# بررسی type_string برای تشخیص نوع دقیق
if type_string and "انتقال" in type_string:
return "transfer"
elif type_string and "تولید" in type_string:
return "production_in"
else:
return "receipt"
elif old_type == "output":
if type_string and "انتقال" in type_string:
return "transfer"
elif type_string and "تولید" in type_string:
return "production_out"
else:
return "issue"
else:
return "adjustment" # پیش‌فرض
```
### 3.2. تبدیل وضعیت (completed/is_approved → status)
```python
def convert_status(completed: int | None, is_approved: int | None) -> str:
"""
تبدیل وضعیت قدیمی به status جدید
Returns:
'draft'|'posted'|'cancelled'
"""
if completed == 1:
return "posted"
elif is_approved == 0:
return "cancelled"
else:
return "draft"
```
### 3.3. تبدیل تاریخ
- **date**: از فرمت شمسی (1402/08/27) به `date`
- **date_submit**: از timestamp به `datetime`
### 3.4. تبدیل تعداد (count → quantity)
```python
def convert_quantity(count_str: str | None) -> Decimal | None:
"""
تبدیل count از varchar به decimal
"""
if not count_str or not count_str.strip():
return None
try:
cleaned = count_str.strip().replace(',', '').replace(' ', '').replace('،', '')
if not cleaned or cleaned == '0':
return None
return Decimal(cleaned)
except (ValueError, InvalidOperation, TypeError):
return None
```
### 3.5. تولید کد انبار (code)
```python
def generate_warehouse_code(name: str, existing_codes: set) -> str:
"""
تولید کد یکتا برای انبار
"""
# استفاده از name (با محدودیت 64 کاراکتر)
base_code = name[:64].strip()
# اگر تکراری است، اضافه کردن شماره
code = base_code
counter = 1
while code in existing_codes:
suffix = f"_{counter}"
code = (base_code[:64-len(suffix)] + suffix)
counter += 1
return code
```
## 4. روابط و وابستگی‌ها
### 4.1. وابستگی‌های انبارها
- **business_id**: نیاز به mapping از `bid_id` قدیمی به `business_id` جدید
- **code**: باید یکتا در هر کسب و کار باشد
### 4.2. وابستگی‌های اسناد انبار
- **business_id**: نیاز به mapping
- **fiscal_year_id**: نیاز به mapping از `year_id`
- **warehouse_id_from/warehouse_id_to**: نیاز به mapping از `storeroom_id`
- **created_by_user_id**: نیاز به mapping از `submitter_id`
- **source_document_id**: نیاز به mapping از `doc_id` (اگر فاکتور مرتبط باشد)
- **code**: باید یکتا باشد (UNIQUE)
### 4.3. وابستگی‌های خطوط سند
- **warehouse_document_id**: نیاز به mapping از `ticket_id`
- **product_id**: نیاز به mapping از `commodity_id`
- **warehouse_id**: نیاز به mapping از `storeroom_id`
## 5. چالش‌ها و راه‌حل‌ها
### 5.1. یکتایی کد سند (code)
- **مشکل**: `code` در `warehouse_documents` باید یکتا باشد
- **راه‌حل**: اگر تکراری است، اضافه کردن suffix (مثلاً `_1`, `_2`)
### 5.2. تشخیص نوع سند (transfer vs receipt/issue)
- **مشکل**: `type` فقط `input`/`output` است، اما باید `transfer` را تشخیص دهیم
- **راه‌حل**: استفاده از `type_string` برای تشخیص
### 5.3. mapping فاکتورها (doc_id → source_document_id)
- **مشکل**: `doc_id` در دیتابیس قدیمی به فاکتورها اشاره می‌کند که هنوز منتقل نشده‌اند
- **راه‌حل**: اگر فاکتورها منتقل نشده‌اند، `source_document_id` را NULL بگذاریم و `source_type` را `manual` کنیم
### 5.4. انبار پیش‌فرض (is_default)
- **راه‌حل**: اولین انبار هر کسب و کار را `is_default = true` کنیم
### 5.5. تبدیل تاریخ شمسی
- **راه‌حل**: استفاده از کتابخانه `jdatetime` برای تبدیل تاریخ شمسی به میلادی
## 6. مراحل انتقال
1. **انتقال انبارها (warehouses)**
- ایجاد mapping بین `storeroom_id` قدیمی و `warehouse_id` جدید
- فقط انبارهای `active = 1` را منتقل کنیم
2. **انتقال اسناد انبار (warehouse_documents)**
- ایجاد mapping بین `ticket_id` قدیمی و `warehouse_document_id` جدید
- تبدیل `type` به `doc_type`
- تبدیل تاریخ‌ها
- تبدیل وضعیت
3. **انتقال خطوط سند (warehouse_document_lines)**
- استفاده از mapping های ایجاد شده
- تبدیل `count` به `quantity`
- تبدیل `type` به `movement`
## 7. آمار کلی
- **انبارها**: 1,185
- **اسناد انبار**: 4,564
- ورود: 1,511
- خروج: 3,053
- **آیتم‌های سند**: 12,645
- ورود: 5,359
- خروج: 7,286
- **کسب و کارهای دارای انبار**: 924