feat(core): implement optimistic locking across all entities
Add VersionMismatch error variant and check_version() helper to erp-core. All 13 mutable entities now enforce version checking on update/delete: - erp-auth: user, role, organization, department, position - erp-config: dictionary, dictionary_item, menu, setting, numbering_rule - erp-workflow: process_definition, process_instance, task - erp-message: message, message_subscription Update DTOs to expose version in responses and require version in update requests. HTTP 409 Conflict returned on version mismatch.
This commit is contained in:
@@ -7,6 +7,7 @@ use uuid::Uuid;
|
||||
use crate::dto::{CreateOrganizationReq, OrganizationResp, UpdateOrganizationReq};
|
||||
use crate::entity::organization;
|
||||
use crate::error::{AuthError, AuthResult};
|
||||
use erp_core::error::check_version;
|
||||
use erp_core::events::EventBus;
|
||||
|
||||
/// Organization CRUD service -- create, read, update, soft-delete organizations
|
||||
@@ -118,6 +119,7 @@ impl OrgService {
|
||||
level,
|
||||
sort_order: req.sort_order.unwrap_or(0),
|
||||
children: vec![],
|
||||
version: 1,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -152,6 +154,8 @@ impl OrgService {
|
||||
}
|
||||
}
|
||||
|
||||
let next_ver = check_version(req.version, model.version)?;
|
||||
|
||||
let mut active: organization::ActiveModel = model.into();
|
||||
|
||||
if let Some(ref name) = req.name {
|
||||
@@ -166,6 +170,7 @@ impl OrgService {
|
||||
|
||||
active.updated_at = Set(Utc::now());
|
||||
active.updated_by = Set(operator_id);
|
||||
active.version = Set(next_ver);
|
||||
|
||||
let updated = active
|
||||
.update(db)
|
||||
@@ -181,6 +186,7 @@ impl OrgService {
|
||||
level: updated.level,
|
||||
sort_order: updated.sort_order,
|
||||
children: vec![],
|
||||
version: updated.version,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -213,10 +219,12 @@ impl OrgService {
|
||||
));
|
||||
}
|
||||
|
||||
let current_version = model.version;
|
||||
let mut active: organization::ActiveModel = model.into();
|
||||
active.deleted_at = Set(Some(Utc::now()));
|
||||
active.updated_at = Set(Utc::now());
|
||||
active.updated_by = Set(operator_id);
|
||||
active.version = Set(current_version + 1);
|
||||
active
|
||||
.update(db)
|
||||
.await
|
||||
@@ -258,6 +266,7 @@ fn build_org_tree(items: &[organization::Model]) -> Vec<OrganizationResp> {
|
||||
level: item.level,
|
||||
sort_order: item.sort_order,
|
||||
children,
|
||||
version: item.version,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user