Branches: - 5 services: branch, schedule, inventory-settings, payment-terminal, user-assignment - Hierarchical management, schedules, terminals Products: - 6 services: category, product, price, supplier, attribute, variant - Hierarchical categories, multi-pricing, variants Projects: - 6 services: project, task, timesheet, milestone, member, stage - Kanban support, timesheet approval workflow Sales: - 2 services: quotation, sales-order - Full sales workflow with quotation-to-order conversion Invoices: - 2 services: invoice, payment - Complete invoicing with payment allocation Notifications: - 5 services: notification, preference, template, channel, in-app - Multi-channel support (email, sms, push, whatsapp, in-app) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
207 lines
5.4 KiB
TypeScript
207 lines
5.4 KiB
TypeScript
/**
|
|
* BranchSchedule Service
|
|
* Servicio para gestión de horarios de sucursales
|
|
*
|
|
* @module Branches
|
|
*/
|
|
|
|
import { Repository, FindOptionsWhere } from 'typeorm';
|
|
import { AppDataSource } from '../../../shared/database/typeorm.config';
|
|
import { BranchSchedule, ScheduleType } from '../entities/branch-schedule.entity';
|
|
import { ServiceContext } from './branch.service';
|
|
|
|
export interface CreateBranchScheduleDto {
|
|
branchId: string;
|
|
name: string;
|
|
description?: string;
|
|
scheduleType?: ScheduleType;
|
|
dayOfWeek?: number;
|
|
specificDate?: Date;
|
|
openTime: string;
|
|
closeTime: string;
|
|
shifts?: Array<{ name: string; start: string; end: string }>;
|
|
isActive?: boolean;
|
|
}
|
|
|
|
export interface UpdateBranchScheduleDto {
|
|
name?: string;
|
|
description?: string;
|
|
scheduleType?: ScheduleType;
|
|
dayOfWeek?: number;
|
|
specificDate?: Date;
|
|
openTime?: string;
|
|
closeTime?: string;
|
|
shifts?: Array<{ name: string; start: string; end: string }>;
|
|
isActive?: boolean;
|
|
}
|
|
|
|
export interface BranchScheduleFilters {
|
|
branchId?: string;
|
|
scheduleType?: ScheduleType;
|
|
dayOfWeek?: number;
|
|
isActive?: boolean;
|
|
}
|
|
|
|
export class BranchScheduleService {
|
|
private repository: Repository<BranchSchedule>;
|
|
|
|
constructor() {
|
|
this.repository = AppDataSource.getRepository(BranchSchedule);
|
|
}
|
|
|
|
async findAll(_ctx: ServiceContext, filters?: BranchScheduleFilters): Promise<BranchSchedule[]> {
|
|
const where: FindOptionsWhere<BranchSchedule> = {};
|
|
|
|
if (filters?.branchId) {
|
|
where.branchId = filters.branchId;
|
|
}
|
|
|
|
if (filters?.scheduleType) {
|
|
where.scheduleType = filters.scheduleType;
|
|
}
|
|
|
|
if (filters?.dayOfWeek !== undefined) {
|
|
where.dayOfWeek = filters.dayOfWeek;
|
|
}
|
|
|
|
if (filters?.isActive !== undefined) {
|
|
where.isActive = filters.isActive;
|
|
}
|
|
|
|
return this.repository.find({
|
|
where,
|
|
relations: ['branch'],
|
|
order: { dayOfWeek: 'ASC', openTime: 'ASC' },
|
|
});
|
|
}
|
|
|
|
async findById(_ctx: ServiceContext, id: string): Promise<BranchSchedule | null> {
|
|
return this.repository.findOne({
|
|
where: { id },
|
|
relations: ['branch'],
|
|
});
|
|
}
|
|
|
|
async findByBranch(_ctx: ServiceContext, branchId: string): Promise<BranchSchedule[]> {
|
|
return this.repository.find({
|
|
where: { branchId, isActive: true },
|
|
order: { dayOfWeek: 'ASC', openTime: 'ASC' },
|
|
});
|
|
}
|
|
|
|
async findRegularSchedule(_ctx: ServiceContext, branchId: string): Promise<BranchSchedule[]> {
|
|
return this.repository.find({
|
|
where: { branchId, scheduleType: 'regular', isActive: true },
|
|
order: { dayOfWeek: 'ASC' },
|
|
});
|
|
}
|
|
|
|
async findHolidaySchedule(_ctx: ServiceContext, branchId: string): Promise<BranchSchedule[]> {
|
|
return this.repository.find({
|
|
where: { branchId, scheduleType: 'holiday', isActive: true },
|
|
order: { specificDate: 'ASC' },
|
|
});
|
|
}
|
|
|
|
async findScheduleForDate(
|
|
_ctx: ServiceContext,
|
|
branchId: string,
|
|
date: Date
|
|
): Promise<BranchSchedule | null> {
|
|
// First check for specific date (holiday or special)
|
|
const specificSchedule = await this.repository.findOne({
|
|
where: {
|
|
branchId,
|
|
specificDate: date,
|
|
isActive: true,
|
|
},
|
|
});
|
|
|
|
if (specificSchedule) {
|
|
return specificSchedule;
|
|
}
|
|
|
|
// Fall back to regular schedule for day of week
|
|
const dayOfWeek = date.getDay();
|
|
return this.repository.findOne({
|
|
where: {
|
|
branchId,
|
|
scheduleType: 'regular',
|
|
dayOfWeek,
|
|
isActive: true,
|
|
},
|
|
});
|
|
}
|
|
|
|
async create(_ctx: ServiceContext, data: CreateBranchScheduleDto): Promise<BranchSchedule> {
|
|
const schedule = this.repository.create(data);
|
|
return this.repository.save(schedule);
|
|
}
|
|
|
|
async update(
|
|
ctx: ServiceContext,
|
|
id: string,
|
|
data: UpdateBranchScheduleDto
|
|
): Promise<BranchSchedule | null> {
|
|
const schedule = await this.findById(ctx, id);
|
|
if (!schedule) {
|
|
return null;
|
|
}
|
|
|
|
Object.assign(schedule, data);
|
|
return this.repository.save(schedule);
|
|
}
|
|
|
|
async delete(_ctx: ServiceContext, id: string): Promise<boolean> {
|
|
const result = await this.repository.delete({ id });
|
|
return result.affected ? result.affected > 0 : false;
|
|
}
|
|
|
|
async createWeeklySchedule(
|
|
_ctx: ServiceContext,
|
|
branchId: string,
|
|
weeklyHours: Array<{
|
|
dayOfWeek: number;
|
|
openTime: string;
|
|
closeTime: string;
|
|
shifts?: Array<{ name: string; start: string; end: string }>;
|
|
}>
|
|
): Promise<BranchSchedule[]> {
|
|
// Delete existing regular schedules for this branch
|
|
await this.repository.delete({
|
|
branchId,
|
|
scheduleType: 'regular',
|
|
});
|
|
|
|
// Create new schedules
|
|
const schedules = weeklyHours.map(hours =>
|
|
this.repository.create({
|
|
branchId,
|
|
name: `Regular - Day ${hours.dayOfWeek}`,
|
|
scheduleType: 'regular',
|
|
dayOfWeek: hours.dayOfWeek,
|
|
openTime: hours.openTime,
|
|
closeTime: hours.closeTime,
|
|
shifts: hours.shifts || [],
|
|
isActive: true,
|
|
})
|
|
);
|
|
|
|
return this.repository.save(schedules);
|
|
}
|
|
|
|
async isBranchOpenAt(
|
|
ctx: ServiceContext,
|
|
branchId: string,
|
|
dateTime: Date
|
|
): Promise<boolean> {
|
|
const schedule = await this.findScheduleForDate(ctx, branchId, dateTime);
|
|
if (!schedule) {
|
|
return false;
|
|
}
|
|
|
|
const timeStr = dateTime.toTimeString().slice(0, 5); // HH:MM format
|
|
return timeStr >= schedule.openTime && timeStr <= schedule.closeTime;
|
|
}
|
|
}
|