- Introduced new tables `timeline_footprints` and `timeline_activities` to manage employee location data and activity records. - Updated `company_settings` to include `gps_interval_seconds` and `checkout_warning_radius_meters` for enhanced tracking configuration. - Implemented foreign key constraints to ensure data integrity between new tables and existing `employees`, `customers`, and `visits` tables. - Created services and controllers for handling timeline activities and footprints, including ingestion and retrieval of data. - Enhanced DTOs and validation logic to support new fields and ensure correct data formats in API requests. - Added unit and integration tests to validate the new functionalities and ensure proper handling of timeline records. - Created migration scripts to apply the necessary database schema changes for the new features.
84 lines
2.9 KiB
TypeScript
84 lines
2.9 KiB
TypeScript
import { Inject, Injectable } from '@nestjs/common';
|
|
import { eq } from 'drizzle-orm';
|
|
import { DateTime } from '../../../common/value-objects/date-time/date-time';
|
|
import { Status } from '../../../common/value-objects/status/status';
|
|
import { DRIZZLE, type DrizzleDB } from '../../../database/database.module';
|
|
import {
|
|
companySettings,
|
|
type CompanySettingsRow,
|
|
} from '../../../database/company-settings-table';
|
|
import type {
|
|
CompanySetting,
|
|
UpsertCompanySettingInput,
|
|
} from './company-setting';
|
|
|
|
@Injectable()
|
|
export class CompanySettingsRepository {
|
|
constructor(@Inject(DRIZZLE) private readonly db: DrizzleDB) {}
|
|
|
|
async find(): Promise<CompanySetting | null> {
|
|
const rows: CompanySettingsRow[] = await this.db
|
|
.select()
|
|
.from(companySettings)
|
|
.limit(1);
|
|
const row = rows[0];
|
|
return row ? this.toDomain(row) : null;
|
|
}
|
|
|
|
async upsert(input: UpsertCompanySettingInput): Promise<CompanySetting> {
|
|
const now = DateTime.fromUnixMs(Date.now());
|
|
const existing = await this.find();
|
|
if (!existing) {
|
|
const inserted = await this.db
|
|
.insert(companySettings)
|
|
.values({
|
|
cycleStartDate: input.cycleStartDate.value,
|
|
checkInRadiusMeters: input.checkInRadiusMeters ?? 100,
|
|
gpsIntervalSeconds: input.gpsIntervalSeconds ?? 5,
|
|
checkoutWarningRadiusMeters: input.checkoutWarningRadiusMeters ?? 200,
|
|
status: Status.create(Status.DEFAULT).value,
|
|
createdAt: now.value,
|
|
updatedAt: now.value,
|
|
createdBy: input.userId,
|
|
updatedBy: input.userId,
|
|
})
|
|
.returning();
|
|
return this.toDomain(inserted[0]);
|
|
}
|
|
const updated = await this.db
|
|
.update(companySettings)
|
|
.set({
|
|
cycleStartDate: input.cycleStartDate.value,
|
|
...(input.checkInRadiusMeters !== undefined
|
|
? { checkInRadiusMeters: input.checkInRadiusMeters }
|
|
: {}),
|
|
...(input.gpsIntervalSeconds !== undefined
|
|
? { gpsIntervalSeconds: input.gpsIntervalSeconds }
|
|
: {}),
|
|
...(input.checkoutWarningRadiusMeters !== undefined
|
|
? { checkoutWarningRadiusMeters: input.checkoutWarningRadiusMeters }
|
|
: {}),
|
|
updatedAt: now.value,
|
|
updatedBy: input.userId,
|
|
})
|
|
.where(eq(companySettings.id, existing.id))
|
|
.returning();
|
|
return this.toDomain(updated[0]);
|
|
}
|
|
|
|
private toDomain(row: CompanySettingsRow): CompanySetting {
|
|
return {
|
|
id: row.id,
|
|
cycleStartDate: DateTime.fromUnixMs(row.cycleStartDate),
|
|
checkInRadiusMeters: row.checkInRadiusMeters,
|
|
gpsIntervalSeconds: row.gpsIntervalSeconds,
|
|
checkoutWarningRadiusMeters: row.checkoutWarningRadiusMeters,
|
|
status: Status.create(row.status),
|
|
createdAt: DateTime.fromUnixMs(row.createdAt),
|
|
updatedAt: DateTime.fromUnixMs(row.updatedAt),
|
|
createdBy: row.createdBy,
|
|
updatedBy: row.updatedBy,
|
|
};
|
|
}
|
|
}
|