feat: implement deactivation of conflicting active contract templates during state updates
This commit is contained in:
parent
deb94c028b
commit
aa98d9ac37
@ -144,6 +144,49 @@ class DocumentTemplateRepository {
|
||||
}
|
||||
}
|
||||
|
||||
// Deactivate other active contract templates that would conflict with the one being activated.
|
||||
// Conflict dimensions:
|
||||
// - same type='contract'
|
||||
// - same contract_type ('contract' | 'gdpr')
|
||||
// - same lang
|
||||
// - overlapping user_type (personal/company/both)
|
||||
async deactivateOtherActiveContracts({ excludeId, contract_type, lang, user_type }, conn) {
|
||||
logger.info('DocumentTemplateRepository.deactivateOtherActiveContracts:start', { excludeId, contract_type, lang, user_type });
|
||||
const safeContractType = (contract_type === 'gdpr' || contract_type === 'contract') ? contract_type : 'contract';
|
||||
const safeLang = (lang === 'en' || lang === 'de') ? lang : 'en';
|
||||
const safeUserType = (user_type === 'personal' || user_type === 'company' || user_type === 'both') ? user_type : 'both';
|
||||
|
||||
// user_type overlap rules
|
||||
const overlap = safeUserType === 'both'
|
||||
? ['personal', 'company', 'both']
|
||||
: [safeUserType, 'both'];
|
||||
|
||||
const query = `
|
||||
UPDATE document_templates
|
||||
SET state = 'inactive', updatedAt = NOW()
|
||||
WHERE id <> ?
|
||||
AND type = 'contract'
|
||||
AND contract_type = ?
|
||||
AND lang = ?
|
||||
AND state = 'active'
|
||||
AND user_type IN (${overlap.map(() => '?').join(', ')})
|
||||
`;
|
||||
const params = [excludeId, safeContractType, safeLang, ...overlap];
|
||||
try {
|
||||
if (conn) {
|
||||
const [res] = await conn.execute(query, params);
|
||||
logger.info('DocumentTemplateRepository.deactivateOtherActiveContracts:success', { affected: res?.affectedRows });
|
||||
return res?.affectedRows || 0;
|
||||
}
|
||||
const res = await db.execute(query, params);
|
||||
logger.info('DocumentTemplateRepository.deactivateOtherActiveContracts:success', { affected: res?.affectedRows });
|
||||
return res?.affectedRows || 0;
|
||||
} catch (error) {
|
||||
logger.error('DocumentTemplateRepository.deactivateOtherActiveContracts:error', { error: error.message });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async delete(id, conn) {
|
||||
logger.info('DocumentTemplateRepository.delete:start', { id });
|
||||
const query = `DELETE FROM document_templates WHERE id = ?`;
|
||||
|
||||
@ -116,7 +116,25 @@ class DocumentTemplateService {
|
||||
const uow = new UnitOfWork();
|
||||
try {
|
||||
await uow.start();
|
||||
const current = await DocumentTemplateRepository.findById(id, uow.connection);
|
||||
if (!current) {
|
||||
logger.warn('DocumentTemplateService.updateTemplateState:not_found', { id });
|
||||
await uow.rollback();
|
||||
return null;
|
||||
}
|
||||
|
||||
await DocumentTemplateRepository.updateState(id, state, uow.connection);
|
||||
|
||||
// Enforce singleton active template per (contract_type + lang + overlapping user scope)
|
||||
if (state === 'active' && current.type === 'contract') {
|
||||
await DocumentTemplateRepository.deactivateOtherActiveContracts({
|
||||
excludeId: id,
|
||||
contract_type: current.contract_type || 'contract',
|
||||
lang: current.lang,
|
||||
user_type: current.user_type || 'both'
|
||||
}, uow.connection);
|
||||
}
|
||||
|
||||
const updated = await DocumentTemplateRepository.findById(id, uow.connection);
|
||||
await uow.commit();
|
||||
logger.info('DocumentTemplateService.updateTemplateState:success', { id, state });
|
||||
@ -158,6 +176,16 @@ class DocumentTemplateService {
|
||||
uow.connection
|
||||
);
|
||||
|
||||
// If new template is active and is a contract template, deactivate other conflicting actives
|
||||
if (nextState === 'active' && (data.type === 'contract' || previous.type === 'contract')) {
|
||||
await DocumentTemplateRepository.deactivateOtherActiveContracts({
|
||||
excludeId: created.id,
|
||||
contract_type: (data.contract_type || previous.contract_type || 'contract'),
|
||||
lang: (data.lang || previous.lang),
|
||||
user_type: (data.user_type || previous.user_type || 'both')
|
||||
}, uow.connection);
|
||||
}
|
||||
|
||||
// Deactivate previous (requirement: deactive the previous one)
|
||||
await DocumentTemplateRepository.updateState(previousId, 'inactive', uow.connection);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user