erp-core-backend/src/modules/core/states.service.ts
rckrdmrd d809e23b5c feat(core): Add States, CurrencyRates, and UoM conversion (MGN-005)
- State entity and service with CRUD operations
- CurrencyRate entity and service with conversion support
- UoM conversion methods (convertQuantity, getConversionTable)
- New API endpoints for states, currency rates, UoM conversions
- Updated controller and routes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 08:57:21 -06:00

149 lines
3.9 KiB
TypeScript

import { Repository } from 'typeorm';
import { AppDataSource } from '../../config/typeorm.js';
import { State } from './entities/state.entity.js';
import { NotFoundError } from '../../shared/errors/index.js';
import { logger } from '../../shared/utils/logger.js';
export interface CreateStateDto {
countryId: string;
code: string;
name: string;
timezone?: string;
isActive?: boolean;
}
export interface UpdateStateDto {
name?: string;
timezone?: string;
isActive?: boolean;
}
export interface StateFilter {
countryId?: string;
countryCode?: string;
isActive?: boolean;
}
class StatesService {
private repository: Repository<State>;
constructor() {
this.repository = AppDataSource.getRepository(State);
}
async findAll(filter: StateFilter = {}): Promise<State[]> {
logger.debug('Finding all states', { filter });
const query = this.repository
.createQueryBuilder('state')
.leftJoinAndSelect('state.country', 'country');
if (filter.countryId) {
query.andWhere('state.countryId = :countryId', { countryId: filter.countryId });
}
if (filter.countryCode) {
query.andWhere('country.code = :countryCode', { countryCode: filter.countryCode.toUpperCase() });
}
if (filter.isActive !== undefined) {
query.andWhere('state.isActive = :isActive', { isActive: filter.isActive });
}
query.orderBy('state.name', 'ASC');
return query.getMany();
}
async findById(id: string): Promise<State> {
logger.debug('Finding state by id', { id });
const state = await this.repository.findOne({
where: { id },
relations: ['country'],
});
if (!state) {
throw new NotFoundError('Estado no encontrado');
}
return state;
}
async findByCode(countryId: string, code: string): Promise<State | null> {
logger.debug('Finding state by code', { countryId, code });
return this.repository.findOne({
where: { countryId, code: code.toUpperCase() },
relations: ['country'],
});
}
async findByCountry(countryId: string): Promise<State[]> {
logger.debug('Finding states by country', { countryId });
return this.repository.find({
where: { countryId, isActive: true },
relations: ['country'],
order: { name: 'ASC' },
});
}
async findByCountryCode(countryCode: string): Promise<State[]> {
logger.debug('Finding states by country code', { countryCode });
return this.repository
.createQueryBuilder('state')
.leftJoinAndSelect('state.country', 'country')
.where('country.code = :countryCode', { countryCode: countryCode.toUpperCase() })
.andWhere('state.isActive = :isActive', { isActive: true })
.orderBy('state.name', 'ASC')
.getMany();
}
async create(dto: CreateStateDto): Promise<State> {
logger.info('Creating state', { dto });
// Check if state already exists for this country
const existing = await this.findByCode(dto.countryId, dto.code);
if (existing) {
throw new Error(`Estado con código ${dto.code} ya existe para este país`);
}
const state = this.repository.create({
...dto,
code: dto.code.toUpperCase(),
isActive: dto.isActive ?? true,
});
return this.repository.save(state);
}
async update(id: string, dto: UpdateStateDto): Promise<State> {
logger.info('Updating state', { id, dto });
const state = await this.findById(id);
Object.assign(state, dto);
return this.repository.save(state);
}
async delete(id: string): Promise<void> {
logger.info('Deleting state', { id });
const state = await this.findById(id);
await this.repository.remove(state);
}
async setActive(id: string, isActive: boolean): Promise<State> {
logger.info('Setting state active status', { id, isActive });
const state = await this.findById(id);
state.isActive = isActive;
return this.repository.save(state);
}
}
export const statesService = new StatesService();