feat(property): convert registrationDate to Date object and add Jalali utilities
deploy-chabokan / deploy (push) Canceled after 0s
deploy-chabokan / deploy (push) Canceled after 0s
This commit is contained in:
@@ -57,7 +57,7 @@ const propertySchema = new mongoose.Schema(
|
|||||||
serialNumber: String, // شماره سریال چاپی سند
|
serialNumber: String, // شماره سریال چاپی سند
|
||||||
provinceRegistry: String,
|
provinceRegistry: String,
|
||||||
localRegistryOffice: String,
|
localRegistryOffice: String,
|
||||||
registrationDate: String, // تاریخ ثبت سند
|
registrationDate: Date, // تاریخ ثبت سند (MongoDB Date object)
|
||||||
|
|
||||||
// Owner Specifications (مشخصات مالک)
|
// Owner Specifications (مشخصات مالک)
|
||||||
ownerName: String,
|
ownerName: String,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const AppError = require('../../globalErrorHandler/AppError')
|
|||||||
const { client } = require('../../setup/typesense')
|
const { client } = require('../../setup/typesense')
|
||||||
const TsApiFeatures = require('../../utils/TsApiFeatures')
|
const TsApiFeatures = require('../../utils/TsApiFeatures')
|
||||||
const { moveFromTempToMain, getSignedUrl } = require('../file/fileService')
|
const { moveFromTempToMain, getSignedUrl } = require('../file/fileService')
|
||||||
|
const { normalizeToDate } = require('../../utils/jalali')
|
||||||
|
|
||||||
const getAllProperties = async () => {
|
const getAllProperties = async () => {
|
||||||
return Property.find({}, null, null).populate('category').populate('status')
|
return Property.find({}, null, null).populate('category').populate('status')
|
||||||
@@ -18,6 +19,10 @@ const createProperty = async (data) => {
|
|||||||
data.documentUrls = await moveFromTempToMain(data.documentUrls, 'documents')
|
data.documentUrls = await moveFromTempToMain(data.documentUrls, 'documents')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.registrationDate !== undefined) {
|
||||||
|
data.registrationDate = normalizeToDate(data.registrationDate)
|
||||||
|
}
|
||||||
|
|
||||||
if (data.propertyType === 'Land' || data.propertyType === 'زمین') {
|
if (data.propertyType === 'Land' || data.propertyType === 'زمین') {
|
||||||
return Land.create(data)
|
return Land.create(data)
|
||||||
} else if (data.propertyType === 'Building' || data.propertyType === 'ساختمان') {
|
} else if (data.propertyType === 'Building' || data.propertyType === 'ساختمان') {
|
||||||
@@ -52,6 +57,10 @@ const updateProperty = async (propertyId, data) => {
|
|||||||
data.documentUrls = await moveFromTempToMain(data.documentUrls, 'documents')
|
data.documentUrls = await moveFromTempToMain(data.documentUrls, 'documents')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.registrationDate !== undefined) {
|
||||||
|
data.registrationDate = normalizeToDate(data.registrationDate)
|
||||||
|
}
|
||||||
|
|
||||||
const property = await Property.findOneAndUpdate({ _id: propertyId }, data, { new: true })
|
const property = await Property.findOneAndUpdate({ _id: propertyId }, data, { new: true })
|
||||||
|
|
||||||
if (!property) {
|
if (!property) {
|
||||||
@@ -180,6 +189,7 @@ const searchPropertiesMongo = async (inputQuery = {}) => {
|
|||||||
registrationPlate: prop.registrationPlate || '',
|
registrationPlate: prop.registrationPlate || '',
|
||||||
uniqueId: prop.uniqueId || '',
|
uniqueId: prop.uniqueId || '',
|
||||||
serialNumber: prop.serialNumber || '',
|
serialNumber: prop.serialNumber || '',
|
||||||
|
registrationDate: prop.registrationDate,
|
||||||
coordinates: prop.location?.coordinates || [0, 0],
|
coordinates: prop.location?.coordinates || [0, 0],
|
||||||
location: prop.location,
|
location: prop.location,
|
||||||
createdAt: Math.floor(new Date(prop.createdAt || Date.now()).getTime() / 1000),
|
createdAt: Math.floor(new Date(prop.createdAt || Date.now()).getTime() / 1000),
|
||||||
|
|||||||
+174
@@ -0,0 +1,174 @@
|
|||||||
|
/**
|
||||||
|
* Jalali (Solar Hijri / Shamsi) calendar conversion utilities (Backend)
|
||||||
|
*/
|
||||||
|
|
||||||
|
const persianMonths = [
|
||||||
|
{ value: 1, label: 'فروردین' },
|
||||||
|
{ value: 2, label: 'اردیبهشت' },
|
||||||
|
{ value: 3, label: 'خرداد' },
|
||||||
|
{ value: 4, label: 'تیر' },
|
||||||
|
{ value: 5, label: 'مرداد' },
|
||||||
|
{ value: 6, label: 'شهریور' },
|
||||||
|
{ value: 7, label: 'مهر' },
|
||||||
|
{ value: 8, label: 'آبان' },
|
||||||
|
{ value: 9, label: 'آذر' },
|
||||||
|
{ value: 10, label: 'دی' },
|
||||||
|
{ value: 11, label: 'بهمن' },
|
||||||
|
{ value: 12, label: 'اسفند' }
|
||||||
|
]
|
||||||
|
|
||||||
|
function toEnglishDigits(str) {
|
||||||
|
if (str === null || str === undefined) return ''
|
||||||
|
return String(str)
|
||||||
|
.replace(/[۰-۹]/g, (d) => '۰۱۲۳۴۵۶۷۸۹'.indexOf(d))
|
||||||
|
.replace(/[٠-٩]/g, (d) => '٠١٢٣٤٥٦٧٨٩'.indexOf(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
function jalaliToGregorian(jy, jm, jd) {
|
||||||
|
jy = Number(jy)
|
||||||
|
jm = Number(jm)
|
||||||
|
jd = Number(jd)
|
||||||
|
|
||||||
|
let gy = jy > 979 ? 1600 : 621
|
||||||
|
jy = jy > 979 ? jy - 979 : jy
|
||||||
|
|
||||||
|
let days =
|
||||||
|
365 * jy +
|
||||||
|
Math.floor(jy / 33) * 8 +
|
||||||
|
Math.floor(((jy % 33) + 3) / 4) +
|
||||||
|
78 +
|
||||||
|
jd +
|
||||||
|
(jm < 7 ? (jm - 1) * 31 : (jm - 7) * 30 + 186)
|
||||||
|
|
||||||
|
gy += 400 * Math.floor(days / 146097)
|
||||||
|
days %= 146097
|
||||||
|
|
||||||
|
if (days > 36524) {
|
||||||
|
gy += 100 * Math.floor(--days / 36524)
|
||||||
|
days %= 36524
|
||||||
|
if (days >= 365) days++
|
||||||
|
}
|
||||||
|
|
||||||
|
gy += 4 * Math.floor(days / 1461)
|
||||||
|
days %= 1461
|
||||||
|
|
||||||
|
if (days > 365) {
|
||||||
|
gy += Math.floor((days - 1) / 365)
|
||||||
|
days = (days - 1) % 365
|
||||||
|
}
|
||||||
|
|
||||||
|
let gd = days + 1
|
||||||
|
const isLeap = (gy % 4 === 0 && gy % 100 !== 0) || gy % 400 === 0
|
||||||
|
const sal_a = [0, 31, isLeap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
||||||
|
|
||||||
|
let gm
|
||||||
|
for (gm = 0; gm < 13; gm++) {
|
||||||
|
const v = sal_a[gm]
|
||||||
|
if (gd <= v) break
|
||||||
|
gd -= v
|
||||||
|
}
|
||||||
|
|
||||||
|
return { gy, gm, gd }
|
||||||
|
}
|
||||||
|
|
||||||
|
function gregorianToJalali(gy, gm, gd) {
|
||||||
|
gy = Number(gy)
|
||||||
|
gm = Number(gm)
|
||||||
|
gd = Number(gd)
|
||||||
|
|
||||||
|
const g_d_m = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
|
||||||
|
let jy = gy > 1600 ? 979 : 0
|
||||||
|
gy = gy > 1600 ? gy - 1600 : gy - 621
|
||||||
|
|
||||||
|
const gy2 = gm > 2 ? gy + 1 : gy
|
||||||
|
let days =
|
||||||
|
365 * gy +
|
||||||
|
Math.floor((gy2 + 3) / 4) -
|
||||||
|
Math.floor((gy2 + 99) / 100) +
|
||||||
|
Math.floor((gy2 + 399) / 400) -
|
||||||
|
80 +
|
||||||
|
gd +
|
||||||
|
g_d_m[gm - 1]
|
||||||
|
|
||||||
|
jy += 33 * Math.floor(days / 12053)
|
||||||
|
days %= 12053
|
||||||
|
|
||||||
|
jy += 4 * Math.floor(days / 1461)
|
||||||
|
days %= 1461
|
||||||
|
|
||||||
|
if (days > 365) {
|
||||||
|
jy += Math.floor((days - 1) / 365)
|
||||||
|
days = (days - 1) % 365
|
||||||
|
}
|
||||||
|
|
||||||
|
const jm = days < 186 ? 1 + Math.floor(days / 31) : 7 + Math.floor((days - 186) / 30)
|
||||||
|
const jd = 1 + (days < 186 ? days % 31 : (days - 186) % 30)
|
||||||
|
|
||||||
|
return { jy, jm, jd }
|
||||||
|
}
|
||||||
|
|
||||||
|
function jalaliToDate(jy, jm, jd) {
|
||||||
|
const y = parseInt(toEnglishDigits(jy), 10)
|
||||||
|
const m = parseInt(toEnglishDigits(jm), 10)
|
||||||
|
const d = parseInt(toEnglishDigits(jd), 10)
|
||||||
|
|
||||||
|
if (isNaN(y) || isNaN(m) || isNaN(d) || y <= 0 || m < 1 || m > 12 || d < 1 || d > 31) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const { gy, gm, gd } = jalaliToGregorian(y, m, d)
|
||||||
|
return new Date(Date.UTC(gy, gm - 1, gd, 12, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseDateToJalali(dateVal) {
|
||||||
|
if (!dateVal) return null
|
||||||
|
|
||||||
|
if (dateVal instanceof Date || (typeof dateVal === 'string' && (dateVal.includes('T') || dateVal.includes('-')))) {
|
||||||
|
const d = new Date(dateVal)
|
||||||
|
if (!isNaN(d.getTime())) {
|
||||||
|
return gregorianToJalali(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof dateVal === 'string' && dateVal.includes('/')) {
|
||||||
|
const clean = toEnglishDigits(dateVal.trim())
|
||||||
|
const parts = clean.split('/')
|
||||||
|
if (parts.length === 3) {
|
||||||
|
const jy = parseInt(parts[0], 10)
|
||||||
|
const jm = parseInt(parts[1], 10)
|
||||||
|
const jd = parseInt(parts[2], 10)
|
||||||
|
if (!isNaN(jy) && !isNaN(jm) && !isNaN(jd)) {
|
||||||
|
return { jy, jm, jd }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeToDate(input) {
|
||||||
|
if (!input) return null
|
||||||
|
if (input instanceof Date && !isNaN(input.getTime())) return input
|
||||||
|
if (typeof input === 'string') {
|
||||||
|
const trimmed = input.trim()
|
||||||
|
if (trimmed.includes('/')) {
|
||||||
|
const parts = toEnglishDigits(trimmed).split('/')
|
||||||
|
if (parts.length === 3) {
|
||||||
|
return jalaliToDate(parts[0], parts[1], parts[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const d = new Date(trimmed)
|
||||||
|
if (!isNaN(d.getTime())) return d
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
persianMonths,
|
||||||
|
toEnglishDigits,
|
||||||
|
jalaliToGregorian,
|
||||||
|
gregorianToJalali,
|
||||||
|
jalaliToDate,
|
||||||
|
parseDateToJalali,
|
||||||
|
normalizeToDate,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user