Add independent subject pass rules and atomic score imports
This commit is contained in:
+46
-14
@@ -57,7 +57,7 @@ function buildSeedOperations(state) {
|
||||
const nullable = value => value == null || value === '' ? null : value;
|
||||
|
||||
add(
|
||||
'UPDATE schema_metadata SET schema_version = 10, app_version = ?, self_registration_enabled = ?, created_at = ? WHERE id = 1',
|
||||
'UPDATE schema_metadata SET schema_version = 12, app_version = ?, self_registration_enabled = ?, created_at = ? WHERE id = 1',
|
||||
Number(state.meta?.version || 1), state.settings?.selfRegistrationEnabled ? 1 : 0,
|
||||
state.meta?.createdAt || new Date().toISOString()
|
||||
);
|
||||
@@ -129,15 +129,16 @@ function buildSeedOperations(state) {
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
exam.id, exam.code, exam.name, exam.description || '', exam.registrationStart, exam.registrationEnd,
|
||||
exam.examStart, exam.examEnd, exam.admitDownloadStart, exam.admitDownloadEnd, exam.location || '',
|
||||
exam.passPolicy || 'score_ratio', Number(exam.passValue ?? 60), exam.status, exam.createdAt
|
||||
exam.passPolicy === 'score_ratio' ? 'rank_percent' : (exam.passPolicy || 'rank_percent'), Number(exam.passValue ?? 60), exam.status, exam.createdAt
|
||||
);
|
||||
exam.subjects.forEach((subject, index) => add(
|
||||
`INSERT INTO exam_subjects (
|
||||
id, exam_id, name, subject_date, start_time, end_time, fee, full_score, pass_score, position
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
id, exam_id, name, subject_date, start_time, end_time, fee, full_score, pass_score, pass_rule, pass_value, position
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
subject.id, exam.id, subject.name, subject.date || String(exam.examStart).slice(0, 10),
|
||||
subject.start || '', subject.end || '', Number(subject.fee || 0), Number(subject.fullScore || 150),
|
||||
Number(subject.passScore ?? Number(subject.fullScore || 150) * .6), Number(subject.order || index + 1)
|
||||
Number(subject.passScore ?? 0), subject.passRule === 'rank_percent' ? 'score_ratio' : (subject.passRule || 'fixed_score'),
|
||||
Number(subject.passValue ?? subject.passScore ?? Number(subject.fullScore || 150) * .6), Number(subject.order || index + 1)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -342,6 +343,9 @@ function buildSeedOperations(state) {
|
||||
function stateFromRows(rows) {
|
||||
const subjectsByExam = new Map();
|
||||
for (const row of rows.subjects) {
|
||||
const fullScore = Number(row.full_score ?? 150);
|
||||
const passRule = row.pass_rule === 'score_ratio' ? 'rank_percent' : (row.pass_rule || 'fixed_score');
|
||||
const passValue = Number(row.pass_value ?? row.pass_score ?? fullScore * .6);
|
||||
const subject = {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
@@ -349,8 +353,10 @@ function stateFromRows(rows) {
|
||||
start: row.start_time,
|
||||
end: row.end_time,
|
||||
fee: Number(row.fee),
|
||||
fullScore: Number(row.full_score ?? 150),
|
||||
passScore: Number(row.pass_score ?? 90),
|
||||
fullScore,
|
||||
passRule,
|
||||
passValue,
|
||||
passScore: passRule === 'fixed_score' ? Number(passValue.toFixed(2)) : null,
|
||||
order: Number(row.position)
|
||||
};
|
||||
const subjects = subjectsByExam.get(row.exam_id) || [];
|
||||
@@ -521,7 +527,7 @@ function stateFromRows(rows) {
|
||||
admitDownloadStart: row.admit_download_start,
|
||||
admitDownloadEnd: row.admit_download_end,
|
||||
location: row.location,
|
||||
passPolicy: row.pass_policy || 'score_ratio',
|
||||
passPolicy: row.pass_policy === 'score_ratio' ? 'rank_percent' : (row.pass_policy || 'rank_percent'),
|
||||
passValue: Number(row.pass_value ?? 60),
|
||||
status: row.status,
|
||||
createdAt: row.created_at,
|
||||
@@ -1008,6 +1014,12 @@ function createRepository({ client, location, read, transaction, close }) {
|
||||
status = ?, review_note = ?, reviewed_at = ? WHERE id = ?`,
|
||||
business.status, optional(business.reviewNote), optional(business.reviewedAt), business.id
|
||||
));
|
||||
} else if (instance.businessType === 'score_appeal' && business) {
|
||||
operations.push(operation(
|
||||
`UPDATE results SET score = ?, grade = ?, published = ?, updated_at = ?, published_at = ? WHERE id = ?`,
|
||||
Number(business.score), business.grade, business.published ? 1 : 0,
|
||||
optional(business.updatedAt), optional(business.publishedAt), business.id
|
||||
));
|
||||
}
|
||||
if (log) operations.push(auditOperation(log));
|
||||
await transaction(operations);
|
||||
@@ -1298,11 +1310,11 @@ function createRepository({ client, location, read, transaction, close }) {
|
||||
)];
|
||||
exam.subjects.forEach((subject, index) => operations.push(operation(
|
||||
`INSERT INTO exam_subjects (
|
||||
id, exam_id, name, subject_date, start_time, end_time, fee, full_score, pass_score, position
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
id, exam_id, name, subject_date, start_time, end_time, fee, full_score, pass_score, pass_rule, pass_value, position
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
subject.id, exam.id, subject.name, subject.date || String(exam.examStart).slice(0, 10),
|
||||
subject.start || '', subject.end || '', Number(subject.fee || 0), Number(subject.fullScore),
|
||||
Number(subject.passScore), Number(subject.order || index + 1)
|
||||
Number(subject.passScore ?? 0), subject.passRule === 'rank_percent' ? 'score_ratio' : (subject.passRule || 'fixed_score'), Number(subject.passValue ?? subject.passScore ?? 0), Number(subject.order || index + 1)
|
||||
)));
|
||||
operations.push(auditOperation(log));
|
||||
await transaction(operations);
|
||||
@@ -1323,11 +1335,11 @@ function createRepository({ client, location, read, transaction, close }) {
|
||||
operations.push(operation('DELETE FROM exam_subjects WHERE exam_id = ?', exam.id));
|
||||
exam.subjects.forEach((subject, index) => operations.push(operation(
|
||||
`INSERT INTO exam_subjects (
|
||||
id, exam_id, name, subject_date, start_time, end_time, fee, full_score, pass_score, position
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
id, exam_id, name, subject_date, start_time, end_time, fee, full_score, pass_score, pass_rule, pass_value, position
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
subject.id, exam.id, subject.name, subject.date || String(exam.examStart).slice(0, 10),
|
||||
subject.start || '', subject.end || '', Number(subject.fee || 0), Number(subject.fullScore),
|
||||
Number(subject.passScore), Number(subject.order || index + 1)
|
||||
Number(subject.passScore ?? 0), subject.passRule === 'rank_percent' ? 'score_ratio' : (subject.passRule || 'fixed_score'), Number(subject.passValue ?? subject.passScore ?? 0), Number(subject.order || index + 1)
|
||||
)));
|
||||
}
|
||||
operations.push(auditOperation(log));
|
||||
@@ -1370,6 +1382,26 @@ function createRepository({ client, location, read, transaction, close }) {
|
||||
optional(result.updatedAt), optional(result.publishedAt), result.id
|
||||
);
|
||||
await transaction([resultOperation, auditOperation(log)]);
|
||||
},
|
||||
async saveResults(entries) {
|
||||
const operations = [];
|
||||
for (const { result, isNew, log } of entries) {
|
||||
operations.push(isNew
|
||||
? operation(
|
||||
`INSERT INTO results (
|
||||
id, registration_id, subject_id, score, grade, published, updated_at, published_at
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
result.id, result.registrationId, result.subjectId, result.score, result.grade,
|
||||
result.published ? 1 : 0, optional(result.updatedAt), optional(result.publishedAt)
|
||||
)
|
||||
: operation(
|
||||
`UPDATE results SET score = ?, grade = ?, published = ?, updated_at = ?, published_at = ? WHERE id = ?`,
|
||||
result.score, result.grade, result.published ? 1 : 0,
|
||||
optional(result.updatedAt), optional(result.publishedAt), result.id
|
||||
));
|
||||
operations.push(auditOperation(log));
|
||||
}
|
||||
await transaction(operations);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user