Skip to content

Commit 683bbed

Browse files
fixNotification1 (#174)
FIx sulla chiamata checkresultList
1 parent df61a85 commit 683bbed

File tree

4 files changed

+136
-121
lines changed

4 files changed

+136
-121
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "pn-local-validator",
3-
"version": "2.5.3",
3+
"version": "2.5.4",
44
"description": "A system that emulates some features of Piattaforma Notifiche platform.",
55
"main": "dist/main.js",
66
"scripts": {

src/domain/Notification.ts

Lines changed: 100 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable functional/immutable-data */
22
/* eslint-disable sonarjs/cognitive-complexity */
3-
3+
44
import * as M from 'fp-ts/Monoid';
55
import * as O from 'fp-ts/Option';
66
import * as RA from 'fp-ts/ReadonlyArray';
@@ -21,32 +21,33 @@ import {
2121
} from './GetNotificationDetailRecord';
2222
import { NotificationRequest, makeNotificationRequestFromFind } from './NotificationRequest';
2323
import { updateTimeline } from './TimelineElement';
24+
import { Response } from './types';
2425

2526
export type Notification = FullSentNotificationV27 & Pick<NotificationRequest, 'notificationRequestId'>;
2627

27-
export const mkNotification = (env: DomainEnv, notificationRequest: NotificationRequest, iun: IUN) => ({
28+
export const mkNotification = (env: DomainEnv, notificationRequest: NotificationRequest, iun: IUN): Notification => ({
2829
notificationRequestId: notificationRequest.notificationRequestId,
2930
...makeFullSentNotification(env)(notificationRequest)(iun),
3031
});
3132

33+
/** ---------- IUN helpers ---------- */
3234
const getIunFromFind =
33-
(notificationRequest: NotificationRequest) => (findNotificationRequestRecord: CheckNotificationStatusRecord) =>
35+
(notificationRequest: NotificationRequest) => (findRecord: CheckNotificationStatusRecord) =>
3436
pipe(
35-
findNotificationRequestRecord.output.statusCode === 200
36-
? O.some(findNotificationRequestRecord.output.returned)
37-
: O.none,
37+
findRecord.output.statusCode === 200 ? O.some(findRecord.output.returned) : O.none,
3838
O.filter((e) => e.notificationRequestId === notificationRequest.notificationRequestId),
3939
O.filterMap((e) => O.fromNullable(e.iun))
4040
);
4141

4242
const getIunFromConsume =
43-
(notificationRequest: NotificationRequest) => (consumeEventStreamRecord: ConsumeEventStreamRecord) =>
43+
(notificationRequest: NotificationRequest) => (consumeRecord: ConsumeEventStreamRecord) =>
4444
pipe(
45-
getProgressResponseList([consumeEventStreamRecord]),
45+
getProgressResponseList([consumeRecord]),
4646
RA.findLast((e) => e.notificationRequestId === notificationRequest.notificationRequestId),
4747
O.filterMap(({ iun }) => pipe(IUN.decode(iun), O.fromEither))
4848
);
4949

50+
/** ---------- Counters ---------- */
5051
const countFromFind = (notificationRequestId: string) =>
5152
flow(
5253
RA.filterMap(makeNotificationRequestFromFind),
@@ -57,7 +58,6 @@ const countFromFind = (notificationRequestId: string) =>
5758
const countFromConsume = (notificationRequestId: string) =>
5859
flow(
5960
RA.filterMap(getProgressResponse),
60-
// for each page remove duplicated notificationRequestId
6161
RA.map(
6262
flow(
6363
RA.filterMap((e) => O.fromNullable(e.notificationRequestId)),
@@ -77,7 +77,8 @@ const countFromDetail = (iun: IUN) =>
7777
RA.size
7878
);
7979

80-
const makeStatus = (env: DomainEnv, occurrences: number) =>
80+
/** ---------- Status from occurrences ---------- */
81+
const makeStatus = (env: DomainEnv, occurrences: number): O.Option<NotificationStatusV26Enum> =>
8182
env.occurrencesToDelivering <= occurrences && occurrences < env.occurrencesToDelivered
8283
? O.some(NotificationStatusV26Enum.DELIVERING)
8384
: env.occurrencesToDelivered <= occurrences && occurrences < env.occurrencesToViewed
@@ -86,14 +87,22 @@ const makeStatus = (env: DomainEnv, occurrences: number) =>
8687
? O.some(NotificationStatusV26Enum.VIEWED)
8788
: O.none;
8889

89-
/** Legge in modo sicuro lo status più recente (statusCode 200) dai detail */
90-
const getLatestDetailStatus = (
91-
records: ReadonlyArray<GetNotificationDetailRecord>
90+
/** ---------- Detail helpers & type guard ---------- */
91+
type OkDetail = { output: Response<200, FullSentNotificationV27> };
92+
93+
const isOkDetailForIun =
94+
(iun: IUN) =>
95+
(r: GetNotificationDetailRecord): r is GetNotificationDetailRecord & OkDetail =>
96+
r.input.iun === iun && r.output.statusCode === 200;
97+
98+
const latestDetailStatusForIun = (
99+
records: ReadonlyArray<GetNotificationDetailRecord>,
100+
iun: IUN
92101
): O.Option<NotificationStatusV26Enum> =>
93102
pipe(
94103
records,
95-
RA.findLastMap((r) => (r.output.statusCode === 200 ? O.some(r.output.returned) : O.none)),
96-
O.map((ret) => ret.notificationStatus),
104+
RA.findLast(isOkDetailForIun(iun)),
105+
O.map((r) => r.output.returned.notificationStatus),
97106
O.filter((s): s is NotificationStatusV26Enum => s !== undefined)
98107
);
99108

@@ -102,93 +111,92 @@ const getLatestDetailStatus = (
102111
*/
103112
export const makeNotification =
104113
(env: DomainEnv) =>
105-
(findNotificationRequestRecord: ReadonlyArray<CheckNotificationStatusRecord>) =>
106-
(consumeEventStreamRecord: ReadonlyArray<ConsumeEventStreamRecord>) =>
107-
(getNotificationDetailRecord: ReadonlyArray<GetNotificationDetailRecord>) =>
114+
(findRecords: ReadonlyArray<CheckNotificationStatusRecord>) =>
115+
(consumeRecords: ReadonlyArray<ConsumeEventStreamRecord>) =>
116+
(detailRecords: ReadonlyArray<GetNotificationDetailRecord>) =>
108117
(notificationRequest: NotificationRequest): O.Option<Notification> =>
109118
pipe(
110-
// get iun from find records
111-
pipe(findNotificationRequestRecord, RA.findLastMap(getIunFromFind(notificationRequest))),
112-
// get iun from consume records
113-
O.alt(() => pipe(consumeEventStreamRecord, RA.findLastMap(getIunFromConsume(notificationRequest)))),
114-
// create Notification from iun if any
119+
// 1) IUN da find
120+
pipe(findRecords, RA.findLastMap(getIunFromFind(notificationRequest))),
121+
// 2) IUN da consume
122+
O.alt(() => pipe(consumeRecords, RA.findLastMap(getIunFromConsume(notificationRequest)))),
123+
// 3) se ho IUN → notifica
115124
O.map((iun) => mkNotification(env, notificationRequest, iun)),
116-
// try to create notification from find records
117-
// if no iun was found then create a new notification based on occurrences counter
125+
// 4) altrimenti crea notifica su base occurrences
118126
O.alt(() =>
119127
pipe(
120128
M.concatAll(n.MonoidSum)([
121-
pipe(findNotificationRequestRecord, countFromFind(notificationRequest.notificationRequestId)),
122-
pipe(consumeEventStreamRecord, countFromConsume(notificationRequest.notificationRequestId)),
129+
pipe(findRecords, countFromFind(notificationRequest.notificationRequestId)),
130+
pipe(consumeRecords, countFromConsume(notificationRequest.notificationRequestId)),
123131
]),
124-
(occurrences) =>
125-
occurrences >= env.occurrencesToAccepted
132+
(occ) =>
133+
occ >= env.occurrencesToAccepted
126134
? O.some(mkNotification(env, notificationRequest, env.iunGenerator()))
127135
: O.none
128136
)
129137
),
130-
O.map((notification) =>
131-
pipe(
132-
M.concatAll(n.MonoidSum)([
133-
pipe(findNotificationRequestRecord, countFromFind(notificationRequest.notificationRequestId)),
134-
pipe(consumeEventStreamRecord, countFromConsume(notificationRequest.notificationRequestId)),
135-
pipe(getNotificationDetailRecord, countFromDetail(notification.iun)),
136-
]),
137-
(occurrences) => {
138-
// Valuta lo stato (eventuale) proveniente dai "detail"
139-
const maybeDetailStatus = getLatestDetailStatus(getNotificationDetailRecord);
140-
const isCancelled = pipe(
141-
maybeDetailStatus,
142-
O.exists((st) => st === NotificationStatusV26Enum.CANCELLED)
143-
);
144-
145-
if (isCancelled) {
146-
// Aggiorna subito a CANCELLED e arricchisci timeline/history
147-
notification.notificationStatus = NotificationStatusV26Enum.CANCELLED;
148-
notification.cancelledIun = notification.iun;
149-
notification.timeline = [
150-
...notification.timeline,
151-
{
152-
elementId: `NOTIFICATION_CANCELLATION_REQUEST.IUN_${notification.iun}`,
153-
timestamp: env.dateGenerator(),
154-
legalFactsIds: [],
155-
category: TimelineElementCategoryV27Enum.NOTIFICATION_CANCELLATION_REQUEST,
156-
details: { cancellationRequestId: '90e3f130-cb23-4b6b-a0aa-858de7ffb3a0' },
157-
},
158-
{
159-
elementId: `NOTIFICATION_CANCELLED.IUN_${notification.iun}`,
160-
timestamp: env.dateGenerator(),
161-
legalFactsIds: [],
162-
category: TimelineElementCategoryV27Enum.NOTIFICATION_CANCELLED,
163-
details: { notificationCost: 100, notRefinedRecipientIndexes: [0] },
164-
},
165-
];
166-
notification.notificationStatusHistory = [
167-
...notification.notificationStatusHistory,
168-
{
169-
status: NotificationStatusV26Enum.CANCELLED,
170-
activeFrom: env.dateGenerator(),
171-
relatedTimelineElements: [`NOTIFICATION_CANCELLED.IUN_${notification.iun}`],
172-
},
173-
];
174-
}
138+
// 5) aggiorna stato finale — evitando Option<void>
139+
O.map((notification) => {
140+
const occurrences = M.concatAll(n.MonoidSum)([
141+
pipe(findRecords, countFromFind(notificationRequest.notificationRequestId)),
142+
pipe(consumeRecords, countFromConsume(notificationRequest.notificationRequestId)),
143+
pipe(detailRecords, countFromDetail(notification.iun)),
144+
]);
175145

176-
// update the notification according to the number of occurrences
177-
return pipe(
178-
makeStatus(env, occurrences),
179-
O.map((newStatus) =>
180-
updateTimeline(env)(
181-
notification,
182-
isCancelled ? NotificationStatusV26Enum.CANCELLED : newStatus
183-
)
184-
),
185-
O.getOrElse(() =>
186-
isCancelled
187-
? updateTimeline(env)(notification, NotificationStatusV26Enum.CANCELLED)
188-
: notification
189-
)
190-
);
191-
}
192-
)
193-
)
146+
// CANCELLED da detail (per lo stesso IUN) ha priorità
147+
const isCancelled = pipe(
148+
latestDetailStatusForIun(detailRecords, notification.iun),
149+
O.exists((st) => st === NotificationStatusV26Enum.CANCELLED)
150+
);
151+
152+
if (isCancelled) {
153+
notification.notificationStatus = NotificationStatusV26Enum.CANCELLED;
154+
notification.cancelledIun = notification.iun;
155+
notification.timeline = [
156+
...notification.timeline,
157+
{
158+
elementId: `NOTIFICATION_CANCELLATION_REQUEST.IUN_${notification.iun}`,
159+
timestamp: env.dateGenerator(),
160+
legalFactsIds: [],
161+
category: TimelineElementCategoryV27Enum.NOTIFICATION_CANCELLATION_REQUEST,
162+
details: { cancellationRequestId: '90e3f130-cb23-4b6b-a0aa-858de7ffb3a0' },
163+
},
164+
{
165+
elementId: `NOTIFICATION_CANCELLED.IUN_${notification.iun}`,
166+
timestamp: env.dateGenerator(),
167+
legalFactsIds: [],
168+
category: TimelineElementCategoryV27Enum.NOTIFICATION_CANCELLED,
169+
details: { notificationCost: 100, notRefinedRecipientIndexes: [0] },
170+
},
171+
];
172+
notification.notificationStatusHistory = [
173+
...notification.notificationStatusHistory,
174+
{
175+
status: NotificationStatusV26Enum.CANCELLED,
176+
activeFrom: env.dateGenerator(),
177+
relatedTimelineElements: [`NOTIFICATION_CANCELLED.IUN_${notification.iun}`],
178+
},
179+
];
180+
}
181+
182+
const maybeStatus = makeStatus(env, occurrences);
183+
184+
// Applica side-effect e ritorna SEMPRE notification
185+
return pipe(
186+
maybeStatus,
187+
O.match(
188+
() => {
189+
if (isCancelled) {
190+
updateTimeline(env)(notification, NotificationStatusV26Enum.CANCELLED);
191+
}
192+
return notification;
193+
},
194+
(st) => {
195+
const finalSt = isCancelled ? NotificationStatusV26Enum.CANCELLED : st;
196+
updateTimeline(env)(notification, finalSt);
197+
return notification;
198+
}
199+
)
200+
);
201+
})
194202
);

0 commit comments

Comments
 (0)