feat: enhance contract upload process to handle missing templates gracefully and return skipped uploads
This commit is contained in:
parent
4aead9bedc
commit
41b444a190
@ -1459,7 +1459,9 @@ exports.previewLatestForMe = async (req, res) => {
|
|||||||
// Find the latest active template for this user type
|
// Find the latest active template for this user type
|
||||||
const latest = await DocumentTemplateService.getLatestActiveForUserType(userType, 'contract', contractType);
|
const latest = await DocumentTemplateService.getLatestActiveForUserType(userType, 'contract', contractType);
|
||||||
if (!latest) {
|
if (!latest) {
|
||||||
return res.status(404).json({ error: 'No active template found for your user type' });
|
logger.info('[previewLatestForMe] no active template', { userId: targetUserId, userType, contractType });
|
||||||
|
// Return 200 with empty body so clients can show a friendly empty state.
|
||||||
|
return res.status(200).send('');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch template HTML from storage
|
// Fetch template HTML from storage
|
||||||
|
|||||||
@ -50,30 +50,39 @@ class ContractUploadController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const uploads = [];
|
const uploads = [];
|
||||||
// Primary contract
|
const skipped = [];
|
||||||
uploads.push(await ContractUploadService.uploadContract({
|
const tryUpload = async ({ contract_type, fileOverride }) => {
|
||||||
userId,
|
try {
|
||||||
file,
|
const result = await ContractUploadService.uploadContract({
|
||||||
documentType: 'contract',
|
userId,
|
||||||
contractCategory: 'personal',
|
file: fileOverride,
|
||||||
unitOfWork,
|
documentType: 'contract',
|
||||||
contractData,
|
contractCategory: 'personal',
|
||||||
signatureImage: signatureMeta ? signatureMeta.base64 : null,
|
unitOfWork,
|
||||||
contract_type: 'contract',
|
contractData,
|
||||||
user_type: 'personal'
|
signatureImage: signatureMeta ? signatureMeta.base64 : null,
|
||||||
}));
|
contract_type,
|
||||||
|
user_type: 'personal'
|
||||||
|
});
|
||||||
|
uploads.push({ contract_type, ...result });
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
const msg = (e && e.message) ? String(e.message) : '';
|
||||||
|
if (msg.includes('No active') && msg.includes('template found')) {
|
||||||
|
skipped.push({ contract_type, reason: 'no_active_template' });
|
||||||
|
logger.info('[ContractUploadController] template missing, skipping', { userId, contract_type });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// GDPR contract (auto-generated from latest GDPR template)
|
const didUploadContract = await tryUpload({ contract_type: 'contract', fileOverride: file });
|
||||||
uploads.push(await ContractUploadService.uploadContract({
|
const didUploadGdpr = await tryUpload({ contract_type: 'gdpr', fileOverride: undefined });
|
||||||
userId,
|
|
||||||
documentType: 'contract',
|
if (!didUploadContract && !didUploadGdpr) {
|
||||||
contractCategory: 'personal',
|
throw new Error('No active documents are available at this moment.');
|
||||||
unitOfWork,
|
}
|
||||||
contractData,
|
|
||||||
signatureImage: signatureMeta ? signatureMeta.base64 : null,
|
|
||||||
contract_type: 'gdpr',
|
|
||||||
user_type: 'personal'
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Cleanup standalone signature record after contracts are saved
|
// Cleanup standalone signature record after contracts are saved
|
||||||
if (signatureMeta) {
|
if (signatureMeta) {
|
||||||
@ -83,7 +92,7 @@ class ContractUploadController {
|
|||||||
|
|
||||||
await unitOfWork.commit();
|
await unitOfWork.commit();
|
||||||
logger.info(`[ContractUploadController] uploadPersonalContract success for userId: ${userId}`);
|
logger.info(`[ContractUploadController] uploadPersonalContract success for userId: ${userId}`);
|
||||||
res.json({ success: true, uploads, downloadUrls: uploads.map(u => u.url || null) });
|
res.json({ success: true, uploads, skipped, downloadUrls: uploads.map(u => u.url || null) });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`[ContractUploadController] uploadPersonalContract error for userId: ${userId}`, { error });
|
logger.error(`[ContractUploadController] uploadPersonalContract error for userId: ${userId}`, { error });
|
||||||
await unitOfWork.rollback(error);
|
await unitOfWork.rollback(error);
|
||||||
@ -116,24 +125,48 @@ class ContractUploadController {
|
|||||||
logger.info('[ContractUploadController] signature stored for company user', { userId, bytes: signatureMeta.size });
|
logger.info('[ContractUploadController] signature stored for company user', { userId, bytes: signatureMeta.size });
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await ContractUploadService.uploadContract({
|
const uploads = [];
|
||||||
userId,
|
const skipped = [];
|
||||||
file,
|
const tryUpload = async ({ contract_type, fileOverride }) => {
|
||||||
documentType: 'contract',
|
try {
|
||||||
contractCategory: 'company',
|
const result = await ContractUploadService.uploadContract({
|
||||||
unitOfWork,
|
userId,
|
||||||
contractData,
|
file: fileOverride,
|
||||||
signatureImage: signatureMeta ? signatureMeta.base64 : null,
|
documentType: 'contract',
|
||||||
contract_type: 'contract',
|
contractCategory: 'company',
|
||||||
user_type: 'company'
|
unitOfWork,
|
||||||
});
|
contractData,
|
||||||
|
signatureImage: signatureMeta ? signatureMeta.base64 : null,
|
||||||
|
contract_type,
|
||||||
|
user_type: 'company'
|
||||||
|
});
|
||||||
|
uploads.push({ contract_type, ...result });
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
const msg = (e && e.message) ? String(e.message) : '';
|
||||||
|
if (msg.includes('No active') && msg.includes('template found')) {
|
||||||
|
skipped.push({ contract_type, reason: 'no_active_template' });
|
||||||
|
logger.info('[ContractUploadController] template missing, skipping', { userId, contract_type });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const didUploadContract = await tryUpload({ contract_type: 'contract', fileOverride: file });
|
||||||
|
const didUploadGdpr = await tryUpload({ contract_type: 'gdpr', fileOverride: undefined });
|
||||||
|
|
||||||
|
if (!didUploadContract && !didUploadGdpr) {
|
||||||
|
throw new Error('No active documents are available at this moment.');
|
||||||
|
}
|
||||||
|
|
||||||
await unitOfWork.commit();
|
await unitOfWork.commit();
|
||||||
if (signatureMeta) {
|
if (signatureMeta) {
|
||||||
await repo.deleteSignatureDocumentsForUser(userId);
|
await repo.deleteSignatureDocumentsForUser(userId);
|
||||||
logger.info('[ContractUploadController] signature cleanup completed for company user', { userId });
|
logger.info('[ContractUploadController] signature cleanup completed for company user', { userId });
|
||||||
}
|
}
|
||||||
logger.info(`[ContractUploadController] uploadCompanyContract success for userId: ${userId}`);
|
logger.info(`[ContractUploadController] uploadCompanyContract success for userId: ${userId}`);
|
||||||
res.json({ success: true, upload: result, downloadUrl: result.url || null });
|
res.json({ success: true, uploads, skipped, downloadUrls: uploads.map(u => u.url || null) });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`[ContractUploadController] uploadCompanyContract error for userId: ${userId}`, { error });
|
logger.error(`[ContractUploadController] uploadCompanyContract error for userId: ${userId}`, { error });
|
||||||
await unitOfWork.rollback(error);
|
await unitOfWork.rollback(error);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user