Ver Fonte

商旅对账需求
1.新增特殊人员配置功能,配置的人员按配置分配部门
2.调整获取工作日历逻辑,所属公司没有配置工作日历则继续往上找
3.
个人额度
1.调整人员岗位职级备份表逻辑,每次执行都更新新、旧职级岗位
2.新增岗位、职级同步时,关闭旧职级、岗位下的个人额度逻辑
3.新增人员额度按照费用项目、同步类型、当月额度等逻辑,判断额度同步月份
4.新增新增人员创建差旅补助级别功能

lisheng há 1 dia atrás
pai
commit
a68e60a327

+ 13 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/constant/travelcheck/SecretarySpeSettingConstant.java

@@ -0,0 +1,13 @@
+package nckd.jimin.jyyy.fi.common.constant.travelcheck;
+
+import nckd.jimin.jyyy.fi.common.constant.BillConstant;
+
+public interface SecretarySpeSettingConstant extends BillConstant {
+    String ENTITYID = "nckd_secretary_spesetting";
+
+    String NCKD_USER = "nckd_user";
+
+    String NCKD_ORG_BELONG = "nckd_org_belong";
+
+    String NCKD_ORG_CHECK = "nckd_org_check";
+}

+ 18 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/util/CommonUtils.java

@@ -110,6 +110,24 @@ public class CommonUtils {
         return calendar.get(filed);
     }
 
+    public static Date getFirstDayOfNextMonth(Date date) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+
+        // 增加一个月
+        calendar.add(Calendar.MONTH, 1);
+
+        // 设置为该月的第一天
+        calendar.set(Calendar.DAY_OF_MONTH, 1);
+
+        // 将时分秒毫秒设置为0,确保是当天的开始
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+
+        return calendar.getTime();
+    }
     public static DynamicObject getUserByHrPersonId(Object hrPersonId){
         DynamicObject hrPersonInfo = QueryServiceHelper.queryOne("hrpi_person", "number", new QFilter("id", QCP.equals, hrPersonId).toArray());
         if(hrPersonInfo == null){

+ 71 - 3
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/form/travelcheck/FinanDraftConfirmEdit.java

@@ -182,13 +182,11 @@ public class FinanDraftConfirmEdit extends AbstractBillPlugIn {
     }
 
     protected void createDetailEntry(DynamicObjectCollection detailEntryCol,Long secreataryId, List<Long> deptIds) {
-        // 查询部门下、待确认的商旅财务对账底稿数据
 
         Set<Long> draftIds = QueryServiceHelper.query(TravelFinanDraftConstant.ENTITYID, TravelFinanDraftConstant.ID, new QFilter[]{
                 new QFilter(TravelFinanDraftConstant.NCKD_DEPT, QFilter.in, deptIds),
                 new QFilter(TravelFinanDraftConstant.NCKD_CONFIRMSTATUS, QFilter.equals, TravelFinanDraftConstant.ConfirmStatus.TOCONFIRM),
         }).stream().map(r -> r.getLong(TravelFinanDraftConstant.ID)).collect(Collectors.toSet());
-
         if(CollectionUtils.isEmpty(draftIds)){
             // 没有待确认商旅财务对账底稿数据,不创建
             return;
@@ -204,9 +202,65 @@ public class FinanDraftConfirmEdit extends AbstractBillPlugIn {
 
         DynamicObjectCollection draftEntryCol = detailEntry.getDynamicObjectCollection(FinanceBillConfirmConstant.DRAFTENTRY.ENTITYID);
         DynamicObject[] draftArray = BusinessDataServiceHelper.load(draftIds.toArray(), EntityMetadataCache.getDataEntityType(TravelFinanDraftConstant.ENTITYID_F7));
-        Arrays.stream(draftArray).forEach(draftInfo -> draftEntryCol.addNew().set(FinanceBillConfirmConstant.DRAFTENTRY.NCKD_TRAVELFINANDRAFT, draftInfo));
+
+        List<DynamicObject> draftList = Arrays.asList(draftArray);
+        // 移除秘书管辖部门中,配置了特殊人员的出差人数据
+        removeSecretarySetting(draftList,deptIds);
+        // 添加秘书管辖部门中,配置了特殊人员的出差人数据
+        addSecretarySetting(draftList,deptIds);
+        draftList.forEach(draftInfo -> draftEntryCol.addNew().set(FinanceBillConfirmConstant.DRAFTENTRY.NCKD_TRAVELFINANDRAFT, draftInfo));
+    }
+
+    protected void removeSecretarySetting(List<DynamicObject> draftList,List<Long> deptIds) {
+        // 查询特殊秘书特殊人员配置
+        List<DynamicObject> secretarySpeSettingCol = getSecretarySpeSettingCol();
+        // 移除配置了部门特殊人员配置的底稿
+        Map<Object, DynamicObject> applierBelongOrgMap = secretarySpeSettingCol.stream()
+                .filter(r -> deptIds.contains(r.getDynamicObject(SecretarySpeSettingConstant.NCKD_ORG_BELONG).getPkValue()))
+                .collect(Collectors.toMap(r -> r.getDynamicObject(SecretarySpeSettingConstant.NCKD_USER).getPkValue(),
+                        r -> r, (v1, v2) -> v1));
+
+
+        Iterator<DynamicObject> iterator = draftList.iterator();
+        while (iterator.hasNext()){
+            DynamicObject draftInfo = iterator.next();
+            Object applierId = draftInfo.getDynamicObject(TravelFinanDraftConstant.NCKD_TRIPREQBILL).getDynamicObject(TripReqBillConstant.APPLIER).getPkValue();
+            if(applierBelongOrgMap.containsKey(applierId)){
+                DynamicObject speSetting = applierBelongOrgMap.get(applierId);
+                if(speSetting != null && draftInfo.getDynamicObject(TravelFinanDraftConstant.NCKD_DEPT).getPkValue()
+                        .equals(speSetting.getDynamicObject(SecretarySpeSettingConstant.NCKD_ORG_BELONG).getPkValue())){
+                    // 移除
+                    iterator.remove();
+                }
+            }
+        }
+    }
+
+    protected void addSecretarySetting(List<DynamicObject> draftList,List<Long> deptIds) {
+        List<DynamicObject> secretarySpeSettingCol = getSecretarySpeSettingCol();
+
+        Map<Object, DynamicObject> applierCheckOrgMap = secretarySpeSettingCol.stream()
+                .filter(r -> deptIds.contains(r.getDynamicObject(SecretarySpeSettingConstant.NCKD_ORG_CHECK).getPkValue()))
+                .collect(Collectors.toMap(r -> r.getDynamicObject(SecretarySpeSettingConstant.NCKD_USER).getPkValue(),
+                        r -> r, (v1, v2) -> v1));
+        Set<Long> otherDeptApplierData = new HashSet<>();
+        applierCheckOrgMap.forEach( (applierId, secretarySpeSetting) -> otherDeptApplierData.addAll(
+                getDeptApplierData(applierId, secretarySpeSetting.getDynamicObject(SecretarySpeSettingConstant.NCKD_ORG_CHECK).getPkValue())
+        ));
+        DynamicObject[] draftArray = BusinessDataServiceHelper.load(otherDeptApplierData.toArray(), EntityMetadataCache.getDataEntityType(TravelFinanDraftConstant.ENTITYID_F7));
+        draftList.addAll(Arrays.asList(draftArray));
+
     }
 
+    protected Set<Long> getDeptApplierData(Object applierId , Object deptId){
+        return QueryServiceHelper.query(TravelFinanDraftConstant.ENTITYID, TravelFinanDraftConstant.ID, new QFilter[]{
+                new QFilter(TravelFinanDraftConstant.NCKD_DEPT, QFilter.equals, deptId),
+                new QFilter(String.join(",", TravelFinanDraftConstant.NCKD_TRIPREQBILL,TripReqBillConstant.APPLIER), QFilter.equals, applierId),
+                new QFilter(TravelFinanDraftConstant.NCKD_CONFIRMSTATUS, QFilter.equals, TravelFinanDraftConstant.ConfirmStatus.TOCONFIRM),
+        }).stream().map(r -> r.getLong(TravelFinanDraftConstant.ID)).collect(Collectors.toSet());
+    }
+
+
     protected Map<Long, List<Long>> getDepSecretaryOrgMap() {
         DynamicObject[] depSecretaryArray = BusinessDataServiceHelper.load(DepSecretaryConstant.ENTITYID,
                 String.join(",", DepSecretaryConstant.NCKD_SECRETARY, DepSecretaryConstant.ENTITYID_ENTRY, DepSecretaryConstant.NCKD_ORG), new QFilter[]{
@@ -218,9 +272,23 @@ public class FinanDraftConfirmEdit extends AbstractBillPlugIn {
         return Arrays.stream(depSecretaryArray).collect(Collectors.toMap(
                 r -> r.getDynamicObject(DepSecretaryConstant.NCKD_SECRETARY).getLong(DepSecretaryConstant.ID),
                 r -> r.getDynamicObjectCollection(DepSecretaryConstant.ENTITYID_ENTRY).stream()
+
+
                         .map(entry -> entry.getDynamicObject(DepSecretaryConstant.NCKD_ORG).getLong(DepSecretaryConstant.ID))
                         .collect(Collectors.toList()),
                 (a, b) -> a));
 
     }
+
+    protected List<DynamicObject> getSecretarySpeSettingCol() {
+        List<Long> idList = QueryServiceHelper.query(SecretarySpeSettingConstant.ENTITYID, SecretarySpeSettingConstant.ID, new QFilter[]{
+                QFilter.isNotNull(SecretarySpeSettingConstant.NCKD_ORG_CHECK),
+                QFilter.isNotNull(SecretarySpeSettingConstant.NCKD_ORG_BELONG),
+                new QFilter(SecretarySpeSettingConstant.KEY_STATUS, QFilter.equals, "C"),
+                new QFilter(SecretarySpeSettingConstant.KEY_ENABLE, QFilter.equals, Boolean.TRUE)
+        }).stream().map(r -> r.getLong(SecretarySpeSettingConstant.ID)).collect(Collectors.toList());
+        return Arrays.stream(BusinessDataServiceHelper.load(idList.toArray(), EntityMetadataCache.getDataEntityType(SecretarySpeSettingConstant.ENTITYID)))
+                .filter(r -> r.getDynamicObject(SecretarySpeSettingConstant.NCKD_ORG_CHECK).getPkValue().equals(r.getDynamicObject(SecretarySpeSettingConstant.NCKD_ORG_BELONG).getPkValue()))
+                .collect(Collectors.toList());
+    }
 }

+ 3 - 3
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/form/travelcheck/PersonPositionListProvider.java

@@ -20,16 +20,16 @@ public class PersonPositionListProvider extends ListDataProvider {
         DynamicObjectCollection data = super.getData(start, limit);
 
         List<String> applierNameList = data.stream()
-                .map(dyx -> dyx.getString("nckd_tripreqbill.applier.number"))
+                .map(dyx -> dyx.getString("nckd_tripreqbill.applier.name"))
                 .collect(Collectors.toList());
 
-        DynamicObjectCollection queryUserCol = QueryServiceHelper.query("bos_user", "number,entryentity.dpt.fullname", new QFilter[]{
+        DynamicObjectCollection queryUserCol = QueryServiceHelper.query("bos_user", "number,entryentity.orgstructure.fullname", new QFilter[]{
                 new QFilter("number", QCP.in, applierNameList),
                 new QFilter("ispartjob", QCP.equals, Boolean.FALSE),
         });
         // 查询人员及主岗部门映射
         Map<String, String> userDeptMap = queryUserCol.stream()
-                .collect(Collectors.toMap(dyx -> dyx.getString("number"), dyx -> dyx.getString("entryentity.dpt.fullname"), (k1, k2) -> k1));
+                .collect(Collectors.toMap(dyx -> dyx.getString("number"), dyx -> dyx.getString("entryentity.orgstructure.fullname"), (k1, k2) -> k1));
 
 
         // 查询当前生效的人员岗位信息

+ 2 - 2
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/form/travelcheck/TravelFinanDraftList.java

@@ -42,7 +42,7 @@ public class TravelFinanDraftList extends AbstractListPlugin {
     @Override
     public void beforeCreateListDataProvider(BeforeCreateListDataProviderArgs args) {
         super.beforeCreateListDataProvider(args);
-        //args.setListDataProvider(new PersonPositionListProvider());
+        args.setListDataProvider(new PersonPositionListProvider());
     }
 
     @Override
@@ -54,7 +54,7 @@ public class TravelFinanDraftList extends AbstractListPlugin {
             String period = CommonUtils.parsePeriod(new Date());
             // 判断当前期间是否已经存在
             if(ORM.create().exists(FinanceBillConfirmConstant.ENTITYID, new QFilter(FinanceBillConfirmConstant.NCKD_CHECKMONTH, QCP.equals, period).toArray())){
-                this.getView().showTipNotification(String.format("期间[%s]已经存在结账确认单,请勿重复创建!", period));
+                this.getView().showTipNotification(String.format("期间[%s]已经存在商旅确认单,请勿重复创建!", period));
                 args.setCancel(true);
                 return;
             }

+ 167 - 21
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/Helper/PersonReimQuotaHelper.java

@@ -49,15 +49,9 @@ public class PersonReimQuotaHelper {
      * @param quotaVO
      * @return
      */
-    public void createPersonReimAmount(PersonReimQuotaVO  quotaVO){
-        Calendar calendar = Calendar.getInstance();
-        String year = String.valueOf(calendar.get(Calendar.YEAR));
-        int month = calendar.get(Calendar.MONTH) + 1;
-        // 费用标准同步的下个月生效
-        if(ReimAmountSourceTypeEnum.STANDARDCHANGE.equals(quotaVO.getSourcetype())){
-            month = month+1;
-        }
+    public DynamicObject createPersonReimAmount(PersonReimQuotaVO  quotaVO){
 
+        initQuotaYearAndMonth(quotaVO);
         // 通过[公司、费用类型、人员、币别、年度]判断是否已经创建个人额度表
         DynamicObject queryPersonAmount = QueryServiceHelper.queryOne(BillTypeConstants.ER_REIMBURSEAMOUNT, "id,nckd_sourcetype", new QFilter[]{
                 new QFilter("company.id", QCP.equals, quotaVO.getCompanyId()),
@@ -65,7 +59,7 @@ public class PersonReimQuotaHelper {
                 new QFilter("expenseitem.id", QCP.equals, quotaVO.getExpenseItemId()),
                 new QFilter("currency.id", QCP.equals, quotaVO.getCurrencyId()),
                 new QFilter("auditstatus", QCP.equals, "1"),
-                new QFilter("dateyear", QCP.equals, year)
+                new QFilter("dateyear", QCP.equals, String.valueOf(quotaVO.getYear()))
         });
 
         DynamicObject personAmountBill = BusinessDataServiceHelper.newDynamicObject(BillTypeConstants.ER_REIMBURSEAMOUNT);
@@ -74,11 +68,11 @@ public class PersonReimQuotaHelper {
 
             if(ReimAmountSourceTypeEnum.ER_REIMCTL_NEW.getKey().equals(queryPersonAmount.getString("nckd_sourcetype"))){
                 BizLog.log(String.format("个人额度表【%s】已存在,且为手工新增,不予处理!", queryPersonAmount.getString("id")));
-                return;
+                return null;
             }
-            boolean isNeedUpdate = copyModifyPersonReim(personAmountBill, queryPersonAmount.getLong("id"), quotaVO.getAmount(), month);
+            boolean isNeedUpdate = copyModifyPersonReim(personAmountBill, queryPersonAmount.getLong("id"), quotaVO.getAmount(), quotaVO.getMonth());
             if(!isNeedUpdate){
-                return;
+                return null;
             }
 
         }else{
@@ -104,7 +98,90 @@ public class PersonReimQuotaHelper {
         if(!approveOp.isSuccess() || approveOp.getSuccessPkIds().size() == 0){
             throw new KDBizException(CommonUtils.getOperationResultErrorInfos(approveOp));
         }
+        return personAmountBill;
+    }
 
+    protected DynamicObject getHrPersonInfo(Object userId){
+        DynamicObject userInfo = BusinessDataServiceHelper.loadSingleFromCache(userId, "bos_user","number");
+        // 查询人员的信息
+        return QueryServiceHelper.queryOne(BillTypeConstants.HRPI_EMPPOSORGREL, "person.id,bsed", new QFilter[]{
+                new QFilter("businessstatus", QCP.equals, "1"),
+                new QFilter("iscurrentversion", QCP.equals, "1"),
+                new QFilter("datastatus", QCP.equals, "1"),
+                new QFilter("isprimary", QCP.equals, "1"),
+                new QFilter("person.number", QCP.equals, userInfo.getString("number"))
+        });
+    }
+
+    protected void initQuotaYearAndMonth(PersonReimQuotaVO  quotaVO){
+        Calendar calendar = Calendar.getInstance();
+        Date quotaDate = new Date();
+        calendar.setTime(quotaDate);
+        // 来源费用标准变更,次月生效
+        if(ReimAmountSourceTypeEnum.STANDARDCHANGE.equals(quotaVO.getSourcetype())){
+            quotaDate = CommonUtils.getFirstDayOfNextMonth(quotaDate);
+            // 来源职级和岗位变动的,当月生效
+        }else if(ReimAmountSourceTypeEnum.JOBLEVELCHANGE.equals(quotaVO.getSourcetype())
+                || ReimAmountSourceTypeEnum.POSITIONCHANGE.equals(quotaVO.getSourcetype())){
+            // 查询当年的额度
+            DynamicObject queryPersonAmount = QueryServiceHelper.queryOne(BillTypeConstants.ER_REIMBURSEAMOUNT, "id,nckd_sourcetype", new QFilter[]{
+                    new QFilter("company.id", QCP.equals, quotaVO.getCompanyId()),
+                    new QFilter("employee.id", QCP.equals, quotaVO.getUserId()),
+                    new QFilter("expenseitem.id", QCP.equals, quotaVO.getExpenseItemId()),
+                    new QFilter("currency.id", QCP.equals, quotaVO.getCurrencyId()),
+                    new QFilter("auditstatus", QCP.equals, "1"),
+                    new QFilter("dateyear", QCP.equals, String.valueOf(calendar.get(Calendar.YEAR)))
+            });
+            if(queryPersonAmount != null){
+                DynamicObject personAmountBill = BusinessDataServiceHelper.loadSingle(queryPersonAmount.get("id"), BillTypeConstants.ER_REIMBURSEAMOUNT);
+                // 获取当前月份的
+                BigDecimal curAmount = personAmountBill.getBigDecimal("month" + (calendar.get(Calendar.MONTH)+1));
+                // 更新的额度如果小于当前额度,则次月生成
+                if(quotaVO.getAmount().compareTo(curAmount) < 0){
+                    quotaDate = CommonUtils.getFirstDayOfNextMonth(quotaDate);
+                }
+            }
+            // 来源公司的变动,入职生效日期为额度创建时间
+        } else if(ReimAmountSourceTypeEnum.COMPANYCHANGE.equals(quotaVO.getSourcetype())){
+            DynamicObject personPositionInfo = getHrPersonInfo(quotaVO.getUserId());
+            quotaDate = personPositionInfo.getDate("bsed");
+            DynamicObject expenseItem = QueryServiceHelper.queryOne("er_expenseitemedit", "nckd_syncquota_type", new QFilter("id", QCP.equals, quotaVO.getExpenseItemId()).toArray());
+            if("next".equals(expenseItem.getString("nckd_syncquota_type"))){
+                quotaDate = CommonUtils.getFirstDayOfNextMonth(quotaDate);
+            }
+        }
+        calendar.setTime(quotaDate);
+        quotaVO.setYear(calendar.get(Calendar.YEAR));
+        quotaVO.setMonth(calendar.get(Calendar.MONTH) + 1);
+    }
+    protected int getStartMonth(PersonReimQuotaVO  quotaVO , DynamicObject personAmountBill, DynamicObject personPositionInfo) {
+        Calendar calendar = Calendar.getInstance();
+        // 默认当前月
+        int month = calendar.get(Calendar.MONTH) + 1;
+        ReimAmountSourceTypeEnum sourcetype = quotaVO.getSourcetype();
+        // 来源费用标准变更,次月生效
+        if(ReimAmountSourceTypeEnum.STANDARDCHANGE.equals(sourcetype)){
+            month = month+1;
+        // 来源职级和岗位变动的,当月生效
+        }else if(ReimAmountSourceTypeEnum.JOBLEVELCHANGE.equals(sourcetype) || ReimAmountSourceTypeEnum.POSITIONCHANGE.equals(sourcetype)){
+            // 获取当前月份的
+            BigDecimal curAmount = personAmountBill.getBigDecimal("month" + month);
+            // 更新的额度如果小于当前额度,则次月生成
+            if(quotaVO.getAmount().compareTo(curAmount) < 0){
+                month = month+1;
+            }
+        // 来源公司的变动,入职生效日期为额度创建时间
+        } else if(ReimAmountSourceTypeEnum.COMPANYCHANGE.equals(sourcetype)){
+            Date bsedDate = personPositionInfo.getDate("bsed");
+            Calendar bsedCalendar = Calendar.getInstance();
+            bsedCalendar.setTime(bsedDate);
+            month = calendar.get(Calendar.MONTH) + 1;
+            DynamicObject expenseItem = QueryServiceHelper.queryOne("er_expenseitemedit", "nckd_syncquota_type", new QFilter("id", QCP.equals, quotaVO.getExpenseItemId()).toArray());
+            if("next".equals(expenseItem.getString("nckd_syncquota_type"))){
+                month = month+1;
+            }
+        }
+        return month;
     }
 
     protected boolean copyModifyPersonReim(DynamicObject personAmountBill, Long copyPersonAmountBillId,BigDecimal amount, int startMonth) {
@@ -133,8 +210,7 @@ public class PersonReimQuotaHelper {
     }
 
     protected void createNewPersonReimAmount(DynamicObject personAmountBill , PersonReimQuotaVO  quotaVO){
-        Calendar calendar = Calendar.getInstance();
-        String year = String.valueOf(calendar.get(Calendar.YEAR));
+
         DynamicObject userInfo = BusinessDataServiceHelper.loadSingleFromCache(quotaVO.getUserId(), "bos_user");
         DynamicObject companyInfo = BusinessDataServiceHelper.loadSingleFromCache(quotaVO.getCompanyId(), "bos_org");
         DynamicObject expenseItemInfo = BusinessDataServiceHelper.loadSingleFromCache(quotaVO.getExpenseItemId(), "er_expenseitemedit");
@@ -143,7 +219,7 @@ public class PersonReimQuotaHelper {
         personAmountBill.set("company", companyInfo);
         personAmountBill.set("expenseitem", expenseItemInfo);
         personAmountBill.set("currency", currencyInfo);
-        personAmountBill.set("dateyear", String.valueOf(year));
+        personAmountBill.set("dateyear", String.valueOf(quotaVO.getYear()));
         personAmountBill.set("costcompany", companyInfo);
         personAmountBill.set("amounttype", "1");
         personAmountBill.set("employee", userInfo);
@@ -153,8 +229,8 @@ public class PersonReimQuotaHelper {
         personAmountBill.set("modifytime", new Date());
         personAmountBill.set("creator", RequestContext.get().getCurrUserId());
         personAmountBill.set("modifier", RequestContext.get().getCurrUserId());
-        personAmountBill.set("wbsrcbilltype", "er_reimctl_new");
-        setPersonAmountData(personAmountBill,quotaVO.getAmount(),1);
+        personAmountBill.set("wbsrcbilltype", "er_reimctl_modify");
+        setPersonAmountData(personAmountBill,quotaVO.getAmount(),quotaVO.getMonth());
     }
 
     public void syncReimLever(Long userId ,Long companyId,Long jobId){
@@ -191,7 +267,11 @@ public class PersonReimQuotaHelper {
         leverFilterList.add(BaseDataServiceHelper.getBaseDataFilter("er_reimburselevel", companyId));
         leverFilterList.add(new QFilter("enable", QCP.equals,"1"));
         leverFilterList.add(new QFilter("nckd_joblevelhr.fbasedataid", QCP.equals,jobId));
-        return QueryServiceHelper.queryOne("er_reimburselevel", "id", leverFilterList.toArray(new QFilter[0]));
+        DynamicObject queryOne = QueryServiceHelper.queryOne("er_reimburselevel", "id", leverFilterList.toArray(new QFilter[0]));
+        if(queryOne != null){
+            return BusinessDataServiceHelper.loadSingleFromCache(queryOne.getLong("id"), "er_reimburselevel");
+        }
+        return null;
     }
 
     public DynamicObject getDefultReimLever() {
@@ -221,6 +301,10 @@ public class PersonReimQuotaHelper {
 
     public void createQuotaJobleverChange(DynamicObject jobBakInfo, Map<Long, Map<Long, List<DynamicObject>>> limitRelasetExpenseItemMap, ReimAmountSourceTypeEnum sourcetype){
         DynamicObject joblever_new = jobBakInfo.getDynamicObject(JobPositionBakBillConstant.KEY_NCKD_JOBLEVEL_NEW);
+        DynamicObject joblever_old = jobBakInfo.getDynamicObject(JobPositionBakBillConstant.KEY_NCKD_JOBLEVEL_OLD);
+
+        List<DynamicObject> createQuotaList = new ArrayList<>();
+        // 创建新职级下的个人额度
         for(Map.Entry<Long, Map<Long, List<DynamicObject>>> currencyRow : limitRelasetExpenseItemMap.entrySet()){
             // 币别ID
             Long currencyId = currencyRow.getKey();
@@ -230,7 +314,6 @@ public class PersonReimQuotaHelper {
             for(Map.Entry<Long, List<DynamicObject>> expenseItemRow : expenseItemGroupMap.entrySet()){
                 Long expenseItemId = expenseItemRow.getKey();
                 List<DynamicObject> limitRelasetList = expenseItemRow.getValue();
-
                 Optional<DynamicObject> findJobleverOp = limitRelasetList.stream().filter(r -> joblever_new.getPkValue()
                         .equals(r.getDynamicObject(LimitRelasetConstant.KEY_NCKD_CLASSFIELD_JOBPOS).getPkValue())).findFirst();
                 if(findJobleverOp.isPresent()){
@@ -244,15 +327,47 @@ public class PersonReimQuotaHelper {
                             Optional.ofNullable(sourcetype).orElse(ReimAmountSourceTypeEnum.JOBLEVELCHANGE),
                             "",
                             findJobleverOp.get().getString(LimitRelasetConstant.ID));
-                    createPersonReimAmount(personReimQuotaVO);
+                    createQuotaList.add(createPersonReimAmount(personReimQuotaVO));
+                }
+
+            }
+        }
+
+        if(joblever_old != null){
+            List<Object> createReimList = createQuotaList.stream().filter(r -> !Objects.isNull(r)).map(r -> r.getPkValue()).collect(Collectors.toList());
+            // 作废旧职级下,非新职级创建的个人额度数据
+            for(Map.Entry<Long, Map<Long, List<DynamicObject>>> currencyRow : limitRelasetExpenseItemMap.entrySet()) {
+                // 币别ID
+                Long currencyId = currencyRow.getKey();
+                // 费用项目分组
+                Map<Long, List<DynamicObject>> expenseItemGroupMap = currencyRow.getValue();
+                for(Map.Entry<Long, List<DynamicObject>> expenseItemRow : expenseItemGroupMap.entrySet()){
+                    Long expenseItemId = expenseItemRow.getKey();
+                    List<DynamicObject> limitRelasetList = expenseItemRow.getValue();
+                    Optional<DynamicObject> findJobleverOp = limitRelasetList.stream().filter(r -> joblever_old.getPkValue()
+                            .equals(r.getDynamicObject(LimitRelasetConstant.KEY_NCKD_CLASSFIELD_JOBPOS).getPkValue())).findFirst();
+                    if(findJobleverOp.isPresent()){
+                        doInvalidPersonReim(new QFilter[]{
+                                new QFilter("company.id", QCP.equals,jobBakInfo.getDynamicObject(JobPositionBakBillConstant.KEY_NCKD_ORG_NEW).getLong(JobPositionBakBillConstant.ID)),
+                                new QFilter("employee.id", QCP.equals, jobBakInfo.getDynamicObject(JobPositionBakBillConstant.KEY_NCKD_USER).getLong(JobPositionBakBillConstant.ID)),
+                                new QFilter("expenseitem.id", QCP.equals, expenseItemId),
+                                new QFilter("currency.id", QCP.equals, currencyId),
+                                new QFilter("auditstatus", QCP.equals, "1"),
+                                new QFilter("id", QCP.not_in, createReimList)
+                        });
+                    }
                 }
             }
         }
+
     }
 
     public void createQuotaPositionChange(DynamicObject jobBakInfo,Map<Long, Map<Long, List<DynamicObject>>> limitRelasetExpenseItemMap,ReimAmountSourceTypeEnum sourcetype){
         DynamicObject joblever_new = jobBakInfo.getDynamicObject(JobPositionBakBillConstant.KEY_NCKD_JOBLEVEL_NEW);
         DynamicObject position_new = jobBakInfo.getDynamicObject(JobPositionBakBillConstant.KEY_NCKD_POSITION_NEW);
+        DynamicObject position_old = jobBakInfo.getDynamicObject(JobPositionBakBillConstant.KEY_NCKD_POSITION_OLD);
+        List<DynamicObject> createQuotaList = new ArrayList<>();
+        // 创建新岗位下的额度
         for(Map.Entry<Long, Map<Long, List<DynamicObject>>> currencyRow : limitRelasetExpenseItemMap.entrySet()){
             // 币别ID
             Long currencyId = currencyRow.getKey();
@@ -280,7 +395,38 @@ public class PersonReimQuotaHelper {
                             Optional.ofNullable(sourcetype).orElse(ReimAmountSourceTypeEnum.POSITIONCHANGE),
                             "",
                             findPositionOp.get().getString(LimitRelasetConstant.ID));
-                    createPersonReimAmount(personReimQuotaVO);
+                    createQuotaList.add(createPersonReimAmount(personReimQuotaVO));
+                }
+            }
+        }
+        if(position_old != null){
+            List<Object> createQuotaIdList = createQuotaList.stream().filter(r -> !Objects.isNull(r)).map(r -> r.getPkValue()).collect(Collectors.toList());
+            // 作废旧岗位下的额度
+            for(Map.Entry<Long, Map<Long, List<DynamicObject>>> currencyRow : limitRelasetExpenseItemMap.entrySet()) {
+                // 币别ID
+                Long currencyId = currencyRow.getKey();
+                // 费用项目分组
+                Map<Long, List<DynamicObject>> expenseItemGroupMap = currencyRow.getValue();
+
+                for (Map.Entry<Long, List<DynamicObject>> expenseItemRow : expenseItemGroupMap.entrySet()) {
+                    Long expenseItemId = expenseItemRow.getKey();
+                    List<DynamicObject> limitRelasetList = expenseItemRow.getValue();
+
+                    Optional<DynamicObject> findJobleverOp = limitRelasetList.stream().filter(r -> joblever_new.getPkValue()
+                            .equals(r.getDynamicObject(LimitRelasetConstant.KEY_NCKD_CLASSFIELD_JOBPOS).getPkValue())).findFirst();
+                    Optional<DynamicObject> findPositionOp = limitRelasetList.stream().filter(r -> position_old.getPkValue()
+                            .equals(r.getDynamicObject(LimitRelasetConstant.KEY_NCKD_CLASSFIELD_JOBPOS).getPkValue())).findFirst();
+                    // 人员岗位发生变化时,如果存在职级的费用标准,则不需要作废
+                    if (!findJobleverOp.isPresent() && findPositionOp.isPresent()) {
+                        doInvalidPersonReim(new QFilter[]{
+                                new QFilter("company.id", QCP.equals,jobBakInfo.getDynamicObject(JobPositionBakBillConstant.KEY_NCKD_ORG_NEW).getLong(JobPositionBakBillConstant.ID)),
+                                new QFilter("employee.id", QCP.equals, jobBakInfo.getDynamicObject(JobPositionBakBillConstant.KEY_NCKD_USER).getLong(JobPositionBakBillConstant.ID)),
+                                new QFilter("expenseitem.id", QCP.equals, expenseItemId),
+                                new QFilter("currency.id", QCP.equals, currencyId),
+                                new QFilter("auditstatus", QCP.equals, "1"),
+                                new QFilter("id",QCP.not_in,createQuotaIdList)
+                        });
+                    }
                 }
             }
         }

+ 20 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/Helper/PersonReimQuotaVO.java

@@ -43,6 +43,10 @@ public class PersonReimQuotaVO {
 
     private String limitRelasetId;
 
+    private int year ;
+
+    private int month ;
+
     public PersonReimQuotaVO(Long userId, Long companyId, Long expenseItemId, Long currencyId, BigDecimal amount, ReimAmountSourceTypeEnum sourcetype) {
         this.userId = userId;
         this.companyId = companyId;
@@ -136,4 +140,20 @@ public class PersonReimQuotaVO {
     public void setLimitRelasetId(String limitRelasetId) {
         this.limitRelasetId = limitRelasetId;
     }
+
+    public int getYear() {
+        return year;
+    }
+
+    public void setYear(int year) {
+        this.year = year;
+    }
+
+    public int getMonth() {
+        return month;
+    }
+
+    public void setMonth(int month) {
+        this.month = month;
+    }
 }

+ 39 - 2
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/travelcheck/FinanDraftConfirmOp.java

@@ -1,7 +1,21 @@
 package nckd.jimin.jyyy.fi.plugin.operate.travelcheck;
 
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.entity.EntityMetadataCache;
 import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
 import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import nckd.jimin.jyyy.fi.common.constant.travelcheck.FinanceBillConfirmConstant;
+import nckd.jimin.jyyy.fi.common.constant.travelcheck.TravelFinanDraftConstant;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
 
 public class FinanDraftConfirmOp extends AbstractOperationServicePlugIn {
 
@@ -9,13 +23,36 @@ public class FinanDraftConfirmOp extends AbstractOperationServicePlugIn {
     public void beginOperationTransaction(BeginOperationTransactionArgs e) {
         super.beginOperationTransaction(e);
         String operationKey = e.getOperationKey();
+
+        DynamicObject[] dataEntities = e.getDataEntities();
+        List<Object> idList = Arrays.stream(dataEntities).map(dataEntity -> dataEntity.getPkValue()).collect(Collectors.toList());
+        DynamicObject[] billArray = BusinessDataServiceHelper.load(idList.toArray(), EntityMetadataCache.getDataEntityType(TravelFinanDraftConstant.ENTITYID));
         // 保存或者提交后反写商旅底稿已对账
         if("save".equals(operationKey) || "submit".equals(operationKey)){
-
+            Arrays.stream(billArray).forEach(confirmBill -> writeBackDraft(confirmBill,"20"));
         }
-        //
+        // 删除后更新成待对账
         if("delete".equals(operationKey)){
+            Arrays.stream(billArray).forEach(confirmBill -> writeBackDraft(confirmBill,"10"));
+        }
+    }
+
+    protected void writeBackDraft(DynamicObject confirmBill,String status){
+
+        List<Object> draftIdList = new ArrayList<>();
+        DynamicObjectCollection detailEntryCol = confirmBill.getDynamicObjectCollection(FinanceBillConfirmConstant.DETAILENTITY.ENTITYID);
+        for(DynamicObject detailEntry : detailEntryCol){
+            DynamicObjectCollection draftEntryCol = detailEntry.getDynamicObjectCollection(FinanceBillConfirmConstant.DRAFTENTRY.ENTITYID);
+            for(DynamicObject draftEntry : draftEntryCol){
+                draftIdList.add(draftEntry.getDynamicObject(FinanceBillConfirmConstant.DRAFTENTRY.NCKD_TRAVELFINANDRAFT).getPkValue());
+            }
+        }
 
+        DynamicObject[] draftBillArray = BusinessDataServiceHelper.load(TravelFinanDraftConstant.ENTITYID_F7, TravelFinanDraftConstant.NCKD_CONFIRMSTATUS,
+                new QFilter(TravelFinanDraftConstant.ID, QCP.in, draftIdList).toArray());
+        for(DynamicObject draftBill : draftBillArray){
+            draftBill.set(TravelFinanDraftConstant.NCKD_CONFIRMSTATUS, status);
         }
+        SaveServiceHelper.save(draftBillArray);
     }
 }

+ 8 - 8
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/task/PersonJobPositionBakTask.java

@@ -65,14 +65,14 @@ public class PersonJobPositionBakTask extends AbstractTask implements StopTask {
         DynamicObjectCollection newestBakBillCol = QueryServiceHelper.query(JobPositionBakBillConstant.ENTITYID, JobPositionBakBillConstant.KEY_NCKD_UPDATETIME, QFilter.isNotNull(JobPositionBakBillConstant.ID).toArray(), "nckd_updatetime desc", 1);
         // 是否更新
         boolean isOnlyUpdateNew = false;
-        if(newestBakBillCol != null && newestBakBillCol.size() > 0){
-            Date updateTime = newestBakBillCol.get(0).getDate(JobPositionBakBillConstant.KEY_NCKD_UPDATETIME);
-            if(updateTime != null
-                    && updateTime.getYear() == Calendar.getInstance().get(Calendar.YEAR)
-                    && updateTime.getMonth() == Calendar.getInstance().get(Calendar.MONTH)){
-                isOnlyUpdateNew = true;
-            }
-        }
+//        if(newestBakBillCol != null && newestBakBillCol.size() > 0){
+//            Date updateTime = newestBakBillCol.get(0).getDate(JobPositionBakBillConstant.KEY_NCKD_UPDATETIME);
+//            if(updateTime != null
+//                    && updateTime.getYear() == Calendar.getInstance().get(Calendar.YEAR)
+//                    && updateTime.getMonth() == Calendar.getInstance().get(Calendar.MONTH)){
+//                isOnlyUpdateNew = true;
+//            }
+//        }
 
 
         // 查询当前生效的人员职级信息

+ 56 - 16
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/task/PersonReimLeverSyncTask.java

@@ -1,8 +1,10 @@
 package nckd.jimin.jyyy.fi.task;
 
 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.entity.operate.result.OperationResult;
 import kd.bos.exception.KDException;
 import kd.bos.logging.Log;
 import kd.bos.logging.LogFactory;
@@ -12,13 +14,13 @@ import kd.bos.schedule.api.StopTask;
 import kd.bos.schedule.executor.AbstractTask;
 import kd.bos.servicehelper.BusinessDataServiceHelper;
 import kd.bos.servicehelper.QueryServiceHelper;
+import kd.bos.servicehelper.operation.OperationServiceHelper;
 import kd.bos.servicehelper.operation.SaveServiceHelper;
 import nckd.jimin.jyyy.fi.common.constant.BillTypeConstants;
 import nckd.jimin.jyyy.fi.common.util.CommonUtils;
 import nckd.jimin.jyyy.fi.plugin.operate.Helper.PersonReimQuotaHelper;
 
-import java.util.Map;
-import java.util.Optional;
+import java.util.*;
 import java.util.stream.Collectors;
 
 
@@ -40,7 +42,11 @@ public class PersonReimLeverSyncTask extends AbstractTask implements StopTask {
         log.info("-------- PersonReimLeverSyncTask 启动同步人员报销级别任务 --------");
 
         // 查询所有人员的报销级别设置
-        DynamicObject[] reimburseSettingArray = BusinessDataServiceHelper.load("er_reimbursesetting_rel", "user.id,user.number,reimburselevel.id,company.id", QFilter.isNotNull("user.id").toArray());
+        DynamicObject[] reimburseSettingArray = BusinessDataServiceHelper.load("er_reimbursesetting_rel", "user.id,user.number,reimburselevel.id,company.id",
+                QFilter.isNotNull("user.id").toArray());
+        Map<String, List<DynamicObject>> userReimLeverSettingMap = Arrays.stream(reimburseSettingArray)
+                .filter(r -> r.getDynamicObject("user") != null)
+                .collect(Collectors.groupingBy(r -> r.getString("user.number")));
         // 查询当前生效的人员岗位信息
         DynamicObjectCollection positionCol = QueryServiceHelper.query(BillTypeConstants.HRPI_EMPPOSORGREL, "person.number,company.id", new QFilter[]{
                 new QFilter("businessstatus", QCP.equals, "1"),
@@ -48,7 +54,7 @@ public class PersonReimLeverSyncTask extends AbstractTask implements StopTask {
                 new QFilter("datastatus", QCP.equals, "1"),
                 new QFilter("isprimary", QCP.equals, "1")
         });
-        Map<String, Long> personCompanyMap = positionCol.stream().collect(Collectors.toMap(r -> r.getString("person.number"), r -> r.getLong("company.id"), (k1, k2) -> k1));
+//        Map<String, Long> personCompanyMap = positionCol.stream().collect(Collectors.toMap(r -> r.getString("person.number"), r -> r.getLong("company.id"), (k1, k2) -> k1));
         // 获取所有人员最新的职级
         Map<String, Long> personJobMap = QueryServiceHelper.query(BillTypeConstants.HRPI_EMPJOBREL, "person.number,joblevel.id", new QFilter[]{
                 new QFilter("businessstatus", QCP.equals, "1"),
@@ -59,22 +65,56 @@ public class PersonReimLeverSyncTask extends AbstractTask implements StopTask {
         PersonReimQuotaHelper helper = getPersonReimQuotaHelper();
         // 默认职级
         DynamicObject defultReimLever = helper.getDefultReimLever();
+
         // 通过公司查询共享策略查询报销级别;没有查到就取默认
-        for(DynamicObject reimburseSetting : reimburseSettingArray){
-            String userNumber = reimburseSetting.getString("user.number");
-            Long companyId = reimburseSetting.getLong("company.id");
-            Long personCompanyId = personCompanyMap.get(userNumber);
-            DynamicObject reimLever = null;
-            if(personCompanyId != null && companyId != null && personCompanyId.equals(companyId)) {
-                reimLever = helper.getReimLever(personJobMap.get(userNumber), personCompanyId);
-            }
+        for(DynamicObject personPosition : positionCol){
+            String personNumber = personPosition.getString("person.number");
+            if(personJobMap.containsKey(personNumber)){
+                Long jobId = personJobMap.get(personNumber);
+                Long companyId = personPosition.getLong("company.id");
+                if(companyId != null){
+                    DynamicObject reimLever = null;
+                    if(jobId != null){
+                       reimLever = helper.getReimLever(jobId, companyId);
+                    }
+                    if (reimLever == null) {
+                        reimLever = defultReimLever;
+                    }
+                    DynamicObject reimSettingInfo = null;
+                    // 存在报销级别设置
+                    if(userReimLeverSettingMap.containsKey(personNumber)){
+                        List<DynamicObject> reimLeverSettingCol = userReimLeverSettingMap.get(personNumber);
+                        Optional<DynamicObject> findCompanyOp = reimLeverSettingCol.stream()
+                                .filter(r -> companyId == r.getLong("company.id")).findFirst();
+                        if(findCompanyOp.isPresent()){
+                            reimSettingInfo = findCompanyOp.get();
+                            reimSettingInfo.set("reimburselevel", reimLever.getLong("id"));
+
+                        }
+                    }
+                    if(Objects.isNull(reimSettingInfo)){
+                        DynamicObject userInfo = BusinessDataServiceHelper.loadSingleFromCache("bos_user", new QFilter("number", QCP.equals, personNumber).toArray());
+                        DynamicObject org = BusinessDataServiceHelper.loadSingle(companyId, "bos_org");
+                        reimSettingInfo = BusinessDataServiceHelper.newDynamicObject("er_reimbursesetting_rel");
+                        reimSettingInfo.set("user",userInfo);
+                        reimSettingInfo.set("reimburselevel",reimLever);
+                        reimSettingInfo.set("company",org);
+                    }
+                    SaveServiceHelper.save(new DynamicObject[]{ reimSettingInfo });
 
-            if (reimLever == null) {
-                reimLever = defultReimLever;
+                    // 查看状态,调用已审核
+                    DynamicObject reimBurseSetting = BusinessDataServiceHelper.loadSingle("er_reimbursesetting", new QFilter("number", QCP.equals, personNumber).toArray());
+                    if("A".equals(reimBurseSetting.getString("auditstatus"))){
+                        OperationResult operationResult = OperationServiceHelper.executeOperate("audit","er_reimbursesetting",  new DynamicObject[]{reimBurseSetting}, OperateOption.create());
+                        if(!operationResult.isSuccess()){
+                            log.info(String.format("人员【%s】报销级别审核失败%s", personNumber, CommonUtils.getOperationResultErrorInfos(operationResult)));
+                        }
+                    }
+                }
             }
-            reimburseSetting.set("reimburselevel", reimLever.getLong("id"));
+
         }
-        SaveServiceHelper.save(reimburseSettingArray);
         log.info("-------- PersonReimLeverSyncTask 同步人员报销级别任务结束 --------");
     }
+
 }

+ 16 - 1
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/task/TravelFinanDraftCreateTask.java

@@ -15,6 +15,8 @@ import kd.bos.schedule.executor.AbstractTask;
 import kd.bos.servicehelper.BusinessDataServiceHelper;
 import kd.bos.servicehelper.QueryServiceHelper;
 import kd.bos.servicehelper.operation.SaveServiceHelper;
+import kd.bos.servicehelper.org.OrgUnitServiceHelper;
+import kd.bos.servicehelper.org.OrgViewType;
 import nckd.jimin.jyyy.fi.common.constant.BillTypeConstants;
 import nckd.jimin.jyyy.fi.common.constant.travelcheck.TravelFinanDraftConstant;
 import nckd.jimin.jyyy.fi.common.constant.travelcheck.TripReqBillConstant;
@@ -144,7 +146,7 @@ public class TravelFinanDraftCreateTask extends AbstractTask {
 
     protected int getDays(Date startTime, Date endTime,DynamicObject org){
         // 获取组织下的工作日历
-        DynamicObject workCalendar = QueryServiceHelper.queryOne("bd_workcalendar", "id", new QFilter("org", QCP.equals, org.getPkValue()).toArray());
+        DynamicObject workCalendar = getWorkCalandar(org.getLong("id"));
         List<Date> notWorkDayList = new ArrayList<>();
         if(workCalendar != null){
             notWorkDayList = QueryServiceHelper.query("bd_workcalendar", "dateentry.workdate", new QFilter[]{
@@ -165,6 +167,19 @@ public class TravelFinanDraftCreateTask extends AbstractTask {
         return workDays;
     }
 
+    protected DynamicObject getWorkCalandar(Long orgId){
+        DynamicObject workCalendar = QueryServiceHelper.queryOne("bd_workcalendar", "id", new QFilter("org", QCP.equals, orgId).toArray());
+        if(workCalendar == null){
+            Map<Long, Long> parentOrgMap = OrgUnitServiceHelper.getDirectSuperiorOrg(OrgViewType.Admin, Collections.singletonList(orgId));
+            if(!parentOrgMap.containsKey(orgId)){
+                return null;
+            }else{
+                return getWorkCalandar(parentOrgMap.get(orgId));
+            }
+        }
+        return workCalendar;
+    }
+
 
     protected DynamicObject getDraftData( DynamicObject draftEntry , String source, String orderNum, Date startTime,
                                           Date endTime , String from , String to , BigDecimal amount){