Skip to content

Commit 254db29

Browse files
authored
Merge pull request #1695 from mdavila-2001/ender/far-03-simulador-vigencia-dev
FAR-03 · seguimiento: una receta sin fin de vigencia no vence en el simulador
2 parents 6c38386 + f266aa9 commit 254db29

5 files changed

Lines changed: 69 additions & 10 deletions

File tree

‎src/app/core/mock/fixtures/clinic.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ export interface SimulatedPrescription {
115115
readonly doseText: string;
116116
readonly frequencyText: string;
117117
readonly validFrom: string;
118-
readonly validTo: string;
118+
readonly validTo: string | null; // `null`: sin fin de vigencia, como en la API
119119
readonly patientInstructionsText: string;
120120
readonly signedAt: string | null;
121121
readonly issuedAt: string | null;

‎src/app/core/mock/fixtures/concepts.ts‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -999,10 +999,7 @@ export const ENCOUNTER_STATUS = define('VS_ENCOUNTER_STATUS', [
999999
['ENCST-CANCELLED', 'Cancelado'],
10001000
]);
10011001

1002-
conjunto('VS_MEDICATION_REQUEST_STATUS', 'Estado de la receta', 'Estado de una prescripción.');
1003-
// Los códigos son los de la API (`clinical.concepts.ts`, `MEDICATION_REQUEST_*`):
1004-
// el front decide qué receta se puede pedir por el código (`MR_ISSUED`, FAR-03),
1005-
// así que el simulador no puede inventar los suyos.
1002+
conjunto('VS_MEDICATION_REQUEST_STATUS', 'Estado de la receta', 'Estado de una prescripción.'); // códigos de la API (FAR-03)
10061003
export const PRESCRIPTION_STATUS = define('VS_MEDICATION_REQUEST_STATUS', [
10071004
['MR_ISSUED', 'Vigente'],
10081005
['MR_COMPLETED', 'Completada'],

‎src/app/core/mock/handlers/clinical.handlers.spec.ts‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,31 @@ describe('POST /clinical/medication-requests · sólo diagnóstico confirmado o
270270
expect(prescriptionList.get(id)?.statusConceptId).toBe(PRESCRIPTION_STATUS['MR_ISSUED']);
271271
expect(prescriptionList.get(id)?.issuedAt).not.toBeNull();
272272
});
273+
274+
/*
275+
* FAR-03: como en la API (`medications.service.ts`, el alta deja `validTo`
276+
* vacío si no viene), una receta sin fin de vigencia no vence. Antes el
277+
* simulador le ponía «ahora» y, ya emitida, salía vencida en «Dónde comprar».
278+
*/
279+
it('una receta continua (sin validTo) se emite sin vencimiento; con validTo lo conserva', () => {
280+
const continua = call<MockReply>('POST', '/clinical/medication-requests', {
281+
...CUERPO_BASE,
282+
indicationText: 'Tratamiento crónico',
283+
});
284+
const id = (continua.body as { id: string }).id;
285+
call('POST', `/clinical/medication-requests/${id}/sign`, {});
286+
call('POST', `/clinical/medication-requests/${id}/issue`, {});
287+
288+
expect(prescriptionList.get(id)?.statusConceptId).toBe(PRESCRIPTION_STATUS['MR_ISSUED']);
289+
expect(prescriptionList.get(id)?.validTo).toBeNull();
290+
291+
const conFin = call<MockReply>('POST', '/clinical/medication-requests', {
292+
...CUERPO_BASE,
293+
indicationText: 'Antibiótico por diez días',
294+
validTo: '2099-01-10T00:00:00.000Z',
295+
});
296+
expect(prescriptionList.get((conFin.body as { id: string }).id)?.validTo).toBe('2099-01-10T00:00:00.000Z');
297+
});
273298
});
274299

275300
describe('/charts/notes · contrato tras mudar el handler', () => {

‎src/app/core/mock/handlers/clinical.handlers.ts‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ export function registrarClinica(router: MockRouter): void {
312312
doseText: datos.doseText ?? '',
313313
frequencyText: datos.frequencyText ?? '',
314314
validFrom: datos.validFrom ?? ahora(),
315-
validTo: datos.validTo ?? ahora(),
315+
validTo: datos.validTo ?? null, // sin `validTo` no vence, como en la API
316316
patientInstructionsText: datos.patientInstructionsText ?? '',
317317
// El «para qué es» de la receta. El concepto gana sobre el texto libre,
318318
// igual que la ocupación del alta de paciente: el texto sólo tenía
@@ -360,9 +360,7 @@ export function registrarClinica(router: MockRouter): void {
360360
router.post('/clinical/medication-requests/:id/sign', ({ params }) => {
361361
const r = prescriptionList.get(params['id']!);
362362
if (r === undefined) return notFound();
363-
// Firmar sólo sella `signedAt`: la receta sigue en borrador hasta emitirse,
364-
// como en la API (`medications.service.ts`, `sign` no cambia el estado).
365-
return registroReceta(prescriptionList.actualizar(r.id, { signedAt: ahora() })!);
363+
return registroReceta(prescriptionList.actualizar(r.id, { signedAt: ahora() })!); // firmar no emite, como en la API
366364
});
367365

368366
router.post('/clinical/medication-requests/:id/issue', ({ params }) => {

‎src/app/features/account/medical-record/where-to-buy/orderable-prescription.spec.ts‎

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1+
import { HttpHeaders } from '@angular/common/http';
2+
13
import type { MedicationRequest } from '../../../../core/data-access/clinical/clinical.types';
24
import type { ConceptLabels } from '../../../../core/data-access/terminology/terminology.types';
35
import { prescriptionList, type SimulatedPrescription } from '../../../../core/mock/fixtures/clinic';
46
import { record } from '../../../../core/mock/fixtures/concepts';
7+
import { PACIENTE } from '../../../../core/mock/fixtures/people';
8+
import { registrarClinica } from '../../../../core/mock/handlers/clinical.handlers';
9+
import { MockRouter, type MockMethod, type MockReply } from '../../../../core/mock/mock-router';
10+
import { buscarUsuario, type MockUser } from '../../../../core/mock/mock-session';
511
import { isOrderableRow, orderablePrescriptionOf } from './orderable-prescription';
612

713
/** Una fila del resumen clínico de la receta `enc-a`, con lo mínimo que se mira. */
@@ -125,7 +131,7 @@ describe('el simulador usa los códigos de estado de la API (FAR-03)', () => {
125131
medicationConceptId: rx.medicationConceptId,
126132
statusConceptId: rx.statusConceptId,
127133
createdAt: new Date(rx.createdAt),
128-
validTo: new Date(rx.validTo),
134+
...(rx.validTo === null ? {} : { validTo: new Date(rx.validTo) }),
129135
...(rx.issuedAt === null ? {} : { issuedAt: new Date(rx.issuedAt) }),
130136
...(rx.encounterId === undefined ? {} : { encounterId: rx.encounterId }),
131137
};
@@ -149,6 +155,39 @@ describe('el simulador usa los códigos de estado de la API (FAR-03)', () => {
149155
}
150156
});
151157

158+
it('una receta continua creada y emitida en el simulador (sin validTo) se puede pedir', () => {
159+
const router = new MockRouter();
160+
registrarClinica(router);
161+
const medica = buscarUsuario('medica')!;
162+
const call = (method: MockMethod, path: string, body: unknown): MockReply => {
163+
const match = router.match(method, path);
164+
if (match === null) throw new Error(`No existe ${method} ${path}`);
165+
return match.handler({
166+
method,
167+
path,
168+
params: match.params,
169+
query: new URLSearchParams(),
170+
body,
171+
headers: new HttpHeaders(),
172+
user: medica as MockUser,
173+
}) as MockReply;
174+
};
175+
176+
const created = call('POST', '/clinical/medication-requests', {
177+
patientProfileId: PACIENTE.id,
178+
medicationConceptId: 'med-continua',
179+
indicationText: 'Tratamiento crónico',
180+
});
181+
const id = (created.body as { id: string }).id;
182+
call('POST', `/clinical/medication-requests/${id}/sign`, {});
183+
call('POST', `/clinical/medication-requests/${id}/issue`, {});
184+
185+
const issued = prescriptionList.get(id)!;
186+
const asRead = asRequest(issued);
187+
expect(asRead.validTo).toBeUndefined();
188+
expect(isOrderableRow(asRead, mockLabels, new Date())).toBe(true);
189+
});
190+
152191
it('el catálogo simulado ya no tiene los códigos propios del simulador', () => {
153192
for (const code of ['RX-ACTIVE', 'RX-DRAFT', 'RX-COMPLETED', 'RX-CANCELLED']) {
154193
expect(record.has(code)).toBe(false);

0 commit comments

Comments
 (0)