Files
kavehhn ca911b97a0 REFACTOR: Belonging → Property system migration + utilities update
Property system:
- Rename belonging → property throughout (model, controller, routes, service)
- Add property sub-models: buildingModel, landModel, belongingModel
- Add property lifecycle events: createProperty, deleteProperty
- Add propertyStatus component (model, controller, routes, service, seeder)
- Add commodity and commodityTransaction model stubs

Infrastructure:
- Update transactionModel and transactionService
- Update events/index.js for new property events
- Update seeder (seederDBConnection, seederRunner)
- Update typesense client configuration
- Update upload utilities (bucket, minio)
- Update featureModel and featureSeeder
- Update categorySeeder
- Update TsApiFeatures utility
- Remove docker-compose.yml (moved to root)
- Remove legacy belonging component files
2026-08-11 20:35:47 +03:30

686 lines
23 KiB
JavaScript

const Feature = require('./featureModel')
const Category = require('../category/categoryModel')
const chalk = require('chalk')
const runSeeder = async () => {
// Fetch all categories dynamically so we don't rely on hardcoded ObjectIDs
const allCategories = await Category.find({})
const categoryMap = {}
for (const cat of allCategories) {
categoryMap[cat.englishName] = cat._id
}
const lot = categoryMap['Lot']
const building = categoryMap['Building']
const car = categoryMap['Car']
if (!lot || !building || !car) {
console.log(chalk.red('One or more required categories not found. Run category seeder first.'))
console.log('Found categories:', Object.keys(categoryMap))
return
}
// ─────────────────────────────────────────────────────────────────────────
// Helper: builds the shared registration/ownership/legal block for a given
// category ObjectID. Used for both Lot and Building.
// ─────────────────────────────────────────────────────────────────────────
const sharedRealEstateFields = (category) => [
{
nativeName: 'نام مالک',
englishName: 'ownerName',
category,
featureType: 'string',
filterType: 'exact',
isFilterable: false,
tag: 'مالکیت',
priority: 200,
},
{
nativeName: 'پلاک ثبتی',
englishName: 'registrationPlate',
category,
featureType: 'string',
filterType: 'exact',
isFilterable: false,
tag: 'ثبت',
priority: 195,
},
{
nativeName: 'شماره اصلی',
englishName: 'mainNumber',
category,
featureType: 'string',
filterType: 'exact',
isFilterable: false,
tag: 'ثبت',
priority: 194,
},
{
nativeName: 'شماره فرعی',
englishName: 'subNumber',
category,
featureType: 'string',
filterType: 'exact',
isFilterable: false,
tag: 'ثبت',
priority: 193,
},
{
nativeName: 'بخش ثبتی',
englishName: 'registrationSection',
category,
featureType: 'string',
filterType: 'exact',
isFilterable: true,
tag: 'ثبت',
priority: 192,
},
{
nativeName: 'قطعه',
englishName: 'plotNumber',
category,
featureType: 'string',
filterType: 'exact',
isFilterable: false,
tag: 'ثبت',
priority: 191,
},
{
nativeName: 'ناحیه',
englishName: 'district',
category,
featureType: 'string',
filterType: 'exact',
isFilterable: true,
tag: 'موقعیت',
priority: 190,
},
{
nativeName: 'کدپستی',
englishName: 'postalCode',
category,
featureType: 'string',
filterType: 'exact',
isFilterable: false,
tag: 'موقعیت',
priority: 189,
},
{
nativeName: 'شناسه ملی جغرافیایی',
englishName: 'nationalGeoId',
category,
featureType: 'string',
filterType: 'exact',
isFilterable: false,
tag: 'ثبت',
priority: 188,
},
{
nativeName: 'آدرس',
englishName: 'address',
category,
featureType: 'textarea',
filterType: 'exact',
isFilterable: false,
tag: 'موقعیت',
priority: 187,
},
{
nativeName: 'حدود مفروزات',
englishName: 'propertyBoundaries',
category,
featureType: 'textarea',
filterType: 'exact',
isFilterable: false,
tag: 'ثبت',
priority: 186,
},
{
nativeName: 'مستندات مالکیت',
englishName: 'ownershipDocs',
category,
featureType: 'textarea',
filterType: 'exact',
isFilterable: false,
tag: 'مالکیت',
priority: 185,
},
{
nativeName: 'وضعیت خاص',
englishName: 'specialStatus',
category,
featureType: 'string',
filterType: 'exact',
predefinedValues: ['توقیف', 'رهن', 'وراثتی', 'اوقافی', 'دولتی', 'در دست ساخت', 'مسدود'],
isFilterable: true,
tag: 'مالکیت',
priority: 184,
},
{
nativeName: 'نوع سند',
englishName: 'documentType',
category,
featureType: 'string',
filterType: 'exact',
predefinedValues: ['سند تک‌برگ', 'منگوله‌دار', 'وقفی', 'مشاع', 'بنچاق', 'قولنامه‌ای'],
isFilterable: true,
tag: 'سند',
priority: 183,
},
]
const features = [
// ──────────────────────────────────────────────────────────────────────
// زمین (Lot) features
// ──────────────────────────────────────────────────────────────────────
...sharedRealEstateFields(lot),
{
nativeName: 'متراژ',
englishName: 'area',
category: lot,
featureType: 'number',
filterType: 'range',
unit: 'متر مربع',
isFilterable: true,
tag: 'ابعاد',
priority: 100,
},
{
nativeName: 'کاربری زمین',
englishName: 'landUsage',
category: lot,
featureType: 'string',
filterType: 'exact',
predefinedValues: ['مسکونی', 'تجاری', 'کشاورزی', 'صنعتی', 'ویلایی', 'باغی', 'آموزشی', 'اداری'],
isFilterable: true,
tag: 'کاربری',
priority: 95,
},
{
nativeName: 'نوع ملک',
englishName: 'propertyType',
category: lot,
featureType: 'string',
filterType: 'exact',
predefinedValues: ['زمین مسکونی', 'زمین تجاری', 'زمین کشاورزی', 'زمین صنعتی', 'باغ', 'مزرعه'],
isFilterable: true,
tag: 'مشخصات',
priority: 90,
},
{
nativeName: 'موقعیت جغرافیایی',
englishName: 'geoPosition',
category: lot,
featureType: 'string',
filterType: 'exact',
predefinedValues: ['شمالی', 'جنوبی', 'شرقی', 'غربی', 'کنج'],
isFilterable: true,
tag: 'موقعیت',
priority: 80,
},
{
nativeName: 'عرض گذر',
englishName: 'streetWidth',
category: lot,
featureType: 'number',
filterType: 'range',
unit: 'متر',
isFilterable: true,
tag: 'ابعاد',
priority: 75,
},
{
nativeName: 'تعداد بر',
englishName: 'facadeCount',
category: lot,
featureType: 'number',
filterType: 'range',
isFilterable: true,
tag: 'ابعاد',
priority: 70,
},
{
nativeName: 'طول زمین',
englishName: 'landLength',
category: lot,
featureType: 'number',
filterType: 'range',
unit: 'متر',
isFilterable: false,
tag: 'ابعاد',
priority: 65,
},
{
nativeName: 'عرض زمین',
englishName: 'landWidth',
category: lot,
featureType: 'number',
filterType: 'range',
unit: 'متر',
isFilterable: false,
tag: 'ابعاد',
priority: 64,
},
{
nativeName: 'جهت ساختمان',
englishName: 'buildingDirection',
category: lot,
featureType: 'string',
filterType: 'exact',
predefinedValues: ['شمالی', 'جنوبی', 'شرقی', 'غربی'],
isFilterable: true,
tag: 'موقعیت',
priority: 60,
},
{
nativeName: 'امکانات زیرساختی',
englishName: 'utilities',
category: lot,
featureType: 'string',
filterType: 'multi',
predefinedValues: ['آب', 'برق', 'گاز', 'فاضلاب', 'تلفن', 'اینترنت'],
isFilterable: true,
tag: 'امکانات',
priority: 55,
},
{
nativeName: 'قیمت هر متر مربع',
englishName: 'pricePerMeter',
category: lot,
featureType: 'number',
filterType: 'range',
unit: 'تومان',
isFilterable: true,
tag: 'قیمت',
priority: 50,
},
{
nativeName: 'منطقه شهرداری',
englishName: 'municipalityZone',
category: lot,
featureType: 'string',
filterType: 'exact',
isFilterable: true,
tag: 'موقعیت',
priority: 45,
},
// ──────────────────────────────────────────────────────────────────────
// ساختمان (Building) features
// ──────────────────────────────────────────────────────────────────────
...sharedRealEstateFields(building),
{
nativeName: 'متراژ',
englishName: 'area',
category: building,
featureType: 'number',
filterType: 'range',
unit: 'متر مربع',
isFilterable: true,
tag: 'ابعاد',
priority: 100,
},
{
nativeName: 'نوع ملک',
englishName: 'propertyType',
category: building,
featureType: 'string',
filterType: 'exact',
predefinedValues: ['آپارتمان', 'ویلا', 'خانه مستقل', 'دوبلکس', 'پنت‌هاوس', 'مغازه', 'دفتر', 'سوله'],
isFilterable: true,
tag: 'مشخصات',
priority: 99,
},
{
nativeName: 'تعداد اتاق',
englishName: 'roomCount',
category: building,
featureType: 'number',
filterType: 'range',
isFilterable: true,
tag: 'مشخصات',
priority: 95,
},
{
nativeName: 'طبقه',
englishName: 'floor',
category: building,
featureType: 'number',
filterType: 'range',
isFilterable: true,
tag: 'مشخصات',
priority: 90,
},
{
nativeName: 'تعداد طبقات کل',
englishName: 'totalFloors',
category: building,
featureType: 'number',
filterType: 'range',
isFilterable: true,
tag: 'مشخصات',
priority: 85,
},
{
nativeName: 'سال ساخت',
englishName: 'buildYear',
category: building,
featureType: 'number',
filterType: 'range',
isFilterable: true,
tag: 'عمومی',
priority: 80,
},
{
nativeName: 'پارکینگ',
englishName: 'parking',
category: building,
featureType: 'boolean',
filterType: 'bool',
isFilterable: true,
tag: 'امکانات',
priority: 75,
},
{
nativeName: 'انباری',
englishName: 'storage',
category: building,
featureType: 'boolean',
filterType: 'bool',
isFilterable: true,
tag: 'امکانات',
priority: 74,
},
{
nativeName: 'آسانسور',
englishName: 'elevator',
category: building,
featureType: 'boolean',
filterType: 'bool',
isFilterable: true,
tag: 'امکانات',
priority: 73,
},
{
nativeName: 'بالکن',
englishName: 'balcony',
category: building,
featureType: 'boolean',
filterType: 'bool',
isFilterable: true,
tag: 'امکانات',
priority: 72,
},
{
nativeName: 'وضعیت بنا',
englishName: 'houseCondition',
category: building,
featureType: 'string',
filterType: 'exact',
predefinedValues: ['نوساز', 'بازسازی شده', 'کلنگی', 'قدیمی'],
isFilterable: true,
tag: 'مشخصات',
priority: 70,
},
{
nativeName: 'سیستم گرمایش',
englishName: 'heatingSystem',
category: building,
featureType: 'string',
filterType: 'exact',
predefinedValues: ['شوفاژ', 'پکیج', 'فن‌کوئل', 'گرمای کفی', 'بخاری'],
isFilterable: true,
tag: 'امکانات',
priority: 65,
},
{
nativeName: 'سیستم سرمایش',
englishName: 'coolingSystem',
category: building,
featureType: 'string',
filterType: 'exact',
predefinedValues: ['کولر آبی', 'اسپیلت', 'فن‌کوئل', 'چیلر'],
isFilterable: true,
tag: 'امکانات',
priority: 64,
},
{
nativeName: 'متریال کف',
englishName: 'floorMaterial',
category: building,
featureType: 'string',
filterType: 'exact',
predefinedValues: ['سرامیک', 'پارکت', 'موزاییک', 'سنگ', 'اپوکسی'],
isFilterable: false,
tag: 'مشخصات',
priority: 60,
},
{
nativeName: 'موقعیت جغرافیایی',
englishName: 'geoPosition',
category: building,
featureType: 'string',
filterType: 'exact',
predefinedValues: ['شمالی', 'جنوبی', 'شرقی', 'غربی', 'کنج'],
isFilterable: true,
tag: 'موقعیت',
priority: 55,
},
{
nativeName: 'منطقه شهرداری',
englishName: 'municipalityZone',
category: building,
featureType: 'string',
filterType: 'exact',
isFilterable: true,
tag: 'موقعیت',
priority: 50,
},
// ──────────────────────────────────────────────────────────────────────
// خودرو (Car) features
// ──────────────────────────────────────────────────────────────────────
{
nativeName: 'شماره VIN',
englishName: 'vinNumber',
category: car,
featureType: 'string',
filterType: 'exact',
isFilterable: false,
tag: 'شناسه',
priority: 100,
},
{
nativeName: 'نوع پلاک',
englishName: 'plateType',
category: car,
featureType: 'string',
filterType: 'exact',
predefinedValues: [
'پلاک ملی',
'پلاک منطقه آزاد اروند دائمی',
'پلاک منطقه آزاد اروند موقت',
'پلاک گذر موقت',
],
isFilterable: true,
tag: 'پلاک',
priority: 95,
},
{
nativeName: 'شماره پلاک',
englishName: 'plateNumber',
category: car,
featureType: 'string',
filterType: 'exact',
isFilterable: false,
tag: 'پلاک',
priority: 90,
},
{
nativeName: 'برند',
englishName: 'brand',
category: car,
featureType: 'string',
filterType: 'exact',
predefinedValues: [
'ایران‌خودرو',
'سایپا',
'بهمن',
'کیا',
'هیوندا',
'تویوتا',
'بنز',
'BMW',
'آئودی',
'پژو',
'رنو',
'فولکس واگن',
'شورولت',
'فورد',
'لکسوس',
],
isFilterable: true,
tag: 'مشخصات',
priority: 85,
},
{
nativeName: 'مدل خودرو',
englishName: 'model',
category: car,
featureType: 'string',
filterType: 'exact',
isFilterable: true,
tag: 'مشخصات',
priority: 80,
},
{
nativeName: 'سال تولید',
englishName: 'productionYear',
category: car,
featureType: 'number',
filterType: 'range',
isFilterable: true,
tag: 'مشخصات',
priority: 75,
},
{
nativeName: 'رنگ',
englishName: 'color',
category: car,
featureType: 'string',
filterType: 'exact',
predefinedValues: ['سفید', 'مشکی', 'نقره‌ای', 'خاکستری', 'قرمز', 'آبی', 'سبز', 'طلایی', 'کرم'],
isFilterable: true,
tag: 'مشخصات',
priority: 70,
},
{
nativeName: 'کارکرد (کیلومتر)',
englishName: 'mileage',
category: car,
featureType: 'number',
filterType: 'range',
unit: 'کیلومتر',
isFilterable: true,
tag: 'وضعیت',
priority: 65,
},
{
nativeName: 'نوع سوخت',
englishName: 'fuelType',
category: car,
featureType: 'string',
filterType: 'exact',
predefinedValues: ['بنزین', 'گازوئیل', 'برقی', 'هیبریدی', 'CNG', 'دوگانه‌سوز'],
isFilterable: true,
tag: 'موتور',
priority: 60,
},
{
nativeName: 'نوع گیربکس',
englishName: 'transmission',
category: car,
featureType: 'string',
filterType: 'exact',
predefinedValues: ['دستی', 'اتوماتیک', 'نیمه‌اتوماتیک', 'CVT'],
isFilterable: true,
tag: 'موتور',
priority: 55,
},
{
nativeName: 'ظرفیت موتور',
englishName: 'engineCapacity',
category: car,
featureType: 'number',
filterType: 'range',
unit: 'سی‌سی',
isFilterable: true,
tag: 'موتور',
priority: 50,
},
{
nativeName: 'تعداد سیلندر',
englishName: 'cylinderCount',
category: car,
featureType: 'number',
filterType: 'exact',
predefinedValues: ['3', '4', '6', '8'],
isFilterable: true,
tag: 'موتور',
priority: 45,
},
{
nativeName: 'وضعیت بدنه',
englishName: 'bodyCondition',
category: car,
featureType: 'string',
filterType: 'exact',
predefinedValues: ['صفر', 'بدون خش', 'خط و خش جزئی', 'رنگ شده', 'تصادفی'],
isFilterable: true,
tag: 'وضعیت',
priority: 40,
},
{
nativeName: 'گواهی معاینه فنی',
englishName: 'technicalInspection',
category: car,
featureType: 'boolean',
filterType: 'bool',
isFilterable: true,
tag: 'وضعیت',
priority: 35,
},
{
nativeName: 'بیمه بدنه',
englishName: 'bodyInsurance',
category: car,
featureType: 'boolean',
filterType: 'bool',
isFilterable: true,
tag: 'وضعیت',
priority: 30,
},
{
nativeName: 'نوع بدنه',
englishName: 'bodyType',
category: car,
featureType: 'string',
filterType: 'exact',
predefinedValues: ['سدان', 'هاچبک', 'شاسی‌بلند', 'وانت', 'کوپه', 'مینی‌ون', 'کراس‌اوور'],
isFilterable: true,
tag: 'مشخصات',
priority: 25,
},
]
await Feature.deleteMany({})
console.log(chalk.red('Deleted all feature records.'))
await Feature.insertMany(features)
console.log(chalk.green.bold(`FEATURES: Created ${features.length} feature(s)`))
}
module.exports = { runSeeder }