|
@@ -1,144 +1,176 @@
|
|
|
package com.usoftchina.uas.office.dingtalk.service;
|
|
package com.usoftchina.uas.office.dingtalk.service;
|
|
|
|
|
|
|
|
import com.dingtalk.api.response.OapiAlitripBtripApplySearchResponse;
|
|
import com.dingtalk.api.response.OapiAlitripBtripApplySearchResponse;
|
|
|
|
|
+import com.dingtalk.api.response.OapiAttendanceGetleavestatusResponse;
|
|
|
|
|
+import com.dingtalk.api.response.OapiSmartworkHrmEmployeeListdimissionResponse;
|
|
|
import com.usoftchina.dingtalk.sdk.OaSdk;
|
|
import com.usoftchina.dingtalk.sdk.OaSdk;
|
|
|
|
|
+import com.usoftchina.uas.office.dingtalk.core.DateUtil;
|
|
|
import com.usoftchina.uas.office.service.AbstractService;
|
|
import com.usoftchina.uas.office.service.AbstractService;
|
|
|
|
|
+import org.slf4j.Logger;
|
|
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
-import org.springframework.dao.DataAccessException;
|
|
|
|
|
-import org.springframework.jdbc.core.CallableStatementCallback;
|
|
|
|
|
-import org.springframework.jdbc.core.CallableStatementCreator;
|
|
|
|
|
import org.springframework.jdbc.core.JdbcTemplate;
|
|
import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
import org.springframework.jdbc.support.rowset.SqlRowSet;
|
|
import org.springframework.jdbc.support.rowset.SqlRowSet;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.util.CollectionUtils;
|
|
import org.springframework.util.CollectionUtils;
|
|
|
|
|
|
|
|
-import java.sql.CallableStatement;
|
|
|
|
|
-import java.sql.Connection;
|
|
|
|
|
-import java.sql.SQLException;
|
|
|
|
|
-import java.text.SimpleDateFormat;
|
|
|
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
|
+import java.util.Date;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
|
|
|
|
|
@Service
|
|
@Service
|
|
|
public class UasOaService extends AbstractService {
|
|
public class UasOaService extends AbstractService {
|
|
|
- //创建序列
|
|
|
|
|
- static final String CREATE_SEQ = "CREATE SEQUENCE ? MINVALUE 1 MAXVALUE 99999999999 INCREMENT BY 1 START WITH 3000 CACHE 20 NOORDER NOCYCLE ";
|
|
|
|
|
- @Autowired
|
|
|
|
|
- protected JdbcTemplate jdbcTemplate;
|
|
|
|
|
-
|
|
|
|
|
|
|
+ private final Logger logger = LoggerFactory.getLogger(UasOaService.class);
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private OaSdk oaSdk;
|
|
private OaSdk oaSdk;
|
|
|
|
|
|
|
|
- public void saveOa(int id){
|
|
|
|
|
|
|
+ public void saveOa(String agentCode,int id){
|
|
|
|
|
+ logger.info("agentCode=="+agentCode);
|
|
|
SqlRowSet rs = jdbcTemplate.queryForRowSet("select od_id,od_kind,to_char(od_startdate,'yyyy-MM-dd hh24:mi:ss') startdate,to_char(od_enddate,'yyyy-MM-dd hh24:mi:ss') enddate from OaDingTalklog where od_id=" + id);
|
|
SqlRowSet rs = jdbcTemplate.queryForRowSet("select od_id,od_kind,to_char(od_startdate,'yyyy-MM-dd hh24:mi:ss') startdate,to_char(od_enddate,'yyyy-MM-dd hh24:mi:ss') enddate from OaDingTalklog where od_id=" + id);
|
|
|
while (rs.next()){
|
|
while (rs.next()){
|
|
|
String odKind = rs.getString("od_kind");
|
|
String odKind = rs.getString("od_kind");
|
|
|
String startdate = rs.getString("startdate");
|
|
String startdate = rs.getString("startdate");
|
|
|
String enddate = rs.getString("enddate");
|
|
String enddate = rs.getString("enddate");
|
|
|
|
|
+ //离职、补卡、请假、出差、加班
|
|
|
if ("出差申请单".equals(odKind)){
|
|
if ("出差申请单".equals(odKind)){
|
|
|
- saveAlitripList("Uas", startdate, enddate, 1, 50);
|
|
|
|
|
- } else if ("".equals(odKind)) {
|
|
|
|
|
|
|
+ saveAlitripList(agentCode, startdate, enddate);
|
|
|
|
|
+ } else if ("请假申请单".equals(odKind)) {
|
|
|
|
|
+ saveLeaves(agentCode,DateUtil.parse(startdate,"yyyy-MM-dd HH:mm:ss").getTime(),DateUtil.parse(enddate,"yyyy-MM-dd HH:mm:ss").getTime());
|
|
|
|
|
+ } else if ("加班申请单".equals(odKind)) {
|
|
|
|
|
+
|
|
|
|
|
+ }else if ("补卡申请单".equals(odKind)) {
|
|
|
|
|
|
|
|
|
|
+ }else if ("离职申请单".equals(odKind)) {
|
|
|
|
|
+ saveEmpLeaveRecords(agentCode);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
/**
|
|
/**
|
|
|
* 保存出差申请
|
|
* 保存出差申请
|
|
|
*/
|
|
*/
|
|
|
- public void saveAlitripList(String agentCode, String startTime, String endTime, long offset, long limit) {
|
|
|
|
|
- List<OapiAlitripBtripApplySearchResponse.OpenApplyRs> alitripList = oaSdk.getAllAlitrip(agentCode,startTime,endTime,offset,limit);
|
|
|
|
|
|
|
+ public void saveAlitripList(String agentCode, String startTime, String endTime) {
|
|
|
|
|
+ List<OapiAlitripBtripApplySearchResponse.OpenApplyRs> alitripList = oaSdk.getAllAlitrip(agentCode,startTime,endTime);
|
|
|
if (!CollectionUtils.isEmpty(alitripList)) {
|
|
if (!CollectionUtils.isEmpty(alitripList)) {
|
|
|
|
|
+ logger.info("出差申请单alitripList==" + alitripList.size());
|
|
|
for (OapiAlitripBtripApplySearchResponse.OpenApplyRs openApplyRs:alitripList) {
|
|
for (OapiAlitripBtripApplySearchResponse.OpenApplyRs openApplyRs:alitripList) {
|
|
|
- int id = getSeqId("FEEPLEASE_SEQ");
|
|
|
|
|
- String code = callProcedure("Sp_GetMaxNumber", new Object[]{"FeePlease!CCSQ!new", 2});
|
|
|
|
|
- SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
- String inDate = format.format(openApplyRs.getGmtCreate());
|
|
|
|
|
- List<OapiAlitripBtripApplySearchResponse.OpenItineraryInfo> itineraryList = openApplyRs.getItineraryList();
|
|
|
|
|
- String startDate = format.format(itineraryList.get(0).getDepDate());
|
|
|
|
|
- String endDate = format.format(itineraryList.get(0).getArrDate());
|
|
|
|
|
|
|
+ String inDate = DateUtil.format(openApplyRs.getGmtCreate(),"yyyy-MM-dd HH:mm:ss");
|
|
|
Long rsId = openApplyRs.getId();
|
|
Long rsId = openApplyRs.getId();
|
|
|
- SqlRowSet rowSet = jdbcTemplate.queryForRowSet("select * from FeePlease where dp_ddid=" + rsId);
|
|
|
|
|
- if (!rowSet.next()) {
|
|
|
|
|
- jdbcTemplate.execute("insert into FeePlease (fp_id,fp_code,fp_v9,FP_PEOPLE2,fp_recordman,fp_recorddate,fp_statuscode,fp_status,fp_v3,fp_prestartdate,fp_preenddate,fp_n6,) " +
|
|
|
|
|
- "values (" + id + ",'" + code + "','" + openApplyRs.getDeptName() + "','" + openApplyRs.getUserName() + "','" + openApplyRs.getUserName() + "',to_date('" + inDate + "','yyyy-MM-dd HH:mi:ss'),'AUDITED','已审核','" + openApplyRs.getTripCause() + "',to_date('" + startDate + "','yyyy-MM-dd HH:mi:ss'),to_date('" + endDate + "','yyyy-MM-dd HH:mi:ss')," + openApplyRs.getTripDay() + ")");
|
|
|
|
|
|
|
+ String statusDesc = openApplyRs.getStatusDesc()==null?"空":openApplyRs.getStatusDesc();
|
|
|
|
|
+ if (statusDesc.contains("已同意")){
|
|
|
|
|
+ List<OapiAlitripBtripApplySearchResponse.OpenItineraryInfo> itineraryList = openApplyRs.getItineraryList();
|
|
|
|
|
+ for (OapiAlitripBtripApplySearchResponse.OpenItineraryInfo openItineraryInfo:itineraryList) {
|
|
|
|
|
+ String startDate = DateUtil.format(openItineraryInfo.getDepDate(),"yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
+ String endDate = DateUtil.format(openItineraryInfo.getArrDate(),"yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
+ String projectTitle = openItineraryInfo.getProjectTitle();
|
|
|
|
|
+ String projectCode = openItineraryInfo.getProjectCode();
|
|
|
|
|
+ String arrCity = openItineraryInfo.getArrCity();
|
|
|
|
|
+ String depCity = openItineraryInfo.getDepCity();
|
|
|
|
|
+ String itineraryId = openItineraryInfo.getItineraryId();
|
|
|
|
|
+ String ddid=rsId.toString()+"-"+itineraryId;
|
|
|
|
|
+ int count =queryForObject("select count(1) from FeePlease where fp_dingid='"+ddid+"'", Integer.class);
|
|
|
|
|
+ if (count<=0) {
|
|
|
|
|
+ int id = generateId("FEEPLEASE_SEQ");
|
|
|
|
|
+ String code = generateCode("FeePlease!CCSQ!new", 2);
|
|
|
|
|
+ jdbcTemplate.execute("insert into FeePlease (fp_id,fp_code,fp_kind,fp_v9,FP_PEOPLE2,fp_recordman,fp_recorddate,fp_statuscode,fp_status,fp_v3,fp_prestartdate,fp_preenddate,fp_n6,fp_dingid,fp_remark,fp_prjcode,fp_prjname,fp_depcity,fp_arrcity) " +
|
|
|
|
|
+ "values (" + id + ",'" + code + "','出差申请单','" + openApplyRs.getDeptName() + "','" + openApplyRs.getUserName() + "','" + openApplyRs.getUserName() + "',to_date('" + inDate + "','yyyy-MM-dd HH24:mi:ss'),'AUDITED','已审核','" + openApplyRs.getTripCause() + "',to_date('" + startDate + "','yyyy-MM-dd HH24:mi:ss'),to_date('" + endDate + "','yyyy-MM-dd HH24:mi:ss')," + openApplyRs.getTripDay() + ","+rsId+",'"+statusDesc+"','"+projectCode+"','"+projectTitle+"','"+depCity+"','"+arrCity+"')");
|
|
|
|
|
+ /*jdbcTemplate.execute("insert into FeePleaseDetail(fpd_id,fpd_fpid,fpd_code,fpd_class,fpd_detno,fpd_d5,fpd_d6,fpd_date1,fpd_date2) " +
|
|
|
|
|
+ "values(FeePleaseDetail_seq.nextval,"+id+",'"+code+"','出差申请单',1,'"+projectCode+"','"+projectTitle+"',to_date('" + startDate + "','yyyy-MM-dd HH24:mi:ss'),to_date('" + endDate + "','yyyy-MM-dd HH24:mi:ss'))");*/
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 获取序列号
|
|
|
|
|
- *
|
|
|
|
|
- * @param seq
|
|
|
|
|
- * 指定的序列名
|
|
|
|
|
|
|
+ * 保存离职申请
|
|
|
*/
|
|
*/
|
|
|
- private int getSeqId(String seq) {
|
|
|
|
|
- try {
|
|
|
|
|
- String sql = "select " + seq + ".nextval from dual";
|
|
|
|
|
- SqlRowSet rs = jdbcTemplate.queryForRowSet(sql);
|
|
|
|
|
- if (rs.next()) {
|
|
|
|
|
- return rs.getInt(1);
|
|
|
|
|
- } else {// 如果不存在就创建序列
|
|
|
|
|
- SqlRowSet rowSet = jdbcTemplate.queryForRowSet("select * from user_sequences where Sequence_Name='" + seq.toUpperCase() + "'");
|
|
|
|
|
- if (!rowSet.next()) {
|
|
|
|
|
- jdbcTemplate.execute(CREATE_SEQ.replace("?", seq));
|
|
|
|
|
|
|
+ public void saveEmpLeaveRecords(String agentCode) {
|
|
|
|
|
+ int count = queryForObject("select count(1) from employee where nvl(em_ding,' ')<>' '",Integer.class);
|
|
|
|
|
+ if (count>0) {
|
|
|
|
|
+ int size=50;
|
|
|
|
|
+ int con = (int) Math.ceil((double)count / size);
|
|
|
|
|
+ if (con>0) {
|
|
|
|
|
+ for (int j = 0; j < con; j++) {
|
|
|
|
|
+ int min = j * size, max = (j + 1) * size;
|
|
|
|
|
+ List<String> strings = new ArrayList<>();
|
|
|
|
|
+ SqlRowSet rs = jdbcTemplate.queryForRowSet("select em_ding from (select em_ding,rownum rn from employee where nvl(em_ding,' ')<>' ') where rn>" + min + " and rn<=" + max);
|
|
|
|
|
+ while (rs.next()) {
|
|
|
|
|
+ strings.add(rs.getString("em_ding"));
|
|
|
|
|
+ }
|
|
|
|
|
+ List<OapiSmartworkHrmEmployeeListdimissionResponse.EmpDimissionInfoVo> empLeave = oaSdk.getEmpLeave(agentCode, strings);
|
|
|
|
|
+ if (!CollectionUtils.isEmpty(empLeave)) {
|
|
|
|
|
+ logger.info("离职申请单empLeave==" + empLeave.size());
|
|
|
|
|
+ for (int i = 0; i < empLeave.size(); i++) {
|
|
|
|
|
+ OapiSmartworkHrmEmployeeListdimissionResponse.EmpDimissionInfoVo empDimissionInfoVo = empLeave.get(i);
|
|
|
|
|
+ String deptName = empDimissionInfoVo.getMainDeptName();
|
|
|
|
|
+ String reasonMemo = empDimissionInfoVo.getReasonMemo();
|
|
|
|
|
+ Long lastWorkDay = empDimissionInfoVo.getLastWorkDay();
|
|
|
|
|
+ String leaves = null;
|
|
|
|
|
+ if (lastWorkDay!=null&&lastWorkDay > 0) {
|
|
|
|
|
+ leaves = DateUtil.format(new Date(lastWorkDay), "yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
+ }
|
|
|
|
|
+ String userid = empDimissionInfoVo.getUserid();
|
|
|
|
|
+ Long status = empDimissionInfoVo.getStatus();
|
|
|
|
|
+ int count1 = queryForObject("select count(1) from Turnover where to_dingtalkid='" + userid + "'", Integer.class);
|
|
|
|
|
+ if (count1 <= 0&&status==2) {
|
|
|
|
|
+ int id = generateId("TURNOVER_SEQ");
|
|
|
|
|
+ String code = generateCode("Turnover", 2);
|
|
|
|
|
+ if (leaves != null) {
|
|
|
|
|
+ jdbcTemplate.execute("insert into Turnover (to_id,to_code,to_applymancode,to_applyman,to_leavedate,to_recordor,to_date,to_statuscode,to_status,to_otherreason,to_dingtalkid) " +
|
|
|
|
|
+ "select " + id + ",'" + code + "',em_code,em_name,to_date('" + leaves + "','yyyy-MM-dd HH24:mi:ss'),em_name,sysdate,'AUDITED','已审核','" + reasonMemo + "','" + userid + "' from employee where em_ding='" + userid + "'");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ jdbcTemplate.execute("insert into Turnover (to_id,to_code,to_applymancode,to_applyman,to_recordor,to_date,to_statuscode,to_status,to_otherreason,to_dingtalkid) " +
|
|
|
|
|
+ "select " + id + ",'" + code + "',em_code,em_name,em_name,sysdate,'AUDITED','已审核','" + reasonMemo + "','" + userid + "' from employee where em_ding='" + userid + "'");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- return getSeqId(seq);
|
|
|
|
|
- }
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- SqlRowSet rowSet = jdbcTemplate.queryForRowSet("select * from user_sequences where Sequence_Name='" + seq.toUpperCase() + "'");
|
|
|
|
|
- if (!rowSet.next()) {
|
|
|
|
|
- jdbcTemplate.execute(CREATE_SEQ.replace("?", seq));
|
|
|
|
|
}
|
|
}
|
|
|
- return getSeqId(seq);
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 调用存储过程
|
|
|
|
|
- *
|
|
|
|
|
- * @param procedureName
|
|
|
|
|
- * 存储过程名称
|
|
|
|
|
- * @param args
|
|
|
|
|
- * 参数
|
|
|
|
|
- * @return varchar类型结果
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 请假申请
|
|
|
*/
|
|
*/
|
|
|
- private String callProcedure(final String procedureName, final Object... args) {
|
|
|
|
|
- try {
|
|
|
|
|
- return jdbcTemplate.execute(new CallableStatementCreator() {
|
|
|
|
|
- @Override
|
|
|
|
|
- public CallableStatement createCallableStatement(Connection conn) throws SQLException {
|
|
|
|
|
- StringBuffer storedProcName = new StringBuffer("{call ");
|
|
|
|
|
- int i = 0;
|
|
|
|
|
- storedProcName.append(procedureName + "(");
|
|
|
|
|
- for (i = 0; i < args.length; i++) {
|
|
|
|
|
- if (storedProcName.toString().contains("?")) {
|
|
|
|
|
- storedProcName.append(",");
|
|
|
|
|
- }
|
|
|
|
|
- storedProcName.append("?");
|
|
|
|
|
|
|
+ public void saveLeaves(String agentCode, long startTime, long endTime){
|
|
|
|
|
+ int count = queryForObject("select count(1) from employee where nvl(em_ding,' ')<>' '",Integer.class);
|
|
|
|
|
+ if (count>0){
|
|
|
|
|
+ int size=100;
|
|
|
|
|
+ int con = (int) Math.ceil((double)count / size);
|
|
|
|
|
+ if (con>0) {
|
|
|
|
|
+ for (int i = 0; i < con; i++) {
|
|
|
|
|
+ int min = i * size, max = (i + 1) * size;
|
|
|
|
|
+ List<String> strings = new ArrayList<>();
|
|
|
|
|
+ SqlRowSet rs = jdbcTemplate.queryForRowSet("select em_ding from (select em_ding,rownum rn from employee where nvl(em_ding,' ')<>' ') where rn>" + min + " and rn<=" + max);
|
|
|
|
|
+ while (rs.next()) {
|
|
|
|
|
+ strings.add(rs.getString("em_ding"));
|
|
|
}
|
|
}
|
|
|
- if (storedProcName.toString().contains("?")) {
|
|
|
|
|
- storedProcName.append(",");
|
|
|
|
|
- }
|
|
|
|
|
- storedProcName.append("?");
|
|
|
|
|
- storedProcName.append(")}");
|
|
|
|
|
- CallableStatement cs = conn.prepareCall(storedProcName.toString());
|
|
|
|
|
- for (i = 0; i < args.length; i++) {
|
|
|
|
|
- cs.setObject(i + 1, args[i]);
|
|
|
|
|
|
|
+ List<OapiAttendanceGetleavestatusResponse.LeaveStatusVO> leaveStatusVOS = oaSdk.getAllLeaves(agentCode, strings, startTime, endTime);
|
|
|
|
|
+ if (!CollectionUtils.isEmpty(leaveStatusVOS)) {
|
|
|
|
|
+ logger.info("请假申请单leaveStatusVOS==" + leaveStatusVOS.size());
|
|
|
|
|
+ for (int j = 0; j < leaveStatusVOS.size(); j++) {
|
|
|
|
|
+ OapiAttendanceGetleavestatusResponse.LeaveStatusVO leaveStatusVO = leaveStatusVOS.get(j);
|
|
|
|
|
+ Long durationPercent = leaveStatusVO.getDurationPercent() / 100;
|
|
|
|
|
+ String durationUnit = leaveStatusVO.getDurationUnit();
|
|
|
|
|
+ Long startDate = leaveStatusVO.getStartTime();
|
|
|
|
|
+ Long endDate = leaveStatusVO.getEndTime();
|
|
|
|
|
+ String userid = leaveStatusVO.getUserid();
|
|
|
|
|
+ String startformat = DateUtil.format(new Date(startDate), "yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
+ String endformat = DateUtil.format(new Date(endDate), "yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
+ int count1 = queryForObject("select count(1) from Vacation where va_dingtalkid='" + userid + "' and to_char(va_startime,'yyyy-MM-dd HH24:mi:ss')='" + startformat + "' and to_char(va_endtime,'yyyy-MM-dd HH24:mi:ss')='" + endformat + "'", Integer.class);
|
|
|
|
|
+ if (count1 <= 0) {
|
|
|
|
|
+ int id = generateId("VACATION_SEQ");
|
|
|
|
|
+ String code = generateCode("Ask4Leave", 2);
|
|
|
|
|
+ jdbcTemplate.execute("insert into Vacation (va_id,va_code,va_statuscode,va_status,va_emcode,va_emname,va_date,va_department,va_position,va_recordor,va_recordorid,va_days,va_alltimes,va_startime,va_endtime,va_remark,va_dingtalkid) " +
|
|
|
|
|
+ "select " + id + ",'" + code + "','AUDITED','已审核',em_code,em_name,sysdate,em_depart,em_position,em_name,em_id,case when '" + durationUnit + "'='percent_day' then " + durationPercent + " else 0 end,case when '" + durationUnit + "'='percent_hour' then " + durationPercent + " else 0 end,to_date('" + startformat + "','yyyy-MM-dd hh24:mi:ss'),to_date('" + endformat + "','yyyy-MM-dd hh24:mi:ss'),'钉钉同步','" + userid + "' from employee where em_ding='" + userid + "'");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- cs.registerOutParameter(args.length + 1, java.sql.Types.VARCHAR);
|
|
|
|
|
- return cs;
|
|
|
|
|
}
|
|
}
|
|
|
- }, new CallableStatementCallback<String>() {
|
|
|
|
|
- @Override
|
|
|
|
|
- public String doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
|
|
|
|
|
- cs.execute();
|
|
|
|
|
- return cs.getString(args.length + 1);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- });
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- e.getMessage();
|
|
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- return null;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
}
|
|
}
|