Merge pull request #398 from getrebuild/last-approver-732

Last approver RB-732
This commit is contained in:
RB 2021-11-01 16:47:01 +08:00 committed by GitHub
commit 537f597bbc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 95 additions and 42 deletions

2
@rbv

@ -1 +1 @@
Subproject commit 9a4de36241ba367728a2c45c4b6b4ec475fb9d34
Subproject commit 0662169c52c11b0bdb04e0935f7da4a18289026c

View file

@ -165,6 +165,7 @@ public class EntityHelper {
public static final String ApprovalId = "approvalId";
public static final String ApprovalState = "approvalState";
public static final String ApprovalStepNode = "approvalStepNode";
public static final String ApprovalLastUser = "approvalLastUser";
// 权限

View file

@ -249,7 +249,8 @@ public class MetadataHelper {
public static boolean isApprovalField(String fieldName) {
return EntityHelper.ApprovalId.equalsIgnoreCase(fieldName)
|| EntityHelper.ApprovalState.equalsIgnoreCase(fieldName)
|| EntityHelper.ApprovalStepNode.equalsIgnoreCase(fieldName);
|| EntityHelper.ApprovalStepNode.equalsIgnoreCase(fieldName)
|| EntityHelper.ApprovalLastUser.equalsIgnoreCase(fieldName);
}
/**

View file

@ -93,7 +93,7 @@ public class Entity2Schema extends Field2Schema {
"select min(typeCode) from MetaEntity").unique();
int typeCode = maxTypeCode == null || ObjectUtils.toInt(maxTypeCode[0]) == 0
? 999 : (ObjectUtils.toInt(maxTypeCode[0]) - 1);
if (typeCode <= (License.isCommercial() ? 500 : 900)) {
if (typeCode <= (License.isCommercial() ? 399 : 949)) {
throw new MetadataModificationException("ENTITY CODE EXCEEDS SYSTEM LIMIT : " + typeCode);
}
@ -116,7 +116,7 @@ public class Entity2Schema extends Field2Schema {
}
record.setString("nameField", nameFiled);
record = Application.getCommonsService().create(record);
tempMetaId.add(record.getPrimary());
recordedMetaId.add(record.getPrimary());
Entity tempEntity = new UnsafeEntity(entityName, physicalName, entityLabel, typeCode, nameFiled);
try {
@ -151,13 +151,13 @@ public class Entity2Schema extends Field2Schema {
}
} catch (Throwable ex) {
log.error(null, ex);
Application.getCommonsService().delete(tempMetaId.toArray(new ID[0]));
Application.getCommonsService().delete(recordedMetaId.toArray(new ID[0]));
throw new MetadataModificationException(Language.L("无法同步元数据到数据库 : %s", ex.getLocalizedMessage()));
}
boolean schemaReady = schema2Database(tempEntity);
if (!schemaReady) {
Application.getCommonsService().delete(tempMetaId.toArray(new ID[0]));
Application.getCommonsService().delete(recordedMetaId.toArray(new ID[0]));
throw new MetadataModificationException(Language.L("无法同步元数据到数据库"));
}

View file

@ -52,7 +52,7 @@ public class Field2Schema {
private static final int DECIMAL_SCALE = 8;
final protected ID user;
final protected Set<ID> tempMetaId = new HashSet<>();
final protected Set<ID> recordedMetaId = new HashSet<>();
/**
* @param user
@ -91,7 +91,7 @@ public class Field2Schema {
boolean schemaReady = schema2Database(entity, new Field[]{field});
if (!schemaReady) {
Application.getCommonsService().delete(tempMetaId.toArray(new ID[0]));
Application.getCommonsService().delete(recordedMetaId.toArray(new ID[0]));
throw new MetadataModificationException(Language.L("无法同步元数据到数据库"));
}
@ -292,7 +292,7 @@ public class Field2Schema {
}
recordOfField = Application.getCommonsService().create(recordOfField);
tempMetaId.add(recordOfField.getPrimary());
recordedMetaId.add(recordOfField.getPrimary());
// 以下会改变一些属性因为并不想他们保存在元数据中

View file

@ -40,10 +40,15 @@ public class ApprovalFields2Schema extends Field2Schema {
*/
public boolean createFields(Entity approvalEntity) throws MetadataModificationException {
if (MetadataHelper.hasApprovalField(approvalEntity)) {
if (!approvalEntity.containsField(EntityHelper.ApprovalLastUser)) {
return createApporvalLastUser(approvalEntity);
}
return false;
}
if (!(MetadataHelper.hasPrivilegesField(approvalEntity) || EasyMetaFactory.valueOf(approvalEntity).isPlainEntity())) {
throw new RebuildException("Unsupported entity : " + approvalEntity.getName());
if (!(MetadataHelper.hasPrivilegesField(approvalEntity)
|| EasyMetaFactory.valueOf(approvalEntity).isPlainEntity())) {
throw new RebuildException("UNSUPPORTED ENTITY : " + approvalEntity.getName());
}
Field apporvalId = createUnsafeField(approvalEntity, EntityHelper.ApprovalId, Language.L("审批流程"),
@ -52,16 +57,36 @@ public class ApprovalFields2Schema extends Field2Schema {
DisplayType.STATE, true, false, false, true, true, null, null, null, null, ApprovalState.DRAFT.getState());
Field apporvalStepId = createUnsafeField(approvalEntity, EntityHelper.ApprovalStepNode, Language.L("审批步骤"),
DisplayType.TEXT, true, false, false, true, false, null, null, null, null, null);
Field apporvalLastUser = buildApporvalLastUser(approvalEntity);
boolean schemaReady = schema2Database(approvalEntity,
new Field[] { apporvalId, apporvalState, apporvalStepId });
new Field[] { apporvalId, apporvalState, apporvalStepId, apporvalLastUser });
if (!schemaReady) {
Application.getCommonsService().delete(tempMetaId.toArray(new ID[0]));
Application.getCommonsService().delete(recordedMetaId.toArray(new ID[0]));
throw new MetadataModificationException(Language.L("无法同步元数据到数据库"));
}
MetadataHelper.getMetadataFactory().refresh(false);
return true;
}
// v2.7 最后审批人
private boolean createApporvalLastUser(Entity approvalEntity) {
Field apporvalLastUser = buildApporvalLastUser(approvalEntity);
boolean schemaReady = schema2Database(approvalEntity, new Field[] { apporvalLastUser });
if (!schemaReady) {
Application.getCommonsService().delete(recordedMetaId.toArray(new ID[0]));
throw new MetadataModificationException(Language.L("无法同步元数据到数据库"));
}
MetadataHelper.getMetadataFactory().refresh(false);
return true;
}
private Field buildApporvalLastUser(Entity approvalEntity) {
return createUnsafeField(approvalEntity, EntityHelper.ApprovalLastUser, Language.L("最后审批人"),
DisplayType.REFERENCE, true, false, false, true, true, null, "User", CascadeModel.Ignore, null, null);
}
}

View file

@ -93,11 +93,14 @@ public class ApprovalProcessor extends SetUser {
Set<ID> ccs = nextNodes.getCcUsers(this.getUser(), this.record, selectNextUsers);
Set<ID> ccs4share = nextNodes.getCcUsers4Share(this.getUser(), this.record, selectNextUsers);
Record mainRecord = EntityHelper.forUpdate(this.record, this.getUser(), false);
mainRecord.setID(EntityHelper.ApprovalId, this.approval);
mainRecord.setInt(EntityHelper.ApprovalState, ApprovalState.PROCESSING.getState());
mainRecord.setString(EntityHelper.ApprovalStepNode, nextNodes.getApprovalNode().getNodeId());
Application.getBean(ApprovalStepService.class).txSubmit(mainRecord, ccs, nextApprovers);
Record recordOfMain = EntityHelper.forUpdate(this.record, this.getUser(), false);
recordOfMain.setID(EntityHelper.ApprovalId, this.approval);
recordOfMain.setInt(EntityHelper.ApprovalState, ApprovalState.PROCESSING.getState());
recordOfMain.setString(EntityHelper.ApprovalStepNode, nextNodes.getApprovalNode().getNodeId());
if (recordOfMain.getEntity().containsField(EntityHelper.ApprovalLastUser)) {
recordOfMain.setNull(EntityHelper.ApprovalLastUser);
}
Application.getBean(ApprovalStepService.class).txSubmit(recordOfMain, ccs, nextApprovers);
// 非主事物
shareIfNeed(this.record, ccs4share);

View file

@ -23,6 +23,7 @@ import com.rebuild.core.service.DataSpecificationNoRollbackException;
import com.rebuild.core.service.general.GeneralEntityServiceContextHolder;
import com.rebuild.core.service.notification.MessageBuilder;
import com.rebuild.core.support.i18n.Language;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Set;
@ -36,6 +37,7 @@ import java.util.Set;
* @author devezhao
* @since 07/11/2019
*/
@Slf4j
@Service
public class ApprovalStepService extends BaseService {
@ -167,6 +169,9 @@ public class ApprovalStepService extends BaseService {
// 更新主记录状态
Record recordOfMain = EntityHelper.forUpdate(recordId, UserService.SYSTEM_USER, false);
recordOfMain.setInt(EntityHelper.ApprovalState, ApprovalState.REJECTED.getState());
if (recordOfMain.getEntity().containsField(EntityHelper.ApprovalLastUser)) {
recordOfMain.setID(EntityHelper.ApprovalLastUser, approver);
}
super.update(recordOfMain);
String rejectedMsg = Language.L("@%s 驳回了你的 %s 审批", approver, entityLabel);
@ -218,7 +223,7 @@ public class ApprovalStepService extends BaseService {
// 最终状态审批通过
if (goNextNode && (nextApprovers == null || nextNode == null)) {
Application.getEntityService(recordId.getEntityCode()).approve(recordId, ApprovalState.APPROVED);
Application.getEntityService(recordId.getEntityCode()).approve(recordId, ApprovalState.APPROVED, approver);
return;
}
@ -226,6 +231,9 @@ public class ApprovalStepService extends BaseService {
if (goNextNode) {
Record recordOfMain = EntityHelper.forUpdate(recordId, UserService.SYSTEM_USER, false);
recordOfMain.setString(EntityHelper.ApprovalStepNode, nextNode);
if (recordOfMain.getEntity().containsField(EntityHelper.ApprovalLastUser)) {
recordOfMain.setID(EntityHelper.ApprovalLastUser, approver);
}
super.update(recordOfMain);
}
@ -269,7 +277,7 @@ public class ApprovalStepService extends BaseService {
// 撤销
if (isRevoke) {
Application.getEntityService(recordId.getEntityCode()).approve(recordId, ApprovalState.REVOKED);
Application.getEntityService(recordId.getEntityCode()).approve(recordId, ApprovalState.REVOKED, null);
} else {
Record recordOfMain = EntityHelper.forUpdate(recordId, UserService.SYSTEM_USER, false);
recordOfMain.setInt(EntityHelper.ApprovalState, useState.getState());
@ -387,8 +395,10 @@ public class ApprovalStepService extends BaseService {
final ApprovalState currentState = ApprovalHelper.getApprovalState(recordId);
// 其他状态不能自动审批
if (currentState == ApprovalState.DRAFT || currentState == ApprovalState.REJECTED
if (currentState == ApprovalState.DRAFT
|| currentState == ApprovalState.REJECTED
|| currentState == ApprovalState.REVOKED) {
if (useApprover == null) useApprover = UserService.SYSTEM_USER;
if (useApproval == null) useApproval = APPROVAL_NOID;
@ -404,10 +414,13 @@ public class ApprovalStepService extends BaseService {
recordOfMain.setID(EntityHelper.ApprovalId, useApproval);
recordOfMain.setString(EntityHelper.ApprovalStepNode, FlowNode.NODE_AUTOAPPROVAL);
super.update(recordOfMain);
Application.getEntityService(recordId.getEntityCode()).approve(recordId, ApprovalState.APPROVED);
Application.getEntityService(recordId.getEntityCode()).approve(recordId, ApprovalState.APPROVED, useApprover);
return true;
}
} else {
log.warn("Invalid state {} for auto approval", currentState);
return false;
}
}
}

View file

@ -114,7 +114,8 @@ public interface EntityService extends ServiceSpec {
*
* @param record
* @param state 只接受通过或撤销
* @param approvalUser 审批人
* @see com.rebuild.core.service.approval.ApprovalStepService
*/
void approve(ID record, ApprovalState state);
void approve(ID record, ApprovalState state, ID approvalUser);
}

View file

@ -541,13 +541,19 @@ public class GeneralEntityService extends ObservableService implements EntitySer
}
@Override
public void approve(ID record, ApprovalState state) {
public void approve(ID record, ApprovalState state, ID approvalUser) {
Assert.isTrue(
state == ApprovalState.REVOKED || state == ApprovalState.APPROVED,
"Only REVOKED or APPROVED allowed");
Record approvalRecord = EntityHelper.forUpdate(record, UserService.SYSTEM_USER, false);
approvalRecord.setInt(EntityHelper.ApprovalState, state.getState());
if (state == ApprovalState.APPROVED
&& approvalUser != null
&& MetadataHelper.getEntity(record.getEntityCode()).containsField(EntityHelper.ApprovalLastUser)) {
approvalRecord.setID(EntityHelper.ApprovalLastUser, approvalUser);
}
delegateService.update(approvalRecord);
// 触发器

View file

@ -177,7 +177,7 @@ public class ReferenceSearchController extends EntityController {
private List<Object> resultSearch(String sqlWhere, Entity entity, int maxResults) {
Field nameField = entity.getNameField();
String sql = MessageFormat.format("select {0},{1} from {2} where {3}",
String sql = MessageFormat.format("select {0},{1} from {2} where ({3})",
entity.getPrimaryField().getName(), nameField.getName(), entity.getName(), sqlWhere);
if (!sqlWhere.contains(" order by ")) {

View file

@ -2840,21 +2840,27 @@ form {
margin: 0 -5px;
}
.form.approval-form .form-group {
.form.approval-form > .form-group {
padding: 0 20px;
}
.form.approval-form .form-group .zicon {
.form.approval-form > .form-group .zicon {
float: left;
padding-right: 6px;
width: 18px;
}
.form.approval-form .form-group .zicon.zmdi-mail-send {
.form.approval-form > .form-group .zicon.zmdi-mail-send {
font-size: 1.1rem;
margin-top: 2px;
}
.form.approval-form .rbform {
background-color: #f5f5f5;
border-radius: 2px;
padding: 15px;
}
.form.approval-form .approval-list {
padding: 5px 0;
}
@ -3011,16 +3017,6 @@ form {
text-align: center;
}
.form.approval-form .rbform {
background-color: #f5f5f5;
border-radius: 3px;
padding: 12px 0;
}
.form.approval-form .rbform .form-group.row {
padding: 10px 0;
}
.notification-page {
padding: 0 10px;
}

View file

@ -419,6 +419,7 @@ class ApprovalApproveForm extends ApprovalUsersForm {
<label>{$L('信息完善 (驳回时无需填写)')}</label>
<EditableForm $$$parent={fake} entity={this.props.entity} ref={(c) => (this._rbform = c)}>
{this.state.aform.map((item) => {
item.isFull = true
// eslint-disable-next-line no-undef
return detectElement(item)
})}

View file

@ -555,7 +555,7 @@ const RbListCommon = {
})
// via 过滤
const via = $urlp('via', location.hash)
const via = $urlp('via') || $urlp('via', location.hash)
if (via) {
wpc.protocolFilter = `via:${via}`
const $cleanVia = $(`<div class="badge filter-badge">${$L('当前数据已过滤')}<a class="close" title="${$L('查看全部数据')}">&times;</a></div>`).appendTo('.dataTables_filter')

View file

@ -36,15 +36,21 @@ class RbViewForm extends React.Component {
}
let hadApproval = res.data.hadApproval
let hadAlert = null
if (wpc.type === 'DetailView') {
if (hadApproval === 2) $('.J_edit, .J_delete').attr({ disabled: true, title: $L('主记录正在审批中') })
else if (hadApproval === 10) $('.J_edit, .J_delete').remove()
if (hadApproval === 2 || hadApproval === 10) {
if (window.RbViewPage) window.RbViewPage.setReadonly()
else $('.J_edit, .J_delete').remove()
hadAlert = <RbAlertBox message={hadApproval === 2 ? $L('主记录正在审批中明细记录禁止修改') : $L('主记录已审批完成明细记录禁止修改')} />
}
hadApproval = null
}
const viewData = {}
const VFORM = (
<React.Fragment>
{hadAlert}
{hadApproval && <ApprovalProcessor id={this.props.id} entity={this.props.entity} />}
<div className="row">
{res.data.elements.map((item) => {