package nckd.jxccl.hrmp.hbpm.business.hr.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import kd.bos.bill.BillShowParameter;
import kd.bos.bill.OperationStatus;
import kd.bos.common.enums.EnableEnum;
import kd.bos.context.RequestContext;
import kd.bos.dataentity.OperateOption;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.entity.ILocaleString;
import kd.bos.dataentity.metadata.IDataEntityProperty;
import kd.bos.dataentity.metadata.dynamicobject.DynamicProperty;
import kd.bos.dataentity.serialization.SerializationUtils;
import kd.bos.db.tx.Propagation;
import kd.bos.db.tx.TX;
import kd.bos.db.tx.TXHandle;
import kd.bos.entity.EntityMetadataCache;
import kd.bos.entity.constant.StatusEnum;
import kd.bos.entity.datamodel.IDataModel;
import kd.bos.entity.operate.OperateOptionConst;
import kd.bos.entity.operate.result.OperationResult;
import kd.bos.form.CloseCallBack;
import kd.bos.form.FormShowParameter;
import kd.bos.form.IFormView;
import kd.bos.form.ShowType;
import kd.bos.form.control.EntryGrid;
import kd.bos.form.field.events.BeforeF7SelectEvent;
import kd.bos.list.ListShowParameter;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.servicehelper.MetadataServiceHelper;
import kd.bos.servicehelper.model.PermissionStatus;
import kd.bos.servicehelper.operation.OperationServiceHelper;
import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
import kd.hr.hbp.business.servicehelper.HRMServiceHelper;
import kd.hr.hbp.common.constants.history.HisModelDataStatusEnum;
import kd.hr.hbp.common.model.AuthorizedOrgResult;
import kd.hr.hbp.common.util.HRDateTimeUtils;
import kd.hr.hbp.common.util.HRDynamicObjectUtils;
import kd.hr.hbp.common.util.HRObjectUtils;
import kd.hr.hbp.common.util.HRStringUtils;
import kd.sdk.hr.hdm.common.enums.reg.RegBillStatusEnum;
import nckd.jxccl.base.common.utils.QueryFieldBuilder;
import nckd.jxccl.hrmp.hbpm.common.hr.PositionBillConstant;
import nckd.jxccl.hrmp.hbpm.common.hr.PositionChangeTypeEnum;
import org.apache.commons.lang3.time.DateUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 岗位申请单帮助类
 * @from: kd.hr.homs.business.domain.batchbill.repository.AdminOrgBatchChgHelper
 * @author: jtd
 * @date: 2025-10-31 14:33
 */
public class PositionBillServiceHelper {
    private static final Log log = LogFactory.getLog(PositionBillServiceHelper.class);

    public static void setChangeDes(List<DynamicObject> changeDyos) {
        setChangeDes(changeDyos, false);
    }

    public static void setChangeDes(List<DynamicObject> changeDyos, Boolean isEntry) {
        String positionKey = isEntry ? String.format("%s_%s.%s", PositionBillConstant.NCKD_POSITION_KEY, PositionBillConstant.CHANGE_TAG, PositionBillConstant.BOID_KEY) : String.join(".", PositionBillConstant.NCKD_POSITION_KEY, PositionBillConstant.BOID_KEY);
        List<Long> changeIds = changeDyos.stream().map(changeDyo -> changeDyo.getLong(positionKey)).collect(Collectors.toList());

        // 获取要记录的变更字段
        Map<String, String> changeFieldMap = Arrays.stream(HRBaseServiceHelper.create(PositionBillConstant.NCKD_PBENTRY_CHANGE_FIELD_ENTITY).queryOriginalArray(PositionBillConstant.NUMBER_KEY, null, PositionBillConstant.INDEX_KEY)).map(changeFieldDy -> changeFieldDy.getString(PositionBillConstant.NUMBER_KEY)).collect(Collectors.toMap(Function.identity(), Function.identity(), (oldValue, newValue) -> newValue, LinkedHashMap::new));
        // 获取岗位要转换的键值
        Map<String, String> positionTransKeyMap = getPositionTransKeyMap();
        for (Map.Entry<String, String> entry : changeFieldMap.entrySet()) {
            if (positionTransKeyMap.containsKey(entry.getKey())) {
                changeFieldMap.put(entry.getKey(), positionTransKeyMap.get(entry.getKey()));
            }
        }

        if (isEntry) {
            // 获取分录要转换的键值
            Map<String, String> posBillEntryReverseTransKeyMap = getPosBillEntryTransKeyMap().entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey, (oldValue, newValue) -> newValue));
            changeFieldMap = changeFieldMap.entrySet().stream().collect(Collectors.toMap(entry -> {
                String entryChangeField = String.join("_", entry.getKey(), PositionBillConstant.CHANGE_TAG);
                if (posBillEntryReverseTransKeyMap.containsKey(entry.getKey())) {
                    entryChangeField = String.join("_", posBillEntryReverseTransKeyMap.get(entry.getKey()), PositionBillConstant.CHANGE_TAG);
                }
                return entryChangeField;
            }, Map.Entry::getValue, (oldValue, newValue) -> newValue, LinkedHashMap::new));
        }

        Map<String, IDataEntityProperty> positionAllFields = EntityMetadataCache.getDataEntityType(PositionBillConstant.HBPM_POSITIONHR).getAllFields();
        Map<Long, DynamicObject> dbPositionDyMap = Arrays.stream(HRBaseServiceHelper.create(PositionBillConstant.HBPM_POSITIONHR).loadDynamicObjectArray(changeIds.toArray())).collect(Collectors.toMap(dbPositionDy -> dbPositionDy.getLong(PositionBillConstant.BOID_KEY), Function.identity()));
        for (DynamicObject changeDyo : changeDyos) {
            List<String> changeDesList = new ArrayList<String>();
            DynamicObject dbPositionDyo = dbPositionDyMap.get(changeDyo.getLong(positionKey));
            for (Map.Entry<String, String> entry : changeFieldMap.entrySet()) {
                String positionField = entry.getValue();
                if (!positionAllFields.containsKey(positionField)) {
                    log.warn(HRStringUtils.format("PositionBillServiceHelper.setChangeDes not find field '{}' in position.", positionField));
                    continue;
                }

                boolean isChange;
                Object oldValue = dbPositionDyo.get(positionField);
                Object newValue = changeDyo.get(entry.getKey());
                if (HRObjectUtils.isEmpty(oldValue) && HRObjectUtils.isEmpty(newValue)) {
                    isChange = false;
                } else if ((HRObjectUtils.isEmpty(oldValue) && !HRObjectUtils.isEmpty(newValue)) || (!HRObjectUtils.isEmpty(oldValue) && HRObjectUtils.isEmpty(newValue))) {
                    isChange = true;
                } else {
                    isChange = !HRDynamicObjectUtils.compareValues(oldValue, newValue);
                }

                if (isChange) {
                    String fieldName = changeDyo.getDynamicObjectType().getProperty(entry.getKey()).getDisplayName().getLocaleValue();
                    changeDesList.add(HRStringUtils.format("{}：\"{}\" -> \"{}\"", fieldName, getValue(dbPositionDyo, positionField, oldValue), getValue(changeDyo, entry.getKey(), newValue)));
                }
            }

            changeDyo.set(isEntry ? String.join("_", PositionBillConstant.NCKD_CHANGEDES_KEY, PositionBillConstant.CHANGE_TAG) : PositionBillConstant.NCKD_CHANGEDES_KEY, changeDesList.isEmpty() ? null : String.join(System.lineSeparator(), changeDesList));
        }
    }

    private static String getValue(DynamicObject dyo, String field, Object val) {
        if (!HRObjectUtils.isEmpty(val)) {
            if (val instanceof DynamicObject) {
                return ((DynamicObject) val).getString(PositionBillConstant.NAME_KEY);
            } else if (val instanceof DynamicObjectCollection) {
                if (((DynamicObjectCollection) val).isEmpty()) {
                    return " ";
                }

                List<String> list = new ArrayList<String>();
                for (DynamicObject d : (DynamicObjectCollection) val) {
                    DynamicProperty baseDataProp = d.getDynamicObjectType().getProperty(PositionBillConstant.FBASEDATAID_KEY);
                    if (baseDataProp == null) {
                        list.add(d.getString(PositionBillConstant.NAME_KEY));
                    } else {
                        list.add(d.getDynamicObject(PositionBillConstant.FBASEDATAID_KEY).getString(PositionBillConstant.NAME_KEY));
                    }
                }
                return String.join("；", list);
            } else {
                return dyo.getString(field);
            }
        }

        return " ";
    }

    public static String getNoLineSuffixProp(String prop, String lineSuffix) {
        if (prop.endsWith(lineSuffix)) {
            return prop.substring(0, prop.lastIndexOf(lineSuffix));
        }
        return prop;
    }

    /**
     * 获取岗位转换键值
     * @return 目标字段: 源字段
     */
    public static Map<String, String> getPositionTransKeyMap() {
        String selectFields = QueryFieldBuilder.create().add(PositionBillConstant.NUMBER_KEY).add(PositionBillConstant.NAME_KEY).buildSelect();
        DynamicObject[] transKeyDyos = HRBaseServiceHelper.create(PositionBillConstant.NCKD_POSITION_TRANSKEY_ENTITY).queryOriginalArray(selectFields, null);
        Map<String, String> transKeyMap = Arrays.stream(transKeyDyos).collect(Collectors.toMap(
                transKeyDyo -> transKeyDyo.getString(PositionBillConstant.NAME_KEY),
                transKeyDyo -> transKeyDyo.getString(PositionBillConstant.NUMBER_KEY),
                (oldValue, newValue) -> newValue)
        );
        return transKeyMap;
    }

    /**
     * 获取岗位申请分录转换键值
     * @return 单据分录字段: 分录页面字段
     */
    public static Map<String, String> getPosBillEntryTransKeyMap() {
        String selectFields = QueryFieldBuilder.create().add(PositionBillConstant.NUMBER_KEY).add(PositionBillConstant.NAME_KEY).buildSelect();
        DynamicObject[] transKeyDyos = HRBaseServiceHelper.create(PositionBillConstant.NCKD_PBENTRY_TRANSKEY_ENTITY).queryOriginalArray(selectFields, null);
        Map<String, String> transKeyMap = Arrays.stream(transKeyDyos).collect(Collectors.toMap(
                transKeyDyo -> transKeyDyo.getString(PositionBillConstant.NUMBER_KEY),
                transKeyDyo -> transKeyDyo.getString(PositionBillConstant.NAME_KEY),
                (oldValue, newValue) -> newValue));
        return transKeyMap;
    }

    public static Set<String> getPositionProperties() {
        return EntityMetadataCache.getDataEntityType(PositionBillConstant.HBPM_POSITIONHR).getProperties().stream().map(IDataEntityProperty::getName).collect(Collectors.toSet());
    }

    public static Set<String> getPositionAllFields() {
        return new HashSet<String>(EntityMetadataCache.getDataEntityType(PositionBillConstant.HBPM_POSITIONHR).getAllFields().keySet());
    }

    /**
     * 获取分录序号
     * @param iDataModel
     * @param changeTypeNumber
     * @return
     */
    public static int getEntrySeq(IDataModel iDataModel, String changeTypeNumber) {
        Long billId = iDataModel.getDataEntity().getLong(PositionBillConstant.ID_KEY);
        HRBaseServiceHelper positionBillEntryServiceHelper = new HRBaseServiceHelper(PositionBillConstant.NCKD_POSITIONBILLENTRY_ENTITY);
        QFilter qFilter = new QFilter(PositionBillConstant.NCKD_BILLID, QCP.equals, billId);
        qFilter.and(String.join(".", PositionBillConstant.NCKD_CHANGETYPE, PositionBillConstant.NUMBER_KEY), QCP.equals, changeTypeNumber);
        String selectProps = String.join(",", PositionBillConstant.ID_KEY, PositionBillConstant.NCKD_SEQUENCE);
        String order = String.format("%s desc", PositionBillConstant.NCKD_SEQUENCE);
        DynamicObject dynamicObject = positionBillEntryServiceHelper.queryOne(selectProps, qFilter.toArray(), order);
        return dynamicObject == null ? 1 : dynamicObject.getInt(PositionBillConstant.NCKD_SEQUENCE) + 1;
    }

    /**
     * 打开表单界面
     * @param iFormView
     * @param operation
     * @param pluginName
     */
    public static void openViewForm(IFormView iFormView, String operation, String pluginName, QFilter filter) {
        if (iFormView.getModel().getValue(PositionBillConstant.ORG_KEY) == null) {
            iFormView.showTipNotification("请先填写组织体系管理组织。");
        } else {
            HRBaseServiceHelper positionBillHelper = new HRBaseServiceHelper(PositionBillConstant.NCKD_POSITIONBILL_ENTITY);
            QFilter idFilter = new QFilter(PositionBillConstant.ID_KEY, "=", iFormView.getModel().getDataEntity().getLong(PositionBillConstant.ID_KEY));
            DynamicObject dynamicObject = positionBillHelper.loadDynamicObject(idFilter);
            if (dynamicObject != null) {
                String billStatus = dynamicObject.getString(PositionBillConstant.BILL_STATUS_KEY);
                if (!billStatus.equals(RegBillStatusEnum.TEMPSTORAGE.getCode()) && !billStatus.equals(RegBillStatusEnum.WAITRESUBMIT.getCode()) && !billStatus.equals(RegBillStatusEnum.APPROVING.getCode()) && (!billStatus.equals(RegBillStatusEnum.ALREADYSUBMIT.getCode()) || !HRStringUtils.equals(iFormView.getFormShowParameter().getAppId(), PositionBillConstant.WFTASK_APP))) {
                    String operateLocaleName = PositionChangeTypeEnum.getTipByTag(operation);
                    String auditstatusName = RegBillStatusEnum.getName(dynamicObject.getString(PositionBillConstant.BILL_STATUS_KEY));
                    iFormView.showErrorNotification(String.format("“%1$s”的单据不能“%2$s”。", auditstatusName, operateLocaleName));
                    return;
                }
            }

            ListShowParameter listShowParameter = new ListShowParameter();
            if (filter != null) {
                listShowParameter.getListFilterParameter().getQFilters().add(filter);
            }

            switch (operation) {
                case PositionBillConstant.ADD_TAG:
                    BillShowParameter formShowParameter = new BillShowParameter();
                    formShowParameter.setCustomParam(PositionBillConstant.CP_POSITION_BSED, iFormView.getModel().getValue(PositionBillConstant.NCKD_EFFDT) == null ? HRDateTimeUtils.getNowDateTime().getTime() : ((Date)iFormView.getModel().getValue(PositionBillConstant.NCKD_EFFDT)).getTime());
                    formShowParameter.setFormId(PositionBillConstant.NCKD_POSBILLENTRYADD_ENTITY);
                    formShowParameter.getOpenStyle().setShowType(ShowType.Modal);
                    formShowParameter.setCustomParam(PositionBillConstant.CP_BILLID, iFormView.getModel().getDataEntity().getLong(PositionBillConstant.ID_KEY));
                    formShowParameter.setCustomParam(PositionBillConstant.CP_BILLBSED, iFormView.getModel().getDataEntity().getDate(PositionBillConstant.NCKD_EFFDT));
                    formShowParameter.setCloseCallBack(new CloseCallBack(pluginName, PositionBillConstant.NCKD_ENTRYENTITY_ADD_KEY));

                    if (HRStringUtils.equals(iFormView.getFormShowParameter().getAppId(), PositionBillConstant.WFTASK_APP)) {
                        formShowParameter.setHasRight(true);
                    }
                    formShowParameter.setCustomParam(PositionBillConstant.ORG_KEY, iFormView.getModel().getDataEntity().getLong(String.join(".", PositionBillConstant.ORG_KEY, PositionBillConstant.ID_KEY)));
                    int sequence = getEntrySeq(iFormView.getModel(), PositionChangeTypeEnum.ADD.getNumber());
                    formShowParameter.setCustomParam(PositionBillConstant.CP_SEQUENCE, sequence);
                    formShowParameter.setCustomParam(PositionBillConstant.OP_VALIDATOR_BILL_POSITION_ALL_CHANGE_POSITION_KEY, getThisBillAllValidateDataStr(dynamicObject));
                    formShowParameter.setCustomParam(PositionBillConstant.OP_VALIDATOR_BILL_POSITION_NEW_POSITION_NUMBERS_KEY, getThisBillPositionNumbersStr(dynamicObject));
                    iFormView.showForm(formShowParameter);
                default:
            }
        }
    }

    public static AuthorizedOrgResult getOrgAuth(IFormView iFormView) {
        Long userId = RequestContext.get().getCurrUserId();
        String permItemId = PermissionStatus.View;// 查询权限
        String appId = iFormView.getFormShowParameter().getCheckRightAppId();
        AuthorizedOrgResult permResult = HRMServiceHelper.invokeHRMPService(PositionBillConstant.HRCS_APP, "IHRCSBizDataPermissionService", "getUserAdminOrgsF7", new Object[]{userId, appId, PositionBillConstant.NCKD_POSITIONBILL_ENTITY, permItemId, PositionBillConstant.NCKD_ADMINORGBOID_KEY, Maps.newHashMapWithExpectedSize(0)});
        return permResult;
    }

    public static Map<Long, DynamicObject> getPositionId2BasicInfoDynMapByIds(List<Long> positionIdList) {
        HRBaseServiceHelper serviceHelper = new HRBaseServiceHelper(PositionBillConstant.HBPM_POSITIONHR);
        QFilter qFilter = new QFilter(PositionBillConstant.ID_KEY, QCP.in, positionIdList);
        DynamicObject[] dynamicObjects = serviceHelper.loadDynamicObjectArray(qFilter.toArray());
        Map<Long, DynamicObject> positionId2DynMap = Arrays.stream(dynamicObjects).collect(Collectors.toMap((dyn) -> dyn.getLong(PositionBillConstant.ID_KEY), (dyn) -> dyn));
        return positionId2DynMap;
    }

    public static void setParentFilter(IFormView view, DynamicObject positionObject, BeforeF7SelectEvent event) {
        DynamicObject dataEntityParent = view.getModel().getDataEntity(true);
        QFilter isCurrentVersion = new QFilter(PositionBillConstant.IS_CURRENT_VERSION, QCP.equals, EnableEnum.NO.getCode());
        DynamicObjectCollection addCollection = dataEntityParent.getDynamicObjectCollection(PositionBillConstant.NCKD_ENTRYENTITY_ADD_KEY);
        Set<String> positionSet = addCollection.stream().map((s) -> s.getString(String.join("_", PositionBillConstant.NCKD_POSITION_KEY, PositionBillConstant.ADD_TAG))).collect(Collectors.toSet());
        Set<Long> addPositionIdSet = positionSet.stream().map(Long::valueOf).collect(Collectors.toSet());
        QFilter currentOrderFilter = new QFilter(PositionBillConstant.ID_KEY, QCP.in, addPositionIdSet);

        AuthorizedOrgResult permResult = getOrgAuth(view);
        if (permResult != null && !permResult.isHasAllOrgPerm()) {
            log.info("[非全功能用户过滤条件]");
            QFilter authFilter = new QFilter(String.join(PositionBillConstant.ADMINORG, PositionBillConstant.BOID_KEY), QCP.in, permResult.getHasPermOrgs());
            event.getCustomQFilters().add(authFilter.or(currentOrderFilter));
        }

        DynamicObject buOrg = dataEntityParent.getDynamicObject(PositionBillConstant.ORG_KEY);
        if (positionObject != null) {
            event.getCustomQFilters().add(new QFilter(PositionBillConstant.ID_KEY, QCP.not_equals, positionObject.getLong(PositionBillConstant.ID_KEY)));
            buOrg = positionObject.getDynamicObject(PositionBillConstant.ORG_KEY);
        }

        Date effDate = HRObjectUtils.isEmpty(view.getModel().getValue(PositionBillConstant.NCKD_EFFDT)) ? DateUtils.truncate(new Date(), 5) : (Date) view.getModel().getValue(PositionBillConstant.NCKD_EFFDT);
        event.getCustomQFilters().add(new QFilter(PositionBillConstant.BSED_KEY, QCP.less_equals, effDate));
        event.getCustomQFilters().add(new QFilter(PositionBillConstant.BSLED_KEY, QCP.large_equals, effDate));
        if (buOrg != null) {
            event.getCustomQFilters().add(new QFilter(PositionBillConstant.ORG_KEY, QCP.equals, buOrg.getLong(PositionBillConstant.ID_KEY)));
        }

        QFilter dataStatusFilter = new QFilter(PositionBillConstant.DATA_STATUS, QCP.in, Arrays.asList(HisModelDataStatusEnum.EFFECTING.getStatus(), HisModelDataStatusEnum.TO_BE_EFFECT.getStatus()));
        event.getCustomQFilters().add(dataStatusFilter.or(currentOrderFilter));
        QFilter statusFilter = new QFilter(PositionBillConstant.STATUS, QCP.equals, StatusEnum.C);
        event.getCustomQFilters().add(statusFilter.or(currentOrderFilter));
        event.getCustomQFilters().add(isCurrentVersion.or(currentOrderFilter));
        ListShowParameter formShowParameter = (ListShowParameter) event.getFormShowParameter();
        formShowParameter.setShowApproved(false);
    }

    public static void filterF7Org(IFormView iFormView, BeforeF7SelectEvent event, QFilter filter) {
        FormShowParameter formShowParameter = event.getFormShowParameter();
        formShowParameter.setFormId(PositionBillConstant.NCKD_HBPM_POSORGTREELISTF_ENTITY);
        log.info("[岗位F7过滤条件]");
        event.getCustomQFilters().add(filter);
        Object originalValue = event.getOriginalValue();
        if (originalValue instanceof DynamicObject) {
            DynamicObject originalVal = (DynamicObject) originalValue;
            long currentPositionId = originalVal.getLong(PositionBillConstant.ID_KEY);
            QFilter positionIdFilter = new QFilter(PositionBillConstant.ID_KEY, QCP.not_equals, currentPositionId);
            event.getCustomQFilters().add(positionIdFilter);
        }

        QFilter currentBillPositionFilter = filterCurrentBillOrg(iFormView);
        event.getCustomQFilters().add(currentBillPositionFilter);

        event.getCustomQFilters().add(new QFilter(PositionBillConstant.ORG_KEY, QCP.equals, ((DynamicObject) iFormView.getModel().getValue(PositionBillConstant.ORG_KEY)).getLong(PositionBillConstant.ID_KEY)));
        event.getFormShowParameter().setCaption("岗位");
    }

    public static QFilter filterCurrentBillOrg(IFormView iFormView) {
        List<Long> list = new ArrayList();
        DynamicObjectCollection change = new DynamicObjectCollection();
        if (iFormView.getEntityId().equals(PositionBillConstant.NCKD_POSITIONBILL_ENTITY)) {
            change = iFormView.getModel().getDataEntity(true).getDynamicObjectCollection(PositionBillConstant.NCKD_ENTRYENTITY_CHANGE_KEY);
        } else if (iFormView.getEntityId().equals(PositionBillConstant.NCKD_POSBILLENTRYCHANGE_ENTITY)) {
            change = iFormView.getParentView().getModel().getDataEntity(true).getDynamicObjectCollection(PositionBillConstant.NCKD_ENTRYENTITY_CHANGE_KEY);
        }

        if (change != null) {
            list.addAll(change.stream().map((position) -> position.getLong(String.format("%s_%s.%s", PositionBillConstant.NCKD_POSITION_KEY, PositionBillConstant.CHANGE_TAG, PositionBillConstant.BOID_KEY))).collect(Collectors.toList()));
        }

        return list.isEmpty() ? new QFilter(PositionBillConstant.ID_KEY, QCP.not_equals, 20000L) : new QFilter(PositionBillConstant.BOID_KEY, QCP.not_in, list);
    }

    public static DynamicObject getPositionDyById(Long orgId) {
        HRBaseServiceHelper serviceHelper = new HRBaseServiceHelper(PositionBillConstant.HBPM_POSITIONHR);
        QFilter qFilter = new QFilter(PositionBillConstant.ID_KEY, QCP.equals, orgId);
        DynamicObject dynamicObject = serviceHelper.loadDynamicObject(qFilter.toArray());
        return dynamicObject;
    }

    public static List<Long> getPositionAndChildren(Long positionId, Date positionBsed) {
        List<Long> positionIds = new ArrayList();
        HRBaseServiceHelper parentServiceHelper = new HRBaseServiceHelper(PositionBillConstant.HBPM_POSITIONHR);
        QFilter parentFilter = new QFilter(PositionBillConstant.PARENT_KEY, QCP.equals, positionId)
                .and(PositionBillConstant.IS_CURRENT_VERSION, QCP.equals, false)
                .and(PositionBillConstant.BSED_KEY, QCP.less_equals, positionBsed)
                .and(PositionBillConstant.BSLED_KEY, QCP.large_equals, positionBsed)
                .and(PositionBillConstant.DATA_STATUS, QCP.in, Arrays.asList(HisModelDataStatusEnum.EFFECTING.getStatus(), HisModelDataStatusEnum.TO_BE_EFFECT.getStatus()))
                .and(PositionBillConstant.STATUS, QCP.equals, StatusEnum.C);

        DynamicObjectCollection dynamicObjects = parentServiceHelper.queryOriginalCollection(PositionBillConstant.ID_KEY, parentFilter.toArray());
        dynamicObjects.forEach((dy) -> positionIds.add(dy.getLong(PositionBillConstant.ID_KEY)));

        return positionIds;
    }

    /**
     * 删除岗位新设暂存数据
     * @param positionIdList
     */
    public static void delAddMaster(List<Long> positionIdList) {
//        HisDeleteParam hisDeleteParam = new HisDeleteParam();
//        hisDeleteParam.setEntityNumber(PositionBillConstant.HBPM_POSITIONHR);
//        hisDeleteParam.setDataList(Arrays.asList(HRBaseServiceHelper.create(PositionBillConstant.HBPM_POSITIONHR).loadDynamicObjectArray(positionIdList.toArray())));
//        HisModelServiceHelper.deleteBo(hisDeleteParam);

        // 删除HR岗位暂存的数据
        HRBaseServiceHelper.create(PositionBillConstant.HBPM_POSITIONHR).deleteByFilter(new QFilter[]{new QFilter(PositionBillConstant.BOID_KEY, QCP.in, positionIdList)});

        delAddMasterForBos(positionIdList);
    }

    /**
     * 删除BOS岗位新设暂存数据
     * @param positionIdList
     */
    public static void delAddMasterForBos(List<Long> positionIdList) {
        QFilter[] qFilters = {new QFilter(PositionBillConstant.ID_KEY, QCP.in, positionIdList)};
        if (TX.getPropagation() != Propagation.NOT_SUPPORTED) {
            try (TXHandle tx = TX.requiresNew()) {
                HRBaseServiceHelper.create(PositionBillConstant.BOS_POSITION_ENTITY).deleteByFilter(qFilters);
            }
        } else {
            HRBaseServiceHelper.create(PositionBillConstant.BOS_POSITION_ENTITY).deleteByFilter(qFilters);
        }
    }

    public static DynamicObject getFocusEntry(String suffix, IFormView view, int row) {
        EntryGrid entryGrid = view.getControl(String.join("_", PositionBillConstant.NCKD_ENTRYENTITY, suffix));
        if (row == -1) {
            row = entryGrid.getEntryState().getFocusRow();
        }

        DynamicObject entryEntityDyn = view.getModel().getDataEntity(true).getDynamicObjectCollection(String.join("_", PositionBillConstant.NCKD_ENTRYENTITY, suffix)).get(row);
        long entityId = entryEntityDyn.getLong(PositionBillConstant.ID_KEY);
        if (entityId != 0L) {
            HRBaseServiceHelper serviceHelper = new HRBaseServiceHelper(PositionBillConstant.NCKD_POSITIONBILLENTRY_ENTITY);
            serviceHelper.deleteOne(entityId);
            entryEntityDyn.set(PositionBillConstant.ID_KEY, 0L);
        }

        return entryEntityDyn;
    }

    public static Long getHisId(Long boId) {
        DynamicObject dynamicObject = getHisDynamicObject(boId);
        return dynamicObject != null ? dynamicObject.getLong(PositionBillConstant.ID_KEY) : boId;
    }

    public static DynamicObject getHisDynamicObject(Long boId) {
        if (boId != null && boId != 0L) {
            HRBaseServiceHelper positionHelper = new HRBaseServiceHelper(PositionBillConstant.HBPM_POSITIONHR);
            QFilter idFilter = new QFilter(PositionBillConstant.BOID_KEY, QCP.equals, boId);
            Date effDate = HRDateTimeUtils.truncateDate(new Date());
            QFilter hisVersionFilter = (new QFilter(PositionBillConstant.IS_CURRENT_VERSION, QCP.equals, false)).and((new QFilter(PositionBillConstant.BSED_KEY, QCP.less_equals, effDate)).and(new QFilter(PositionBillConstant.BSLED_KEY, QCP.large_equals, effDate))).and(new QFilter(PositionBillConstant.DATA_STATUS, QCP.in, Arrays.asList(HisModelDataStatusEnum.EFFECTING.getStatus(), HisModelDataStatusEnum.EFFECTING.getStatus())));
            hisVersionFilter.and(PositionBillConstant.ISSTANDARDPOS_KEY, QCP.equals, true);
            return positionHelper.queryOne(PositionBillConstant.ID_KEY, new QFilter[]{idFilter, hisVersionFilter});
        } else {
            return null;
        }
    }

    /**
     * 构建岗位
     * 用于校验岗位数据或获取/回收岗位编码
     * @param addDy
     * @return
     */
    public static DynamicObject getPositionHrDy(DynamicObject addDy) {
        return getPositionHrDy(addDy, getPositionTransKeyMap());
    }

    /**
     * 构建岗位
     * 用于校验岗位数据或获取/回收岗位编码
     * @param addDy
     * @param transKeyMap
     * @return
     */
    public static DynamicObject getPositionHrDy(DynamicObject addDy, Map<String, String> transKeyMap) {
        DynamicObject positionHrDy = new DynamicObject(MetadataServiceHelper.getDataEntityType(PositionBillConstant.HBPM_POSITIONHR));
        getPositionHrDy(addDy, positionHrDy, transKeyMap);
        // 设置 是否标准岗位
        positionHrDy.set(PositionBillConstant.ISSTANDARDPOS_KEY, EnableEnum.NO.getCode());
        // 设置 业务状态
        positionHrDy.set(PositionBillConstant.ENABLE, EnableEnum.YES.getCode());
        // 设置 数据状态
        positionHrDy.set(PositionBillConstant.STATUS, StatusEnum.C);
        // 设置 数据版本状态
        positionHrDy.set(PositionBillConstant.DATA_STATUS, HisModelDataStatusEnum.EFFECTING);
        // 设置 行政组织
        DynamicObject adminOrgVersionDy = addDy.getDynamicObject(PositionBillConstant.NCKD_ADMINORG);
        if (HRObjectUtils.isEmpty(adminOrgVersionDy)) {
            positionHrDy.set(PositionBillConstant.ADMINORG, null);
        } else {
            positionHrDy.set(PositionBillConstant.ADMINORG, HRBaseServiceHelper.create(PositionBillConstant.ADMINORG_ENTITYID).loadSingle(adminOrgVersionDy.getLong(PositionBillConstant.BOID_KEY)));
        }
        // 设置 上级岗位
        DynamicObject parentPositionVersionDy = addDy.getDynamicObject(PositionBillConstant.NCKD_PARENT);
        if (HRObjectUtils.isEmpty(parentPositionVersionDy)) {
            positionHrDy.set(PositionBillConstant.PARENT_KEY, null);
        } else {
            positionHrDy.set(PositionBillConstant.PARENT_KEY, HRBaseServiceHelper.create(PositionBillConstant.HBPM_POSITIONHR).loadSingle(parentPositionVersionDy.getLong(PositionBillConstant.BOID_KEY)));
        }
        return positionHrDy;
    }

    /**
     * 构建岗位
     * @param addDy
     * @param positionDyo
     * @param transKeyMap
     * @return
     */
    public static DynamicObject getPositionHrDy(DynamicObject addDy, DynamicObject positionDyo, Map<String, String> transKeyMap) {
        // 将表单中的信息赋值到岗位信息中
        HRDynamicObjectUtils.copy(addDy, positionDyo, transKeyMap);
        // 设置ID
        positionDyo.set(PositionBillConstant.ID_KEY, addDy.getLong(PositionBillConstant.ID_KEY));
        // 设置 业务状态
        //positionDyo.set(PositionBillConstant.ENABLE, EnableEnum.YES.getCode());
        // 设置 数据状态
        //positionDyo.set(PositionBillConstant.STATUS, StatusEnum.A);
        // 设置 数据版本状态
        //positionDyo.set(PositionBillConstant.DATA_STATUS, " ");
        return positionDyo;
    }

    public static void entryEntityMore(IDataModel iDataModel, IFormView iFormView, String tag, OperationStatus status, String pluginName) {
        EntryGrid entryEntity = iFormView.getControl(String.join("_", PositionBillConstant.NCKD_ENTRYENTITY, tag));
        int row = entryEntity.getEntryState().getFocusRow();
        DynamicObject dynamicObject = iDataModel.getDataEntity(true).getDynamicObjectCollection(String.join("_", PositionBillConstant.NCKD_ENTRYENTITY, tag)).get(row);
        Map map = HRDynamicObjectUtils.convertDynamicObjectToMap(dynamicObject);
        long id = dynamicObject.getLong(PositionBillConstant.ID_KEY);
        BillShowParameter formShowParameter = new BillShowParameter();
        Object dy = dynamicObject.get(String.join("_", PositionBillConstant.NCKD_POSITION_KEY, tag));
        if (dy == null) {
            iFormView.showTipNotification("请先选择岗位。");
        } else {
            if (PositionBillConstant.CHANGE_TAG.equals(tag)) {
                formShowParameter.setFormId(PositionBillConstant.NCKD_POSBILLENTRYCHANGE_ENTITY);
            }

            // 获取岗位申请单分录服务
            HRBaseServiceHelper helper = new HRBaseServiceHelper(PositionBillConstant.NCKD_POSITIONBILLENTRY_ENTITY);
            boolean exists = helper.isExists(id);
            if (exists) {
                formShowParameter.setPkId(id);
            } else {
                formShowParameter.setCustomParam(PositionBillConstant.ID_KEY, id);
            }

            if (HRStringUtils.equals(iFormView.getFormShowParameter().getAppId(), PositionBillConstant.WFTASK_APP)) {
                formShowParameter.setHasRight(true);
            }

            formShowParameter.setStatus(status);
            formShowParameter.setCustomParam(PositionBillConstant.ID_KEY, id);
            formShowParameter.getOpenStyle().setShowType(ShowType.Modal);
            formShowParameter.setCustomParam(PositionBillConstant.CP_SELECTOBJECT, SerializationUtils.toJsonString(map));
            formShowParameter.setCustomParam(PositionBillConstant.CP_BILLID, iDataModel.getValue(PositionBillConstant.ID_KEY));
            formShowParameter.setCustomParam(PositionBillConstant.CP_POSITIONID, String.valueOf(dynamicObject.getLong(String.format("%s_%s.%s", PositionBillConstant.NCKD_POSITION_KEY, tag, PositionBillConstant.ID_KEY))));
            formShowParameter.setCustomParam(PositionBillConstant.CP_POSITION_BSED, iDataModel.getValue(PositionBillConstant.NCKD_EFFDT) == null ? HRDateTimeUtils.getNowDateTime().getTime() : ((Date) iDataModel.getValue(PositionBillConstant.NCKD_EFFDT)).getTime());
            formShowParameter.setCustomParam(PositionBillConstant.ORG_KEY, iDataModel.getDataEntity().getLong(String.join(".", PositionBillConstant.ORG_KEY, PositionBillConstant.ID_KEY)));
            formShowParameter.setCustomParam(PositionBillConstant.BILL_STATUS_KEY, iDataModel.getDataEntity().get(PositionBillConstant.BILL_STATUS_KEY));
            int sequence = getEntrySeq(iFormView.getModel(), PositionChangeTypeEnum.getNumberByTag(tag));
            formShowParameter.setCustomParam(PositionBillConstant.CP_SEQUENCE, sequence);
            formShowParameter.setCloseCallBack(new CloseCallBack(pluginName, String.join("_", PositionBillConstant.NCKD_ENTRYENTITY, tag)));
            formShowParameter.setCustomParam(PositionBillConstant.OP_VALIDATOR_BILL_POSITION_ALL_CHANGE_POSITION_KEY, getThisBillAllValidateDataStr(iDataModel.getDataEntity(true)));
            formShowParameter.setCustomParam(PositionBillConstant.OP_VALIDATOR_BILL_POSITION_NEW_POSITION_NUMBERS_KEY, getThisBillPositionNumbersStr(iDataModel.getDataEntity(true)));
            iFormView.showForm(formShowParameter);
        }
    }

    public static String getThisBillAllValidateDataStr(DynamicObject bill) {
        if (bill == null) {
            return "";
        } else {
            DynamicObjectCollection positionEntryDys = new DynamicObjectCollection();
            positionEntryDys.addAll(bill.getDynamicObjectCollection(PositionBillConstant.NCKD_ENTRYENTITY_ADD_KEY));
            positionEntryDys.addAll(bill.getDynamicObjectCollection(PositionBillConstant.NCKD_ENTRYENTITY_CHANGE_KEY));
            PositionBillSaveHelper helper = PositionBillSaveHelper.getInstance();
            Map<Long, List<String>> positionBoIdToChangeTypeNumberMap = Maps.newHashMapWithExpectedSize(16);

            for(DynamicObject entryDy : positionEntryDys) {
                String suffix = helper.getSuffixFromEntryEntityDyn(entryDy);
                String changeTypeNumber = PositionChangeTypeEnum.getNumberByTag(suffix);
                Long positionBoId = null;
                if (PositionChangeTypeEnum.ADD.getNumber().equals(changeTypeNumber)) {
                    positionBoId = helper.getPositionId(entryDy, suffix);
                } else {
                    DynamicObject positionDyRef = entryDy.getDynamicObject(helper.spliceTwoStringByUnderLine(suffix, PositionBillConstant.NCKD_POSITION_KEY));
                    if (positionDyRef != null) {
                        positionBoId = positionDyRef.getLong(PositionBillConstant.BOID_KEY);
                    }
                }

                if (positionBoId != null && positionBoId != 0L) {
                    List<String> changeTypeNumbers = positionBoIdToChangeTypeNumberMap.get(positionBoId);
                    if (changeTypeNumbers == null) {
                        changeTypeNumbers = Lists.newArrayListWithExpectedSize(10);
                    }

                    changeTypeNumbers.add(changeTypeNumber);
                    positionBoIdToChangeTypeNumberMap.put(positionBoId, changeTypeNumbers);
                }
            }

            return JSONObject.toJSONString(positionBoIdToChangeTypeNumberMap);
        }
    }

    public static String getThisBillPositionNumbersStr(DynamicObject bill) {
        if (bill == null) {
            return "";
        } else {
            DynamicObjectCollection positionNumberEntryDys = new DynamicObjectCollection();
            positionNumberEntryDys.addAll(bill.getDynamicObjectCollection(PositionBillConstant.NCKD_ENTRYENTITY_ADD_KEY));
            positionNumberEntryDys.addAll(bill.getDynamicObjectCollection(PositionBillConstant.NCKD_ENTRYENTITY_CHANGE_KEY));
            PositionBillSaveHelper helper = PositionBillSaveHelper.getInstance();
            Map<String, List<Long>> newNumberToPositionIdsMap = Maps.newHashMapWithExpectedSize(positionNumberEntryDys.size());

            for(DynamicObject positionEntryDy : positionNumberEntryDys) {
                String suffix = helper.getSuffixFromEntryEntityDyn(positionEntryDy);
                long positionId = 0L;
                String positionNumber = positionEntryDy.getString(helper.spliceTwoStringByUnderLine(suffix, PositionBillConstant.NCKD_NUMBER_KEY));
                if (PositionBillConstant.NCKD_ENTRYENTITY_ADD_KEY.equals(positionEntryDy.getDynamicObjectType().getName())) {
                    positionId = positionEntryDy.getLong(helper.spliceTwoStringByUnderLine(suffix, PositionBillConstant.NCKD_POSITION_KEY));
                } else {
                    DynamicObject positionDy = positionEntryDy.getDynamicObject(helper.spliceTwoStringByUnderLine(suffix, PositionBillConstant.NCKD_POSITION_KEY));
                    if (positionDy != null) {
                        positionId = positionDy.getLong(PositionBillConstant.BOID_KEY);
                    }
                }

                if (HRStringUtils.isNotEmpty(positionNumber)) {
                    List<Long> positionIds = newNumberToPositionIdsMap.computeIfAbsent(positionNumber, (key) -> Lists.newArrayListWithExpectedSize(positionNumberEntryDys.size()));
                    positionIds.add(positionId);
                }
            }

            return JSONObject.toJSONString(newNumberToPositionIdsMap);
        }
    }

    public static String getThisBillPositionNamesStr(DynamicObject bill) {
        if (bill == null) {
            return "";
        } else {
            DynamicObjectCollection positionNumberEntryDys = new DynamicObjectCollection();
            positionNumberEntryDys.addAll(bill.getDynamicObjectCollection(PositionBillConstant.NCKD_ENTRYENTITY_ADD_KEY));
            positionNumberEntryDys.addAll(bill.getDynamicObjectCollection(PositionBillConstant.NCKD_ENTRYENTITY_CHANGE_KEY));
            PositionBillSaveHelper helper = PositionBillSaveHelper.getInstance();
            Map<String, Map<String, ILocaleString>> adminOrgBoIdToSiblingNameMap = Maps.newHashMapWithExpectedSize(positionNumberEntryDys.size());

            for(DynamicObject positionEntryDy : positionNumberEntryDys) {
                String suffix = helper.getSuffixFromEntryEntityDyn(positionEntryDy);
                long positionId = 0L;
                DynamicObject adminOrgDy = positionEntryDy.getDynamicObject(helper.spliceTwoStringByUnderLine(suffix, PositionBillConstant.NCKD_ADMINORG));
                if (HRStringUtils.equals(PositionChangeTypeEnum.ADD.getTag(PositionBillConstant.NCKD_ENTRYENTITYUNDERLINE_KEY) , positionEntryDy.getDynamicObjectType().getName())) {
                    positionId = positionEntryDy.getLong(helper.spliceTwoStringByUnderLine(suffix, PositionBillConstant.NCKD_POSITION_KEY));
                } else {
                    DynamicObject positionDy = positionEntryDy.getDynamicObject(helper.spliceTwoStringByUnderLine(suffix, PositionBillConstant.NCKD_POSITION_KEY));
                    if (positionDy != null) {
                        positionId = positionDy.getLong(PositionBillConstant.BOID_KEY);
                    }
                }

                if (adminOrgDy != null) {
                    long boId = adminOrgDy.getLong(PositionBillConstant.BOID_KEY);
                    Map<String, ILocaleString> siblingNameMap = adminOrgBoIdToSiblingNameMap.get(String.valueOf(boId));
                    if (siblingNameMap == null) {
                        siblingNameMap = Maps.newHashMapWithExpectedSize(16);
                    }

                    siblingNameMap.put(String.valueOf(positionId), positionEntryDy.getLocaleString(helper.spliceTwoStringByUnderLine(suffix, PositionBillConstant.NCKD_NAME_KEY)));
                    adminOrgBoIdToSiblingNameMap.put(String.valueOf(boId), siblingNameMap);
                }
            }

            return JSONObject.toJSONString(adminOrgBoIdToSiblingNameMap);
        }
    }

    /**
     * @param operationKey
     * @param positionDys
     * @param option
     * @return
     */
    public static OperationResult executeOperateOnlyValidate(String operationKey, DynamicObject[] positionDys, OperateOption option) {
        OperateOption operateOption = option;
        if (option == null) {
            operateOption = OperateOption.create();
        }

        operateOption.setVariableValue(OperateOptionConst.ISHASRIGHT, Boolean.TRUE.toString());
        operateOption.setVariableValue(OperateOptionConst.ONLY_VALIDATE, Boolean.TRUE.toString());

        try {
            return OperationServiceHelper.executeOperate(operationKey, PositionBillConstant.HBPM_POSITIONHR, positionDys, operateOption);
        } catch (Exception ex) {
            log.error("executeOperate  error", ex);
            throw ex;
        }
    }

}
