@piserve-tech/form-submission 1.3.149 → 1.3.151
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.
|
@@ -3,32 +3,49 @@ import * as i0 from "@angular/core";
|
|
|
3
3
|
export class FormValidationService {
|
|
4
4
|
constructor() { }
|
|
5
5
|
validateRequiredQuestions(page) {
|
|
6
|
-
const validateQuestions = (formElements) => {
|
|
6
|
+
const validateQuestions = (formElements, submissionContext = null) => {
|
|
7
7
|
for (let element of formElements) {
|
|
8
8
|
if (element.entityType === 'QUESTION') {
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
const question = element.element;
|
|
10
|
+
const required = question.required;
|
|
11
|
+
const questionId = question.id;
|
|
12
|
+
const elementType = question.formElement?.elementType;
|
|
13
|
+
// If inside a subform submission context
|
|
14
|
+
if (submissionContext?.isInMultipleSubform) {
|
|
15
|
+
const { submission, questionMap } = submissionContext;
|
|
16
|
+
const submittedAnswer = submission.answers.find((ans) => ans.questionId === questionId);
|
|
17
|
+
const answer = submittedAnswer?.answer;
|
|
18
|
+
const isEmpty = answer === null ||
|
|
19
|
+
answer === undefined ||
|
|
20
|
+
(typeof answer === 'string' && answer.trim() === '') ||
|
|
21
|
+
(typeof answer === 'object' && Object.keys(answer).length === 0);
|
|
22
|
+
if (required && isEmpty) {
|
|
13
23
|
return {
|
|
14
24
|
isValid: false,
|
|
15
|
-
message: `Required
|
|
25
|
+
message: `Required question ${question.questionNumber} is not answered in a subform.`,
|
|
16
26
|
};
|
|
17
27
|
}
|
|
18
28
|
}
|
|
19
29
|
else {
|
|
20
|
-
|
|
30
|
+
// Normal non-subform validation
|
|
31
|
+
const answer = question.answer;
|
|
32
|
+
const isEmpty = answer === null ||
|
|
33
|
+
answer === undefined ||
|
|
34
|
+
(typeof answer === 'string' && answer.trim() === '') ||
|
|
35
|
+
(typeof answer === 'object' && Object.keys(answer).length === 0);
|
|
36
|
+
if (required && isEmpty) {
|
|
21
37
|
return {
|
|
22
38
|
isValid: false,
|
|
23
|
-
message: `Required question ${
|
|
39
|
+
message: `Required question ${question.questionNumber} is not answered.`,
|
|
24
40
|
};
|
|
25
41
|
}
|
|
26
42
|
}
|
|
27
|
-
|
|
28
|
-
|
|
43
|
+
// Recursively validate child logics
|
|
44
|
+
if (question.childLogics) {
|
|
45
|
+
for (let logic of question.childLogics) {
|
|
29
46
|
if (logic.showLogic) {
|
|
30
47
|
for (let row of logic.rows) {
|
|
31
|
-
const result = validateQuestions(row.grid);
|
|
48
|
+
const result = validateQuestions(row.grid, submissionContext);
|
|
32
49
|
if (!result.isValid)
|
|
33
50
|
return result;
|
|
34
51
|
}
|
|
@@ -37,8 +54,50 @@ export class FormValidationService {
|
|
|
37
54
|
}
|
|
38
55
|
}
|
|
39
56
|
else if (element.entityType === 'SUBFORM') {
|
|
40
|
-
|
|
41
|
-
|
|
57
|
+
const subform = element.element;
|
|
58
|
+
if (subform.property?.subFormStructure === 'multiple') {
|
|
59
|
+
const submissions = subform.submissions || [];
|
|
60
|
+
// Check if subform has any required questions
|
|
61
|
+
let hasRequiredQuestion = false;
|
|
62
|
+
for (const row of subform.rows) {
|
|
63
|
+
for (const field of row.grid) {
|
|
64
|
+
if (field.entityType === 'QUESTION' && field.element.required) {
|
|
65
|
+
hasRequiredQuestion = true;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (hasRequiredQuestion)
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
if (hasRequiredQuestion && submissions.length === 0) {
|
|
73
|
+
return {
|
|
74
|
+
isValid: false,
|
|
75
|
+
message: `Subform "${subform.title || 'Untitled'}" is missing required submissions.`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const questionMap = new Map();
|
|
79
|
+
for (const row of subform.rows) {
|
|
80
|
+
for (const field of row.grid) {
|
|
81
|
+
if (field.entityType === 'QUESTION') {
|
|
82
|
+
questionMap.set(field.element.id, field.element);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
for (const submission of submissions) {
|
|
87
|
+
for (const row of subform.rows) {
|
|
88
|
+
const result = validateQuestions(row.grid, {
|
|
89
|
+
isInMultipleSubform: true,
|
|
90
|
+
submission,
|
|
91
|
+
questionMap
|
|
92
|
+
});
|
|
93
|
+
if (!result.isValid)
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
// Single-entry subform
|
|
100
|
+
for (const row of subform.rows || []) {
|
|
42
101
|
const result = validateQuestions(row.grid);
|
|
43
102
|
if (!result.isValid)
|
|
44
103
|
return result;
|
|
@@ -48,7 +107,7 @@ export class FormValidationService {
|
|
|
48
107
|
else if ((element.entityType === 'QUESTION_GROUP' || element.entityType === 'MULTIFIELD') &&
|
|
49
108
|
element.element.rows) {
|
|
50
109
|
for (const row of element.element.rows) {
|
|
51
|
-
const result = validateQuestions(row.grid);
|
|
110
|
+
const result = validateQuestions(row.grid, submissionContext);
|
|
52
111
|
if (!result.isValid)
|
|
53
112
|
return result;
|
|
54
113
|
}
|
|
@@ -56,11 +115,11 @@ export class FormValidationService {
|
|
|
56
115
|
}
|
|
57
116
|
return { isValid: true, message: 'All required questions are answered.' };
|
|
58
117
|
};
|
|
59
|
-
|
|
118
|
+
// Start validation from top-level rows
|
|
119
|
+
for (const row of page.rows) {
|
|
60
120
|
const result = validateQuestions(row.grid);
|
|
61
|
-
if (!result.isValid)
|
|
121
|
+
if (!result.isValid)
|
|
62
122
|
return result;
|
|
63
|
-
}
|
|
64
123
|
}
|
|
65
124
|
return { isValid: true, message: 'All required questions are answered.' };
|
|
66
125
|
}
|
|
@@ -73,4 +132,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
73
132
|
providedIn: 'root'
|
|
74
133
|
}]
|
|
75
134
|
}], ctorParameters: function () { return []; } });
|
|
76
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybS12YWxpZGF0aW9uLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9mb3JtLXN1Ym1pc3Npb24vc3JjL3NlcnZpY2VzL2Zvcm0tdmFsaWRhdGlvbi5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7O0FBSzNDLE1BQU0sT0FBTyxxQkFBcUI7SUFFaEMsZ0JBQWUsQ0FBQztJQUVoQix5QkFBeUIsQ0FBQyxJQUFTO1FBQ2pDLE1BQU0saUJBQWlCLEdBQUcsQ0FDeEIsWUFBbUIsRUFDb0IsRUFBRTtZQUN6QyxLQUFLLElBQUksT0FBTyxJQUFJLFlBQVksRUFBRTtnQkFDaEMsSUFBSSxPQUFPLENBQUMsVUFBVSxLQUFLLFVBQVUsRUFBRTtvQkFDckMsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUM7b0JBQzFDLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDO29CQUN0QyxJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLFdBQVcsS0FBSyxhQUFhLEVBQUU7d0JBQzdELElBQUksUUFBUSxJQUFJLENBQUMsQ0FBQyxNQUFNLElBQUksTUFBTSxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUMsRUFBRTs0QkFDaEQsT0FBTztnQ0FDTCxPQUFPLEVBQUUsS0FBSztnQ0FDZCxPQUFPLEVBQUUsMEJBQTBCLE9BQU8sQ0FBQyxPQUFPLENBQUMsY0FBYyxtQkFBbUI7NkJBQ3JGLENBQUM7eUJBQ0g7cUJBQ0Y7eUJBQU07d0JBQ0wsSUFBSSxRQUFRLElBQUksQ0FBQyxDQUFDLE1BQU0sSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUMsRUFBRTs0QkFDN0QsT0FBTztnQ0FDTCxPQUFPLEVBQUUsS0FBSztnQ0FDZCxPQUFPLEVBQUUscUJBQXFCLE9BQU8sQ0FBQyxPQUFPLENBQUMsY0FBYyxtQkFBbUI7NkJBQ2hGLENBQUM7eUJBQ0g7cUJBQ0Y7b0JBQ0QsSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRTt3QkFDL0IsS0FBSyxJQUFJLEtBQUssSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRTs0QkFDN0MsSUFBSSxLQUFLLENBQUMsU0FBUyxFQUFFO2dDQUNuQixLQUFLLElBQUksR0FBRyxJQUFJLEtBQUssQ0FBQyxJQUFJLEVBQUU7b0NBQzFCLE1BQU0sTUFBTSxHQUFHLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztvQ0FDM0MsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPO3dDQUFFLE9BQU8sTUFBTSxDQUFDO2lDQUNwQzs2QkFDRjt5QkFDRjtxQkFDRjtpQkFDRjtxQkFBTSxJQUFJLE9BQU8sQ0FBQyxVQUFVLEtBQUssU0FBUyxFQUFFO29CQUMzQyxJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFO3dCQUN4QixLQUFLLElBQUksR0FBRyxJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFOzRCQUNwQyxNQUFNLE1BQU0sR0FBRyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7NEJBQzNDLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTztnQ0FBRSxPQUFPLE1BQU0sQ0FBQzt5QkFDcEM7cUJBQ0Y7aUJBQ0Y7cUJBQU0sSUFDTCxDQUFDLE9BQU8sQ0FBQyxVQUFVLEtBQUssZ0JBQWdCLElBQUksT0FBTyxDQUFDLFVBQVUsS0FBSyxZQUFZLENBQUM7b0JBQ2hGLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUNwQjtvQkFDQSxLQUFLLE1BQU0sR0FBRyxJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFO3dCQUN0QyxNQUFNLE1BQU0sR0FBRyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7d0JBQzNDLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTzs0QkFBRSxPQUFPLE1BQU0sQ0FBQztxQkFDcEM7aUJBQ0Y7YUFDRjtZQUVELE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxzQ0FBc0MsRUFBRSxDQUFDO1FBQzVFLENBQUMsQ0FBQztRQUVGLEtBQUssSUFBSSxHQUFHLElBQUksSUFBSSxDQUFDLElBQUksRUFBRTtZQUN6QixNQUFNLE1BQU0sR0FBRyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDM0MsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUU7Z0JBQ25CLE9BQU8sTUFBTSxDQUFDO2FBQ2Y7U0FDRjtRQUVELE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxzQ0FBc0MsRUFBRSxDQUFDO0lBQzVFLENBQUM7K0dBbEVVLHFCQUFxQjttSEFBckIscUJBQXFCLGNBRnBCLE1BQU07OzRGQUVQLHFCQUFxQjtrQkFIakMsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIEZvcm1WYWxpZGF0aW9uU2VydmljZSB7XG5cbiAgY29uc3RydWN0b3IoKSB7fVxuXG4gIHZhbGlkYXRlUmVxdWlyZWRRdWVzdGlvbnMocGFnZTogYW55KTogeyBpc1ZhbGlkOiBib29sZWFuOyBtZXNzYWdlOiBzdHJpbmcgfSB7XG4gICAgY29uc3QgdmFsaWRhdGVRdWVzdGlvbnMgPSAoXG4gICAgICBmb3JtRWxlbWVudHM6IGFueVtdXG4gICAgKTogeyBpc1ZhbGlkOiBib29sZWFuOyBtZXNzYWdlOiBzdHJpbmcgfSA9PiB7XG4gICAgICBmb3IgKGxldCBlbGVtZW50IG9mIGZvcm1FbGVtZW50cykge1xuICAgICAgICBpZiAoZWxlbWVudC5lbnRpdHlUeXBlID09PSAnUVVFU1RJT04nKSB7XG4gICAgICAgICAgY29uc3QgcmVxdWlyZWQgPSBlbGVtZW50LmVsZW1lbnQucmVxdWlyZWQ7XG4gICAgICAgICAgY29uc3QgYW5zd2VyID0gZWxlbWVudC5lbGVtZW50LmFuc3dlcjtcbiAgICAgICAgICBpZiAoZWxlbWVudC5lbGVtZW50LmZvcm1FbGVtZW50LmVsZW1lbnRUeXBlID09PSAnRklMRV9QSUNLRVInKSB7XG4gICAgICAgICAgICBpZiAocmVxdWlyZWQgJiYgKCFhbnN3ZXIgfHwgYW5zd2VyLmxlbmd0aCA9PT0gMCkpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBpc1ZhbGlkOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgUmVxdWlyZWQgZmlsZSBxdWVzdGlvbiAke2VsZW1lbnQuZWxlbWVudC5xdWVzdGlvbk51bWJlcn0gaXMgbm90IGFuc3dlcmVkLmAsXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmIChyZXF1aXJlZCAmJiAoIWFuc3dlciB8fCBPYmplY3Qua2V5cyhhbnN3ZXIpLmxlbmd0aCA9PT0gMCkpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBpc1ZhbGlkOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgUmVxdWlyZWQgcXVlc3Rpb24gJHtlbGVtZW50LmVsZW1lbnQucXVlc3Rpb25OdW1iZXJ9IGlzIG5vdCBhbnN3ZXJlZC5gLFxuICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoZWxlbWVudC5lbGVtZW50LmNoaWxkTG9naWNzKSB7XG4gICAgICAgICAgICBmb3IgKGxldCBsb2dpYyBvZiBlbGVtZW50LmVsZW1lbnQuY2hpbGRMb2dpY3MpIHtcbiAgICAgICAgICAgICAgaWYgKGxvZ2ljLnNob3dMb2dpYykge1xuICAgICAgICAgICAgICAgIGZvciAobGV0IHJvdyBvZiBsb2dpYy5yb3dzKSB7XG4gICAgICAgICAgICAgICAgICBjb25zdCByZXN1bHQgPSB2YWxpZGF0ZVF1ZXN0aW9ucyhyb3cuZ3JpZCk7XG4gICAgICAgICAgICAgICAgICBpZiAoIXJlc3VsdC5pc1ZhbGlkKSByZXR1cm4gcmVzdWx0O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChlbGVtZW50LmVudGl0eVR5cGUgPT09ICdTVUJGT1JNJykge1xuICAgICAgICAgIGlmIChlbGVtZW50LmVsZW1lbnQucm93cykge1xuICAgICAgICAgICAgZm9yIChsZXQgcm93IG9mIGVsZW1lbnQuZWxlbWVudC5yb3dzKSB7XG4gICAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IHZhbGlkYXRlUXVlc3Rpb25zKHJvdy5ncmlkKTtcbiAgICAgICAgICAgICAgaWYgKCFyZXN1bHQuaXNWYWxpZCkgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgICAgKGVsZW1lbnQuZW50aXR5VHlwZSA9PT0gJ1FVRVNUSU9OX0dST1VQJyB8fCBlbGVtZW50LmVudGl0eVR5cGUgPT09ICdNVUxUSUZJRUxEJykgJiZcbiAgICAgICAgICBlbGVtZW50LmVsZW1lbnQucm93c1xuICAgICAgICApIHtcbiAgICAgICAgICBmb3IgKGNvbnN0IHJvdyBvZiBlbGVtZW50LmVsZW1lbnQucm93cykge1xuICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gdmFsaWRhdGVRdWVzdGlvbnMocm93LmdyaWQpO1xuICAgICAgICAgICAgaWYgKCFyZXN1bHQuaXNWYWxpZCkgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHsgaXNWYWxpZDogdHJ1ZSwgbWVzc2FnZTogJ0FsbCByZXF1aXJlZCBxdWVzdGlvbnMgYXJlIGFuc3dlcmVkLicgfTtcbiAgICB9O1xuXG4gICAgZm9yIChsZXQgcm93IG9mIHBhZ2Uucm93cykge1xuICAgICAgY29uc3QgcmVzdWx0ID0gdmFsaWRhdGVRdWVzdGlvbnMocm93LmdyaWQpO1xuICAgICAgaWYgKCFyZXN1bHQuaXNWYWxpZCkge1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7IGlzVmFsaWQ6IHRydWUsIG1lc3NhZ2U6ICdBbGwgcmVxdWlyZWQgcXVlc3Rpb25zIGFyZSBhbnN3ZXJlZC4nIH07XG4gIH1cbn1cbiJdfQ==
|
|
135
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybS12YWxpZGF0aW9uLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9mb3JtLXN1Ym1pc3Npb24vc3JjL3NlcnZpY2VzL2Zvcm0tdmFsaWRhdGlvbi5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7O0FBSzNDLE1BQU0sT0FBTyxxQkFBcUI7SUFFaEMsZ0JBQWUsQ0FBQztJQUVoQix5QkFBeUIsQ0FBQyxJQUFTO1FBQ2pDLE1BQU0saUJBQWlCLEdBQUcsQ0FDeEIsWUFBbUIsRUFDbkIsb0JBQXlCLElBQUksRUFDVSxFQUFFO1lBQ3pDLEtBQUssSUFBSSxPQUFPLElBQUksWUFBWSxFQUFFO2dCQUNoQyxJQUFJLE9BQU8sQ0FBQyxVQUFVLEtBQUssVUFBVSxFQUFFO29CQUNyQyxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDO29CQUNqQyxNQUFNLFFBQVEsR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDO29CQUNuQyxNQUFNLFVBQVUsR0FBRyxRQUFRLENBQUMsRUFBRSxDQUFDO29CQUMvQixNQUFNLFdBQVcsR0FBRyxRQUFRLENBQUMsV0FBVyxFQUFFLFdBQVcsQ0FBQztvQkFFdEQseUNBQXlDO29CQUN6QyxJQUFJLGlCQUFpQixFQUFFLG1CQUFtQixFQUFFO3dCQUMxQyxNQUFNLEVBQUUsVUFBVSxFQUFFLFdBQVcsRUFBRSxHQUFHLGlCQUFpQixDQUFDO3dCQUV0RCxNQUFNLGVBQWUsR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLElBQUksQ0FDN0MsQ0FBQyxHQUFRLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLEtBQUssVUFBVSxDQUM1QyxDQUFDO3dCQUVGLE1BQU0sTUFBTSxHQUFHLGVBQWUsRUFBRSxNQUFNLENBQUM7d0JBRXZDLE1BQU0sT0FBTyxHQUNYLE1BQU0sS0FBSyxJQUFJOzRC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LGlCQUFpQixDQUFDLENBQUM7d0JBQzlELElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTzs0QkFBRSxPQUFPLE1BQU0sQ0FBQztxQkFDcEM7aUJBQ0Y7YUFDRjtZQUVELE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxzQ0FBc0MsRUFBRSxDQUFDO1FBQzVFLENBQUMsQ0FBQztRQUVGLHVDQUF1QztRQUN2QyxLQUFLLE1BQU0sR0FBRyxJQUFJLElBQUksQ0FBQyxJQUFJLEVBQUU7WUFDM0IsTUFBTSxNQUFNLEdBQUcsaUJBQWlCLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzNDLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTztnQkFBRSxPQUFPLE1BQU0sQ0FBQztTQUNwQztRQUVELE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxzQ0FBc0MsRUFBRSxDQUFDO0lBQzVFLENBQUM7K0dBN0lVLHFCQUFxQjttSEFBckIscUJBQXFCLGNBRnBCLE1BQU07OzRGQUVQLHFCQUFxQjtrQkFIakMsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIEZvcm1WYWxpZGF0aW9uU2VydmljZSB7XG5cbiAgY29uc3RydWN0b3IoKSB7fVxuXG4gIHZhbGlkYXRlUmVxdWlyZWRRdWVzdGlvbnMocGFnZTogYW55KTogeyBpc1ZhbGlkOiBib29sZWFuOyBtZXNzYWdlOiBzdHJpbmcgfSB7XG4gICAgY29uc3QgdmFsaWRhdGVRdWVzdGlvbnMgPSAoXG4gICAgICBmb3JtRWxlbWVudHM6IGFueVtdLFxuICAgICAgc3VibWlzc2lvbkNvbnRleHQ6IGFueSA9IG51bGxcbiAgICApOiB7IGlzVmFsaWQ6IGJvb2xlYW47IG1lc3NhZ2U6IHN0cmluZyB9ID0+IHtcbiAgICAgIGZvciAobGV0IGVsZW1lbnQgb2YgZm9ybUVsZW1lbnRzKSB7XG4gICAgICAgIGlmIChlbGVtZW50LmVudGl0eVR5cGUgPT09ICdRVUVTVElPTicpIHtcbiAgICAgICAgICBjb25zdCBxdWVzdGlvbiA9IGVsZW1lbnQuZWxlbWVudDtcbiAgICAgICAgICBjb25zdCByZXF1aXJlZCA9IHF1ZXN0aW9uLnJlcXVpcmVkO1xuICAgICAgICAgIGNvbnN0IHF1ZXN0aW9uSWQgPSBxdWVzdGlvbi5pZDtcbiAgICAgICAgICBjb25zdCBlbGVtZW50VHlwZSA9IHF1ZXN0aW9uLmZvcm1FbGVtZW50Py5lbGVtZW50VHlwZTtcbiAgXG4gICAgICAgICAgLy8gSWYgaW5zaWRlIGEgc3ViZm9ybSBzdWJtaXNzaW9uIGNvbnRleHRcbiAgICAgICAgICBpZiAoc3VibWlzc2lvbkNvbnRleHQ/LmlzSW5NdWx0aXBsZVN1YmZvcm0pIHtcbiAgICAgICAgICAgIGNvbnN0IHsgc3VibWlzc2lvbiwgcXVlc3Rpb25NYXAgfSA9IHN1Ym1pc3Npb25Db250ZXh0O1xuICBcbiAgICAgICAgICAgIGNvbnN0IHN1Ym1pdHRlZEFuc3dlciA9IHN1Ym1pc3Npb24uYW5zd2Vycy5maW5kKFxuICAgICAgICAgICAgICAoYW5zOiBhbnkpID0+IGFucy5xdWVzdGlvbklkID09PSBxdWVzdGlvbklkXG4gICAgICAgICAgICApO1xuICBcbiAgICAgICAgICAgIGNvbnN0IGFuc3dlciA9IHN1Ym1pdHRlZEFuc3dlcj8uYW5zd2VyO1xuICBcbiAgICAgICAgICAgIGNvbnN0IGlzRW1wdHkgPVxuICAgICAgICAgICAgICBhbnN3ZXIgPT09IG51bGwgfHxcbiAgICAgICAgICAgICAgYW5zd2VyID09PSB1bmRlZmluZWQgfHxcbiAgICAgICAgICAgICAgKHR5cGVvZiBhbnN3ZXIgPT09ICdzdHJpbmcnICYmIGFuc3dlci50cmltKCkgPT09ICcnKSB8fFxuICAgICAgICAgICAgICAodHlwZW9mIGFuc3dlciA9PT0gJ29iamVjdCcgJiYgT2JqZWN0LmtleXMoYW5zd2VyKS5sZW5ndGggPT09IDApO1xuICBcbiAgICAgICAgICAgIGlmIChyZXF1aXJlZCAmJiBpc0VtcHR5KSB7XG4gICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgaXNWYWxpZDogZmFsc2UsXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogYFJlcXVpcmVkIHF1ZXN0aW9uICR7cXVlc3Rpb24ucXVlc3Rpb25OdW1iZXJ9IGlzIG5vdCBhbnN3ZXJlZCBpbiBhIHN1YmZvcm0uYCxcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gTm9ybWFsIG5vbi1zdWJmb3JtIHZhbGlkYXRpb25cbiAgICAgICAgICAgIGNvbnN0IGFuc3dlciA9IHF1ZXN0aW9uLmFuc3dlcjtcbiAgICAgICAgICAgIGNvbnN0IGlzRW1wdHkgPVxuICAgICAgICAgICAgICBhbnN3ZXIgPT09IG51bGwgfHxcbiAgICAgICAgICAgICAgYW5zd2VyID09PSB1bmRlZmluZWQgfHxcbiAgICAgICAgICAgICAgKHR5cGVvZiBhbnN3ZXIgPT09ICdzdHJpbmcnICYmIGFuc3dlci50cmltKCkgPT09ICcnKSB8fFxuICAgICAgICAgICAgICAodHlwZW9mIGFuc3dlciA9PT0gJ29iamVjdCcgJiYgT2JqZWN0LmtleXMoYW5zd2VyKS5sZW5ndGggPT09IDApO1xuICBcbiAgICAgICAgICAgIGlmIChyZXF1aXJlZCAmJiBpc0VtcHR5KSB7XG4gICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgaXNWYWxpZDogZmFsc2UsXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogYFJlcXVpcmVkIHF1ZXN0aW9uICR7cXVlc3Rpb24ucXVlc3Rpb25OdW1iZXJ9IGlzIG5vdCBhbnN3ZXJlZC5gLFxuICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgXG4gICAgICAgICAgLy8gUmVjdXJzaXZlbHkgdmFsaWRhdGUgY2hpbGQgbG9naWNzXG4gICAgICAgICAgaWYgKHF1ZXN0aW9uLmNoaWxkTG9naWNzKSB7XG4gICAgICAgICAgICBmb3IgKGxldCBsb2dpYyBvZiBxdWVzdGlvbi5jaGlsZExvZ2ljcykge1xuICAgICAgICAgICAgICBpZiAobG9naWMuc2hvd0xvZ2ljKSB7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgcm93IG9mIGxvZ2ljLnJvd3MpIHtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IHZhbGlkYXRlUXVlc3Rpb25zKHJvdy5ncmlkLCBzdWJtaXNzaW9uQ29udGV4dCk7XG4gICAgICAgICAgICAgICAgICBpZiAoIXJlc3VsdC5pc1ZhbGlkKSByZXR1cm4gcmVzdWx0O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChlbGVtZW50LmVudGl0eVR5cGUgPT09ICdTVUJGT1JNJykge1xuICAgICAgICAgIGNvbnN0IHN1YmZvcm0gPSBlbGVtZW50LmVsZW1lbnQ7XG4gIFxuICAgICAgICAgIGlmIChzdWJmb3JtLnByb3BlcnR5Py5zdWJGb3JtU3RydWN0dXJlID09PSAnbXVsdGlwbGUnKSB7XG4gICAgICAgICAgICBjb25zdCBzdWJtaXNzaW9ucyA9IHN1YmZvcm0uc3VibWlzc2lvbnMgfHwgW107XG4gICAgICAgICAgXG4gICAgICAgICAgICAvLyBDaGVjayBpZiBzdWJmb3JtIGhhcyBhbnkgcmVxdWlyZWQgcXVlc3Rpb25zXG4gICAgICAgICAgICBsZXQgaGFzUmVxdWlyZWRRdWVzdGlvbiA9IGZhbHNlO1xuICAgICAgICAgICAgZm9yIChjb25zdCByb3cgb2Ygc3ViZm9ybS5yb3dzKSB7XG4gICAgICAgICAgICAgIGZvciAoY29uc3QgZmllbGQgb2Ygcm93LmdyaWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoZmllbGQuZW50aXR5VHlwZSA9PT0gJ1FVRVNUSU9OJyAmJiBmaWVsZC5lbGVtZW50LnJlcXVpcmVkKSB7XG4gICAgICAgICAgICAgICAgICBoYXNSZXF1aXJlZFF1ZXN0aW9uID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBpZiAoaGFzUmVxdWlyZWRRdWVzdGlvbikgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgXG4gICAgICAgICAgICBpZiAoaGFzUmVxdWlyZWRRdWVzdGlvbiAmJiBzdWJtaXNzaW9ucy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBpc1ZhbGlkOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgU3ViZm9ybSBcIiR7c3ViZm9ybS50aXRsZSB8fCAnVW50aXRsZWQnfVwiIGlzIG1pc3NpbmcgcmVxdWlyZWQgc3VibWlzc2lvbnMuYCxcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICBcbiAgICAgICAgICAgIGNvbnN0IHF1ZXN0aW9uTWFwID0gbmV3IE1hcCgpO1xuICAgICAgICAgICAgZm9yIChjb25zdCByb3cgb2Ygc3ViZm9ybS5yb3dzKSB7XG4gICAgICAgICAgICAgIGZvciAoY29uc3QgZmllbGQgb2Ygcm93LmdyaWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoZmllbGQuZW50aXR5VHlwZSA9PT0gJ1FVRVNUSU9OJykge1xuICAgICAgICAgICAgICAgICAgcXVlc3Rpb25NYXAuc2V0KGZpZWxkLmVsZW1lbnQuaWQsIGZpZWxkLmVsZW1lbnQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIFxuICAgICAgICAgICAgZm9yIChjb25zdCBzdWJtaXNzaW9uIG9mIHN1Ym1pc3Npb25zKSB7XG4gICAgICAgICAgICAgIGZvciAoY29uc3Qgcm93IG9mIHN1YmZvcm0ucm93cykge1xuICAgICAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IHZhbGlkYXRlUXVlc3Rpb25zKHJvdy5ncmlkLCB7XG4gICAgICAgICAgICAgICAgICBpc0luTXVsdGlwbGVTdWJmb3JtOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgc3VibWlzc2lvbixcbiAgICAgICAgICAgICAgICAgIHF1ZXN0aW9uTWFwXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXN1bHQuaXNWYWxpZCkgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICAgXG4gICAgICAgICAgXG4gICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyBTaW5nbGUtZW50cnkgc3ViZm9ybVxuICAgICAgICAgICAgZm9yIChjb25zdCByb3cgb2Ygc3ViZm9ybS5yb3dzIHx8IFtdKSB7XG4gICAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IHZhbGlkYXRlUXVlc3Rpb25zKHJvdy5ncmlkKTtcbiAgICAgICAgICAgICAgaWYgKCFyZXN1bHQuaXNWYWxpZCkgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgICAgKGVsZW1lbnQuZW50aXR5VHlwZSA9PT0gJ1FVRVNUSU9OX0dST1VQJyB8fCBlbGVtZW50LmVudGl0eVR5cGUgPT09ICdNVUxUSUZJRUxEJykgJiZcbiAgICAgICAgICBlbGVtZW50LmVsZW1lbnQucm93c1xuICAgICAgICApIHtcbiAgICAgICAgICBmb3IgKGNvbnN0IHJvdyBvZiBlbGVtZW50LmVsZW1lbnQucm93cykge1xuICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gdmFsaWRhdGVRdWVzdGlvbnMocm93LmdyaWQsIHN1Ym1pc3Npb25Db250ZXh0KTtcbiAgICAgICAgICAgIGlmICghcmVzdWx0LmlzVmFsaWQpIHJldHVybiByZXN1bHQ7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gIFxuICAgICAgcmV0dXJuIHsgaXNWYWxpZDogdHJ1ZSwgbWVzc2FnZTogJ0FsbCByZXF1aXJlZCBxdWVzdGlvbnMgYXJlIGFuc3dlcmVkLicgfTtcbiAgICB9O1xuICBcbiAgICAvLyBTdGFydCB2YWxpZGF0aW9uIGZyb20gdG9wLWxldmVsIHJvd3NcbiAgICBmb3IgKGNvbnN0IHJvdyBvZiBwYWdlLnJvd3MpIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IHZhbGlkYXRlUXVlc3Rpb25zKHJvdy5ncmlkKTtcbiAgICAgIGlmICghcmVzdWx0LmlzVmFsaWQpIHJldHVybiByZXN1bHQ7XG4gICAgfVxuICBcbiAgICByZXR1cm4geyBpc1ZhbGlkOiB0cnVlLCBtZXNzYWdlOiAnQWxsIHJlcXVpcmVkIHF1ZXN0aW9ucyBhcmUgYW5zd2VyZWQuJyB9O1xuICB9XG4gIFxuICBcbn1cbiJdfQ==
|
|
@@ -430,32 +430,49 @@ function mapOptionToModel(apiOption) {
|
|
|
430
430
|
class FormValidationService {
|
|
431
431
|
constructor() { }
|
|
432
432
|
validateRequiredQuestions(page) {
|
|
433
|
-
const validateQuestions = (formElements) => {
|
|
433
|
+
const validateQuestions = (formElements, submissionContext = null) => {
|
|
434
434
|
for (let element of formElements) {
|
|
435
435
|
if (element.entityType === 'QUESTION') {
|
|
436
|
-
const
|
|
437
|
-
const
|
|
438
|
-
|
|
439
|
-
|
|
436
|
+
const question = element.element;
|
|
437
|
+
const required = question.required;
|
|
438
|
+
const questionId = question.id;
|
|
439
|
+
const elementType = question.formElement?.elementType;
|
|
440
|
+
// If inside a subform submission context
|
|
441
|
+
if (submissionContext?.isInMultipleSubform) {
|
|
442
|
+
const { submission, questionMap } = submissionContext;
|
|
443
|
+
const submittedAnswer = submission.answers.find((ans) => ans.questionId === questionId);
|
|
444
|
+
const answer = submittedAnswer?.answer;
|
|
445
|
+
const isEmpty = answer === null ||
|
|
446
|
+
answer === undefined ||
|
|
447
|
+
(typeof answer === 'string' && answer.trim() === '') ||
|
|
448
|
+
(typeof answer === 'object' && Object.keys(answer).length === 0);
|
|
449
|
+
if (required && isEmpty) {
|
|
440
450
|
return {
|
|
441
451
|
isValid: false,
|
|
442
|
-
message: `Required
|
|
452
|
+
message: `Required question ${question.questionNumber} is not answered in a subform.`,
|
|
443
453
|
};
|
|
444
454
|
}
|
|
445
455
|
}
|
|
446
456
|
else {
|
|
447
|
-
|
|
457
|
+
// Normal non-subform validation
|
|
458
|
+
const answer = question.answer;
|
|
459
|
+
const isEmpty = answer === null ||
|
|
460
|
+
answer === undefined ||
|
|
461
|
+
(typeof answer === 'string' && answer.trim() === '') ||
|
|
462
|
+
(typeof answer === 'object' && Object.keys(answer).length === 0);
|
|
463
|
+
if (required && isEmpty) {
|
|
448
464
|
return {
|
|
449
465
|
isValid: false,
|
|
450
|
-
message: `Required question ${
|
|
466
|
+
message: `Required question ${question.questionNumber} is not answered.`,
|
|
451
467
|
};
|
|
452
468
|
}
|
|
453
469
|
}
|
|
454
|
-
|
|
455
|
-
|
|
470
|
+
// Recursively validate child logics
|
|
471
|
+
if (question.childLogics) {
|
|
472
|
+
for (let logic of question.childLogics) {
|
|
456
473
|
if (logic.showLogic) {
|
|
457
474
|
for (let row of logic.rows) {
|
|
458
|
-
const result = validateQuestions(row.grid);
|
|
475
|
+
const result = validateQuestions(row.grid, submissionContext);
|
|
459
476
|
if (!result.isValid)
|
|
460
477
|
return result;
|
|
461
478
|
}
|
|
@@ -464,8 +481,50 @@ class FormValidationService {
|
|
|
464
481
|
}
|
|
465
482
|
}
|
|
466
483
|
else if (element.entityType === 'SUBFORM') {
|
|
467
|
-
|
|
468
|
-
|
|
484
|
+
const subform = element.element;
|
|
485
|
+
if (subform.property?.subFormStructure === 'multiple') {
|
|
486
|
+
const submissions = subform.submissions || [];
|
|
487
|
+
// Check if subform has any required questions
|
|
488
|
+
let hasRequiredQuestion = false;
|
|
489
|
+
for (const row of subform.rows) {
|
|
490
|
+
for (const field of row.grid) {
|
|
491
|
+
if (field.entityType === 'QUESTION' && field.element.required) {
|
|
492
|
+
hasRequiredQuestion = true;
|
|
493
|
+
break;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
if (hasRequiredQuestion)
|
|
497
|
+
break;
|
|
498
|
+
}
|
|
499
|
+
if (hasRequiredQuestion && submissions.length === 0) {
|
|
500
|
+
return {
|
|
501
|
+
isValid: false,
|
|
502
|
+
message: `Subform "${subform.title || 'Untitled'}" is missing required submissions.`,
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
const questionMap = new Map();
|
|
506
|
+
for (const row of subform.rows) {
|
|
507
|
+
for (const field of row.grid) {
|
|
508
|
+
if (field.entityType === 'QUESTION') {
|
|
509
|
+
questionMap.set(field.element.id, field.element);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
for (const submission of submissions) {
|
|
514
|
+
for (const row of subform.rows) {
|
|
515
|
+
const result = validateQuestions(row.grid, {
|
|
516
|
+
isInMultipleSubform: true,
|
|
517
|
+
submission,
|
|
518
|
+
questionMap
|
|
519
|
+
});
|
|
520
|
+
if (!result.isValid)
|
|
521
|
+
return result;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
else {
|
|
526
|
+
// Single-entry subform
|
|
527
|
+
for (const row of subform.rows || []) {
|
|
469
528
|
const result = validateQuestions(row.grid);
|
|
470
529
|
if (!result.isValid)
|
|
471
530
|
return result;
|
|
@@ -475,7 +534,7 @@ class FormValidationService {
|
|
|
475
534
|
else if ((element.entityType === 'QUESTION_GROUP' || element.entityType === 'MULTIFIELD') &&
|
|
476
535
|
element.element.rows) {
|
|
477
536
|
for (const row of element.element.rows) {
|
|
478
|
-
const result = validateQuestions(row.grid);
|
|
537
|
+
const result = validateQuestions(row.grid, submissionContext);
|
|
479
538
|
if (!result.isValid)
|
|
480
539
|
return result;
|
|
481
540
|
}
|
|
@@ -483,11 +542,11 @@ class FormValidationService {
|
|
|
483
542
|
}
|
|
484
543
|
return { isValid: true, message: 'All required questions are answered.' };
|
|
485
544
|
};
|
|
486
|
-
|
|
545
|
+
// Start validation from top-level rows
|
|
546
|
+
for (const row of page.rows) {
|
|
487
547
|
const result = validateQuestions(row.grid);
|
|
488
|
-
if (!result.isValid)
|
|
548
|
+
if (!result.isValid)
|
|
489
549
|
return result;
|
|
490
|
-
}
|
|
491
550
|
}
|
|
492
551
|
return { isValid: true, message: 'All required questions are answered.' };
|
|
493
552
|
}
|