shift-swap 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +212 -0
  2. package/dist/core/entities/email.vo.d.ts +7 -0
  3. package/dist/core/entities/funcionario.entity.d.ts +7 -0
  4. package/dist/core/entities/name.vo.d.ts +7 -0
  5. package/dist/core/entities/pessoa.entity.d.ts +21 -0
  6. package/dist/core/entities/solicitacao-troca-turno.entity.d.ts +25 -0
  7. package/dist/core/entities/supervisor.entity.d.ts +7 -0
  8. package/dist/core/entities/turno.entity.d.ts +25 -0
  9. package/dist/core/ports/funcionario.repository.d.ts +5 -0
  10. package/dist/core/ports/solicitacao-troca-turno.repository.d.ts +7 -0
  11. package/dist/core/ports/supervisor.repository.d.ts +5 -0
  12. package/dist/core/ports/turno.repository.d.ts +6 -0
  13. package/dist/core/usecases/__mocks__/funcionario-in-memory.repository.d.ts +11 -0
  14. package/dist/core/usecases/__mocks__/solicitacao-troca-turno-in-memory.repository.d.ts +13 -0
  15. package/dist/core/usecases/__mocks__/supervisor-in-memory.repository.d.ts +11 -0
  16. package/dist/core/usecases/__mocks__/turno-in-memory.repository.d.ts +12 -0
  17. package/dist/core/usecases/aceitar-troca-turno.usecase.d.ts +18 -0
  18. package/dist/core/usecases/atualizar-funcionario.usecase.d.ts +15 -0
  19. package/dist/core/usecases/atualizar-turno.usecase.d.ts +16 -0
  20. package/dist/core/usecases/buscar-funcionario-por-id.usecase.d.ts +13 -0
  21. package/dist/core/usecases/buscar-solicitacao-troca-turno-por-id.usecase.d.ts +13 -0
  22. package/dist/core/usecases/buscar-turno-por-id.usecase.d.ts +13 -0
  23. package/dist/core/usecases/cancelar-troca-turno.usecase.d.ts +14 -0
  24. package/dist/core/usecases/criar-funcionario.usecase.d.ts +15 -0
  25. package/dist/core/usecases/criar-supervisor.usecase.d.ts +15 -0
  26. package/dist/core/usecases/criar-turno.usecase.d.ts +10 -0
  27. package/dist/core/usecases/listar-funcionarios.usecase.d.ts +10 -0
  28. package/dist/core/usecases/listar-solicitacoes-troca-turno.usecase.d.ts +10 -0
  29. package/dist/core/usecases/listar-turnos-disponiveis-para-troca.usecase.d.ts +13 -0
  30. package/dist/core/usecases/listar-turnos-por-funcionario-e-data.usecase.d.ts +14 -0
  31. package/dist/core/usecases/listar-turnos.usecase.d.ts +10 -0
  32. package/dist/core/usecases/remover-funcionario.usecase.d.ts +12 -0
  33. package/dist/core/usecases/remover-turno.usecase.d.ts +12 -0
  34. package/dist/core/usecases/solicitar-troca-turno.usecase.d.ts +16 -0
  35. package/dist/index.cjs +740 -0
  36. package/dist/index.d.ts +29 -0
  37. package/dist/index.js +698 -0
  38. package/dist/shared/either.d.ts +16 -0
  39. package/dist/shared/entity.d.ts +9 -0
  40. package/dist/shared/repository.d.ts +9 -0
  41. package/dist/shared/result.d.ts +13 -0
  42. package/dist/shared/use-case.d.ts +5 -0
  43. package/dist/shared/value-object.d.ts +9 -0
  44. package/package.json +25 -0
package/dist/index.js ADDED
@@ -0,0 +1,698 @@
1
+ // src/shared/result.ts
2
+ class Result {
3
+ isSuccess;
4
+ isFailure;
5
+ error;
6
+ _value;
7
+ constructor(isSuccess, error, value) {
8
+ if (isSuccess && error) {
9
+ throw new Error("InvalidOperation: A result cannot be successful and contain an error");
10
+ }
11
+ if (!isSuccess && !error) {
12
+ throw new Error("InvalidOperation: A failing result needs to contain an error message");
13
+ }
14
+ this.isSuccess = isSuccess;
15
+ this.isFailure = !isSuccess;
16
+ this.error = error;
17
+ this._value = value;
18
+ Object.freeze(this);
19
+ }
20
+ getValue() {
21
+ if (this.isFailure) {
22
+ throw new Error(`Cannot get the value of a failed result. Use 'error' instead. Error: ${this.formatError()}`);
23
+ }
24
+ return this._value;
25
+ }
26
+ static ok(value) {
27
+ return new Result(true, undefined, value);
28
+ }
29
+ static fail(error) {
30
+ return new Result(false, error);
31
+ }
32
+ static combine(results) {
33
+ for (const result of results) {
34
+ if (result.isFailure)
35
+ return result;
36
+ }
37
+ return Result.ok();
38
+ }
39
+ formatError() {
40
+ return this.error instanceof Error ? this.error.message : String(this.error);
41
+ }
42
+ }
43
+ // src/shared/entity.ts
44
+ class Entity {
45
+ _id;
46
+ props;
47
+ constructor(props, id) {
48
+ this._id = id ?? crypto.randomUUID();
49
+ this.props = props;
50
+ }
51
+ get id() {
52
+ return this._id;
53
+ }
54
+ equals(other) {
55
+ if (other == null)
56
+ return false;
57
+ if (this === other)
58
+ return true;
59
+ if (!(other instanceof Entity))
60
+ return false;
61
+ return this._id === other._id;
62
+ }
63
+ toString() {
64
+ return `${this.constructor.name}(${this._id})`;
65
+ }
66
+ }
67
+
68
+ // src/shared/value-object.ts
69
+ class ValueObject {
70
+ value;
71
+ constructor(value) {
72
+ this.value = Object.freeze(value);
73
+ }
74
+ equals(other) {
75
+ if (other == null)
76
+ return false;
77
+ if (!(other instanceof ValueObject))
78
+ return false;
79
+ return ValueObject.isEqual(this.value, other.value);
80
+ }
81
+ isEmpty() {
82
+ if (this.value == null)
83
+ return true;
84
+ if (typeof this.value === "string")
85
+ return this.value.trim().length === 0;
86
+ if (typeof this.value === "number")
87
+ return Number.isNaN(this.value);
88
+ if (Array.isArray(this.value))
89
+ return this.value.length === 0;
90
+ return false;
91
+ }
92
+ toString() {
93
+ return typeof this.value === "object" && this.value !== null ? JSON.stringify(this.value) : String(this.value);
94
+ }
95
+ static isEqual(a, b) {
96
+ if (a === b)
97
+ return true;
98
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) {
99
+ return false;
100
+ }
101
+ const aKeys = Object.keys(a);
102
+ const bKeys = Object.keys(b);
103
+ if (aKeys.length !== bKeys.length)
104
+ return false;
105
+ return aKeys.every((key) => ValueObject.isEqual(a[key], b[key]));
106
+ }
107
+ }
108
+
109
+ // src/core/entities/email.vo.ts
110
+ var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
111
+
112
+ class EmailVO extends ValueObject {
113
+ constructor(value) {
114
+ super(value);
115
+ }
116
+ static create(email) {
117
+ if (!email || email.trim().length === 0) {
118
+ return Result.fail("Email não pode ser vazio");
119
+ }
120
+ if (!EMAIL_REGEX.test(email)) {
121
+ return Result.fail(`Email inválido: ${email}`);
122
+ }
123
+ return Result.ok(new EmailVO(email));
124
+ }
125
+ }
126
+
127
+ // src/core/entities/name.vo.ts
128
+ var MIN_LENGTH = 3;
129
+
130
+ class NameVO extends ValueObject {
131
+ constructor(value) {
132
+ super(value);
133
+ }
134
+ static create(name) {
135
+ if (!name || name.trim().length === 0) {
136
+ return Result.fail("Nome não pode ser vazio");
137
+ }
138
+ if (name.trim().length < MIN_LENGTH) {
139
+ return Result.fail(`Nome deve ter pelo menos ${MIN_LENGTH} caracteres`);
140
+ }
141
+ return Result.ok(new NameVO(name));
142
+ }
143
+ }
144
+
145
+ // src/core/entities/pessoa.entity.ts
146
+ class PessoaEntity extends Entity {
147
+ constructor(props, id) {
148
+ super(props, id);
149
+ }
150
+ get name() {
151
+ return this.props.name;
152
+ }
153
+ get email() {
154
+ return this.props.email;
155
+ }
156
+ atualizarDados(props) {
157
+ const propsOrError = PessoaEntity.buildProps(props);
158
+ if (propsOrError.isFailure) {
159
+ return Result.fail(propsOrError.error);
160
+ }
161
+ this.props = propsOrError.getValue();
162
+ return Result.ok();
163
+ }
164
+ static buildProps(props) {
165
+ const nameOrError = NameVO.create(props.name);
166
+ const emailOrError = EmailVO.create(props.email);
167
+ const combined = Result.combine([nameOrError, emailOrError]);
168
+ if (combined.isFailure) {
169
+ return Result.fail(combined.error);
170
+ }
171
+ return Result.ok({ name: nameOrError.getValue(), email: emailOrError.getValue() });
172
+ }
173
+ static create(props, id) {
174
+ const propsOrError = PessoaEntity.buildProps(props);
175
+ if (propsOrError.isFailure) {
176
+ return Result.fail(propsOrError.error);
177
+ }
178
+ return Result.ok(new PessoaEntity(propsOrError.getValue(), id));
179
+ }
180
+ }
181
+
182
+ // src/core/entities/funcionario.entity.ts
183
+ class FuncionarioEntity extends PessoaEntity {
184
+ constructor(props, id) {
185
+ super(props, id);
186
+ }
187
+ static create(props, id) {
188
+ const propsOrError = FuncionarioEntity.buildProps(props);
189
+ if (propsOrError.isFailure) {
190
+ return Result.fail(propsOrError.error);
191
+ }
192
+ return Result.ok(new FuncionarioEntity(propsOrError.getValue(), id));
193
+ }
194
+ }
195
+ // src/core/entities/supervisor.entity.ts
196
+ class SupervisorEntity extends PessoaEntity {
197
+ constructor(props, id) {
198
+ super(props, id);
199
+ }
200
+ static create(props, id) {
201
+ const propsOrError = SupervisorEntity.buildProps(props);
202
+ if (propsOrError.isFailure) {
203
+ return Result.fail(propsOrError.error);
204
+ }
205
+ return Result.ok(new SupervisorEntity(propsOrError.getValue(), id));
206
+ }
207
+ }
208
+ // src/core/entities/turno.entity.ts
209
+ var DATA_REGEX = /^\d{4}-\d{2}-\d{2}$/;
210
+ var HORA_REGEX = /^([01]\d|2[0-3]):[0-5]\d$/;
211
+
212
+ class Turno extends Entity {
213
+ constructor(props, id) {
214
+ super(props, id);
215
+ }
216
+ get data() {
217
+ return this.props.data;
218
+ }
219
+ get horaInicio() {
220
+ return this.props.horaInicio;
221
+ }
222
+ get horaFim() {
223
+ return this.props.horaFim;
224
+ }
225
+ get funcionarioId() {
226
+ return this.props.funcionarioId;
227
+ }
228
+ reatribuir(novoFuncionarioId) {
229
+ if (!novoFuncionarioId || novoFuncionarioId.trim().length === 0) {
230
+ return Result.fail("Id do novo funcionário não pode ser vazio");
231
+ }
232
+ if (novoFuncionarioId === this.props.funcionarioId) {
233
+ return Result.fail("O turno já pertence a esse funcionário");
234
+ }
235
+ this.props.funcionarioId = novoFuncionarioId;
236
+ return Result.ok();
237
+ }
238
+ atualizarHorario(horario) {
239
+ const validacao = Turno.validarHorario(horario);
240
+ if (validacao.isFailure) {
241
+ return validacao;
242
+ }
243
+ this.props.data = horario.data;
244
+ this.props.horaInicio = horario.horaInicio;
245
+ this.props.horaFim = horario.horaFim;
246
+ return Result.ok();
247
+ }
248
+ static validarHorario(horario) {
249
+ if (!DATA_REGEX.test(horario.data)) {
250
+ return Result.fail(`Data inválida: ${horario.data}`);
251
+ }
252
+ if (!HORA_REGEX.test(horario.horaInicio)) {
253
+ return Result.fail(`Hora de início inválida: ${horario.horaInicio}`);
254
+ }
255
+ if (!HORA_REGEX.test(horario.horaFim)) {
256
+ return Result.fail(`Hora de fim inválida: ${horario.horaFim}`);
257
+ }
258
+ if (horario.horaFim <= horario.horaInicio) {
259
+ return Result.fail("Hora de fim deve ser depois da hora de início");
260
+ }
261
+ return Result.ok();
262
+ }
263
+ static create(props, id) {
264
+ const validacao = Turno.validarHorario(props);
265
+ if (validacao.isFailure) {
266
+ return Result.fail(validacao.error);
267
+ }
268
+ if (!props.funcionarioId || props.funcionarioId.trim().length === 0) {
269
+ return Result.fail("Id do funcionário não pode ser vazio");
270
+ }
271
+ return Result.ok(new Turno({
272
+ data: props.data,
273
+ horaInicio: props.horaInicio,
274
+ horaFim: props.horaFim,
275
+ funcionarioId: props.funcionarioId
276
+ }, id));
277
+ }
278
+ }
279
+ // src/core/entities/solicitacao-troca-turno.entity.ts
280
+ class SolicitacaoTrocaTurno extends Entity {
281
+ constructor(props, id) {
282
+ super(props, id);
283
+ }
284
+ get turno() {
285
+ return this.props.turno;
286
+ }
287
+ get solicitanteId() {
288
+ return this.props.solicitanteId;
289
+ }
290
+ get destinatarioId() {
291
+ return this.props.destinatarioId;
292
+ }
293
+ get status() {
294
+ return this.props.status;
295
+ }
296
+ aceitar(funcionarioId) {
297
+ if (this.props.status !== "pendente") {
298
+ return Result.fail("Solicitação de troca não está mais pendente");
299
+ }
300
+ if (funcionarioId === this.props.solicitanteId) {
301
+ return Result.fail("O solicitante não pode aceitar a própria solicitação");
302
+ }
303
+ const reatribuidoOrError = this.props.turno.reatribuir(funcionarioId);
304
+ if (reatribuidoOrError.isFailure) {
305
+ return Result.fail(reatribuidoOrError.error);
306
+ }
307
+ this.props.destinatarioId = funcionarioId;
308
+ this.props.status = "aceita";
309
+ return Result.ok();
310
+ }
311
+ cancelar() {
312
+ if (this.props.status !== "pendente") {
313
+ return Result.fail("Solicitação de troca não está mais pendente");
314
+ }
315
+ this.props.status = "cancelada";
316
+ return Result.ok();
317
+ }
318
+ static create(props, id) {
319
+ if (props.solicitanteId !== props.turno.funcionarioId) {
320
+ return Result.fail("Somente o funcionário dono do turno pode solicitar a troca");
321
+ }
322
+ return Result.ok(new SolicitacaoTrocaTurno({ turno: props.turno, solicitanteId: props.solicitanteId, status: "pendente" }, id));
323
+ }
324
+ }
325
+ // src/shared/repository.ts
326
+ class Repository {
327
+ }
328
+
329
+ // src/core/ports/funcionario.repository.ts
330
+ class FuncionarioRepository extends Repository {
331
+ }
332
+ // src/core/ports/supervisor.repository.ts
333
+ class SupervisorRepository extends Repository {
334
+ }
335
+ // src/core/ports/turno.repository.ts
336
+ class TurnoRepository extends Repository {
337
+ }
338
+ // src/core/ports/solicitacao-troca-turno.repository.ts
339
+ class SolicitacaoTrocaTurnoRepository extends Repository {
340
+ }
341
+ // src/shared/use-case.ts
342
+ class UseCase {
343
+ }
344
+
345
+ // src/core/usecases/criar-funcionario.usecase.ts
346
+ class CriarFuncionarioUseCase extends UseCase {
347
+ funcionarioRepository;
348
+ constructor(funcionarioRepository) {
349
+ super();
350
+ this.funcionarioRepository = funcionarioRepository;
351
+ }
352
+ async execute(input) {
353
+ const funcionarioOrError = FuncionarioEntity.create(input, input.id);
354
+ if (funcionarioOrError.isFailure) {
355
+ return Result.fail(funcionarioOrError.error);
356
+ }
357
+ const funcionario = funcionarioOrError.getValue();
358
+ await this.funcionarioRepository.save(funcionario);
359
+ return Result.ok(funcionario);
360
+ }
361
+ }
362
+ // src/core/usecases/buscar-funcionario-por-id.usecase.ts
363
+ class BuscarFuncionarioPorIdUseCase extends UseCase {
364
+ funcionarioRepository;
365
+ constructor(funcionarioRepository) {
366
+ super();
367
+ this.funcionarioRepository = funcionarioRepository;
368
+ }
369
+ async execute(input) {
370
+ const funcionario = await this.funcionarioRepository.findById(input.id);
371
+ if (!funcionario) {
372
+ return Result.fail("Funcionário não encontrado");
373
+ }
374
+ return Result.ok(funcionario);
375
+ }
376
+ }
377
+ // src/core/usecases/listar-funcionarios.usecase.ts
378
+ class ListarFuncionariosUseCase extends UseCase {
379
+ funcionarioRepository;
380
+ constructor(funcionarioRepository) {
381
+ super();
382
+ this.funcionarioRepository = funcionarioRepository;
383
+ }
384
+ async execute() {
385
+ const funcionarios = await this.funcionarioRepository.findAll();
386
+ return Result.ok(funcionarios);
387
+ }
388
+ }
389
+ // src/core/usecases/atualizar-funcionario.usecase.ts
390
+ class AtualizarFuncionarioUseCase extends UseCase {
391
+ funcionarioRepository;
392
+ constructor(funcionarioRepository) {
393
+ super();
394
+ this.funcionarioRepository = funcionarioRepository;
395
+ }
396
+ async execute(input) {
397
+ const funcionario = await this.funcionarioRepository.findById(input.id);
398
+ if (!funcionario) {
399
+ return Result.fail("Funcionário não encontrado");
400
+ }
401
+ const atualizarOrError = funcionario.atualizarDados({ name: input.name, email: input.email });
402
+ if (atualizarOrError.isFailure) {
403
+ return Result.fail(atualizarOrError.error);
404
+ }
405
+ await this.funcionarioRepository.update(funcionario);
406
+ return Result.ok(funcionario);
407
+ }
408
+ }
409
+ // src/core/usecases/remover-funcionario.usecase.ts
410
+ class RemoverFuncionarioUseCase extends UseCase {
411
+ funcionarioRepository;
412
+ constructor(funcionarioRepository) {
413
+ super();
414
+ this.funcionarioRepository = funcionarioRepository;
415
+ }
416
+ async execute(input) {
417
+ const funcionario = await this.funcionarioRepository.findById(input.id);
418
+ if (!funcionario) {
419
+ return Result.fail("Funcionário não encontrado");
420
+ }
421
+ await this.funcionarioRepository.delete(input.id);
422
+ return Result.ok();
423
+ }
424
+ }
425
+ // src/core/usecases/criar-supervisor.usecase.ts
426
+ class CriarSupervisorUseCase extends UseCase {
427
+ supervisorRepository;
428
+ constructor(supervisorRepository) {
429
+ super();
430
+ this.supervisorRepository = supervisorRepository;
431
+ }
432
+ async execute(input) {
433
+ const supervisorOrError = SupervisorEntity.create(input, input.id);
434
+ if (supervisorOrError.isFailure) {
435
+ return Result.fail(supervisorOrError.error);
436
+ }
437
+ const supervisor = supervisorOrError.getValue();
438
+ await this.supervisorRepository.save(supervisor);
439
+ return Result.ok(supervisor);
440
+ }
441
+ }
442
+ // src/core/usecases/criar-turno.usecase.ts
443
+ class CriarTurnoUseCase extends UseCase {
444
+ turnoRepository;
445
+ constructor(turnoRepository) {
446
+ super();
447
+ this.turnoRepository = turnoRepository;
448
+ }
449
+ async execute(input) {
450
+ const turnoOrError = Turno.create(input);
451
+ if (turnoOrError.isFailure) {
452
+ return Result.fail(turnoOrError.error);
453
+ }
454
+ const turno = turnoOrError.getValue();
455
+ await this.turnoRepository.save(turno);
456
+ return Result.ok(turno);
457
+ }
458
+ }
459
+ // src/core/usecases/buscar-turno-por-id.usecase.ts
460
+ class BuscarTurnoPorIdUseCase extends UseCase {
461
+ turnoRepository;
462
+ constructor(turnoRepository) {
463
+ super();
464
+ this.turnoRepository = turnoRepository;
465
+ }
466
+ async execute(input) {
467
+ const turno = await this.turnoRepository.findById(input.id);
468
+ if (!turno) {
469
+ return Result.fail("Turno não encontrado");
470
+ }
471
+ return Result.ok(turno);
472
+ }
473
+ }
474
+ // src/core/usecases/listar-turnos.usecase.ts
475
+ class ListarTurnosUseCase extends UseCase {
476
+ turnoRepository;
477
+ constructor(turnoRepository) {
478
+ super();
479
+ this.turnoRepository = turnoRepository;
480
+ }
481
+ async execute() {
482
+ const turnos = await this.turnoRepository.findAll();
483
+ return Result.ok(turnos);
484
+ }
485
+ }
486
+ // src/core/usecases/atualizar-turno.usecase.ts
487
+ class AtualizarTurnoUseCase extends UseCase {
488
+ turnoRepository;
489
+ constructor(turnoRepository) {
490
+ super();
491
+ this.turnoRepository = turnoRepository;
492
+ }
493
+ async execute(input) {
494
+ const turno = await this.turnoRepository.findById(input.id);
495
+ if (!turno) {
496
+ return Result.fail("Turno não encontrado");
497
+ }
498
+ const atualizarOrError = turno.atualizarHorario({
499
+ data: input.data,
500
+ horaInicio: input.horaInicio,
501
+ horaFim: input.horaFim
502
+ });
503
+ if (atualizarOrError.isFailure) {
504
+ return Result.fail(atualizarOrError.error);
505
+ }
506
+ await this.turnoRepository.update(turno);
507
+ return Result.ok(turno);
508
+ }
509
+ }
510
+ // src/core/usecases/remover-turno.usecase.ts
511
+ class RemoverTurnoUseCase extends UseCase {
512
+ turnoRepository;
513
+ constructor(turnoRepository) {
514
+ super();
515
+ this.turnoRepository = turnoRepository;
516
+ }
517
+ async execute(input) {
518
+ const turno = await this.turnoRepository.findById(input.id);
519
+ if (!turno) {
520
+ return Result.fail("Turno não encontrado");
521
+ }
522
+ await this.turnoRepository.delete(input.id);
523
+ return Result.ok();
524
+ }
525
+ }
526
+ // src/core/usecases/listar-turnos-por-funcionario-e-data.usecase.ts
527
+ class ListarTurnosPorFuncionarioEDataUseCase extends UseCase {
528
+ turnoRepository;
529
+ constructor(turnoRepository) {
530
+ super();
531
+ this.turnoRepository = turnoRepository;
532
+ }
533
+ async execute(input) {
534
+ const turnos = await this.turnoRepository.findByFuncionarioIdAndData(input.funcionarioId, input.data);
535
+ return Result.ok(turnos);
536
+ }
537
+ }
538
+ // src/core/usecases/solicitar-troca-turno.usecase.ts
539
+ class SolicitarTrocaTurnoUseCase extends UseCase {
540
+ turnoRepository;
541
+ solicitacaoRepository;
542
+ constructor(turnoRepository, solicitacaoRepository) {
543
+ super();
544
+ this.turnoRepository = turnoRepository;
545
+ this.solicitacaoRepository = solicitacaoRepository;
546
+ }
547
+ async execute(input) {
548
+ const turno = await this.turnoRepository.findById(input.turnoId);
549
+ if (!turno) {
550
+ return Result.fail("Turno não encontrado");
551
+ }
552
+ const pendentes = await this.solicitacaoRepository.findPendentesByTurnoId(turno.id);
553
+ if (pendentes.length > 0) {
554
+ return Result.fail("Já existe uma solicitação pendente para esse turno");
555
+ }
556
+ const solicitacaoOrError = SolicitacaoTrocaTurno.create({
557
+ turno,
558
+ solicitanteId: input.solicitanteId
559
+ });
560
+ if (solicitacaoOrError.isFailure) {
561
+ return Result.fail(solicitacaoOrError.error);
562
+ }
563
+ const solicitacao = solicitacaoOrError.getValue();
564
+ await this.solicitacaoRepository.save(solicitacao);
565
+ return Result.ok(solicitacao);
566
+ }
567
+ }
568
+ // src/core/usecases/aceitar-troca-turno.usecase.ts
569
+ function horariosSeSobrepoem(a, b) {
570
+ return a.horaInicio < b.horaFim && b.horaInicio < a.horaFim;
571
+ }
572
+
573
+ class AceitarTrocaTurnoUseCase extends UseCase {
574
+ funcionarioRepository;
575
+ turnoRepository;
576
+ solicitacaoRepository;
577
+ constructor(funcionarioRepository, turnoRepository, solicitacaoRepository) {
578
+ super();
579
+ this.funcionarioRepository = funcionarioRepository;
580
+ this.turnoRepository = turnoRepository;
581
+ this.solicitacaoRepository = solicitacaoRepository;
582
+ }
583
+ async execute(input) {
584
+ const solicitacao = await this.solicitacaoRepository.findById(input.solicitacaoId);
585
+ if (!solicitacao) {
586
+ return Result.fail("Solicitação não encontrada");
587
+ }
588
+ const funcionario = await this.funcionarioRepository.findById(input.funcionarioId);
589
+ if (!funcionario) {
590
+ return Result.fail("Funcionário não encontrado");
591
+ }
592
+ const turnosDoFuncionario = await this.turnoRepository.findByFuncionarioIdAndData(input.funcionarioId, solicitacao.turno.data);
593
+ const temConflito = turnosDoFuncionario.some((turno) => horariosSeSobrepoem(turno, solicitacao.turno));
594
+ if (temConflito) {
595
+ return Result.fail("Funcionário já possui um turno nesse horário");
596
+ }
597
+ const aceitarOrError = solicitacao.aceitar(input.funcionarioId);
598
+ if (aceitarOrError.isFailure) {
599
+ return Result.fail(aceitarOrError.error);
600
+ }
601
+ await this.turnoRepository.update(solicitacao.turno);
602
+ await this.solicitacaoRepository.update(solicitacao);
603
+ return Result.ok(solicitacao);
604
+ }
605
+ }
606
+ // src/core/usecases/cancelar-troca-turno.usecase.ts
607
+ class CancelarTrocaTurnoUseCase extends UseCase {
608
+ solicitacaoRepository;
609
+ constructor(solicitacaoRepository) {
610
+ super();
611
+ this.solicitacaoRepository = solicitacaoRepository;
612
+ }
613
+ async execute(input) {
614
+ const solicitacao = await this.solicitacaoRepository.findById(input.solicitacaoId);
615
+ if (!solicitacao) {
616
+ return Result.fail("Solicitação não encontrada");
617
+ }
618
+ if (solicitacao.solicitanteId !== input.solicitanteId) {
619
+ return Result.fail("Somente o solicitante pode cancelar a solicitação");
620
+ }
621
+ const cancelarOrError = solicitacao.cancelar();
622
+ if (cancelarOrError.isFailure) {
623
+ return Result.fail(cancelarOrError.error);
624
+ }
625
+ await this.solicitacaoRepository.update(solicitacao);
626
+ return Result.ok(solicitacao);
627
+ }
628
+ }
629
+ // src/core/usecases/buscar-solicitacao-troca-turno-por-id.usecase.ts
630
+ class BuscarSolicitacaoTrocaTurnoPorIdUseCase extends UseCase {
631
+ solicitacaoRepository;
632
+ constructor(solicitacaoRepository) {
633
+ super();
634
+ this.solicitacaoRepository = solicitacaoRepository;
635
+ }
636
+ async execute(input) {
637
+ const solicitacao = await this.solicitacaoRepository.findById(input.id);
638
+ if (!solicitacao) {
639
+ return Result.fail("Solicitação não encontrada");
640
+ }
641
+ return Result.ok(solicitacao);
642
+ }
643
+ }
644
+ // src/core/usecases/listar-solicitacoes-troca-turno.usecase.ts
645
+ class ListarSolicitacoesTrocaTurnoUseCase extends UseCase {
646
+ solicitacaoRepository;
647
+ constructor(solicitacaoRepository) {
648
+ super();
649
+ this.solicitacaoRepository = solicitacaoRepository;
650
+ }
651
+ async execute() {
652
+ const solicitacoes = await this.solicitacaoRepository.findAll();
653
+ return Result.ok(solicitacoes);
654
+ }
655
+ }
656
+ // src/core/usecases/listar-turnos-disponiveis-para-troca.usecase.ts
657
+ class ListarTurnosDisponiveisParaTrocaUseCase extends UseCase {
658
+ solicitacaoRepository;
659
+ constructor(solicitacaoRepository) {
660
+ super();
661
+ this.solicitacaoRepository = solicitacaoRepository;
662
+ }
663
+ async execute(input) {
664
+ const solicitacoes = await this.solicitacaoRepository.findPendentesExcetoSolicitante(input.funcionarioId);
665
+ return Result.ok(solicitacoes);
666
+ }
667
+ }
668
+ export {
669
+ AceitarTrocaTurnoUseCase,
670
+ AtualizarFuncionarioUseCase,
671
+ AtualizarTurnoUseCase,
672
+ BuscarFuncionarioPorIdUseCase,
673
+ BuscarSolicitacaoTrocaTurnoPorIdUseCase,
674
+ BuscarTurnoPorIdUseCase,
675
+ CancelarTrocaTurnoUseCase,
676
+ CriarFuncionarioUseCase,
677
+ CriarSupervisorUseCase,
678
+ CriarTurnoUseCase,
679
+ EmailVO,
680
+ FuncionarioEntity,
681
+ FuncionarioRepository,
682
+ ListarFuncionariosUseCase,
683
+ ListarSolicitacoesTrocaTurnoUseCase,
684
+ ListarTurnosDisponiveisParaTrocaUseCase,
685
+ ListarTurnosPorFuncionarioEDataUseCase,
686
+ ListarTurnosUseCase,
687
+ NameVO,
688
+ RemoverFuncionarioUseCase,
689
+ RemoverTurnoUseCase,
690
+ Result,
691
+ SolicitacaoTrocaTurno,
692
+ SolicitacaoTrocaTurnoRepository,
693
+ SolicitarTrocaTurnoUseCase,
694
+ SupervisorEntity,
695
+ SupervisorRepository,
696
+ Turno,
697
+ TurnoRepository
698
+ };
@@ -0,0 +1,16 @@
1
+ declare class Left<L, R> {
2
+ readonly value: L;
3
+ constructor(value: L);
4
+ isLeft(): this is Left<L, R>;
5
+ isRight(): this is Right<L, R>;
6
+ }
7
+ declare class Right<L, R> {
8
+ readonly value: R;
9
+ constructor(value: R);
10
+ isLeft(): this is Left<L, R>;
11
+ isRight(): this is Right<L, R>;
12
+ }
13
+ type Either<L, R> = Left<L, R> | Right<L, R>;
14
+ declare const left: <L, R>(value: L) => Either<L, R>;
15
+ declare const right: <L, R>(value: R) => Either<L, R>;
16
+ export { Either, Left, Right, left, right };