package com.runchain.comac.service.template.weekly;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import com.runchain.arch.service.ServiceException;
import com.runchain.arch.service.base.BaseService;
import com.runchain.arch.util.date.DateBean;
import com.runchain.arch.util.date.DateUtil;
import com.runchain.arch.util.date.WeekDate;
import com.runchain.comac.entity.template.CustomFieldIndexOfTemplate;
import com.runchain.comac.entity.template.TemplateFieldEntity;
import com.runchain.comac.entity.template.task.GroupTask;
import com.runchain.comac.entity.template.task.OrgTask;
import com.runchain.comac.entity.template.task.TemplateTaskEntity;
import com.runchain.comac.entity.template.weekly.WeeklyTemplateEntity;
import com.runchain.comac.service.account.DeptManager;
import com.runchain.comac.service.journal.DailyWorkLogManager;
import com.runchain.comac.service.template.common.CommonTemplateManager;
import com.runchain.comac.service.template.common.CustomFieldIndexOfTemplateManager;
import com.runchain.comac.util.account.OrganizationUtil;
import com.runchain.comac.util.template.ExcelTemplateData;
import com.runchain.comac.util.template.ExcelTemplateResolve;
import com.runchain.comac.util.template.ProjectType;
import com.runchain.comac.util.template.ReportType;
import com.runchain.comac.util.template.TemplateException;
import com.runchain.comac.util.template.TemplateUtil;
/**
* 周报模板Service
* <ul>
* <li>T-模板实体</li>
* <li>TOT-部门和任务项关系</li>
* <li>TT-模板任务项</li>
* <li>TF-模板自定义字段</li>
* </ul>
*
* @author HenryYan
*
*/
public abstract class WeeklyTemplateService<T extends WeeklyTemplateEntity, TOT extends OrgTask, TT extends TemplateTaskEntity<TT>, TF extends TemplateFieldEntity<T>, GT extends GroupTask>
extends BaseService {
@Autowired
protected DailyWorkLogManager dailyWorkLogManager;
@Autowired
protected DeptManager deptManager;
@Autowired
protected CustomFieldIndexOfTemplateManager indexManager;
protected Integer year;
protected Integer week;
protected Long templateId = null;
protected String templateFileName;
protected ExcelTemplateResolve<TT, TOT, TF> resolve;
/**
* 从Excel中导入模板文件到数据库
* @param template 新的模板对象
* @throws ServiceException 业务相关异常
* @throws Exception 系统处理异常
*/
@Transactional(rollbackFor = {TemplateException.class, ServiceException.class, Exception.class})
public void importTemplate(T template) throws TemplateException, ServiceException, Exception {
// 1、检查模板对象
checkAndInit(template);
// 2、解析模板
templateFileName = TemplateUtil.getTemplateFileBasePath() + "/" + template.getTemplateFileName();
logger.info("开始验证类型为:{}的模板:{}", getProjectType(), templateFileName);
resolve = getResolve();
if (resolve.checkTemplate()) {
// 3.0 检查指定年份和周次模板是否存在
T dbTemplate = getTemplateManager().findTemplate(year, week);
if (dbTemplate != null) {
throw new ServiceException(year + "年" + week + "周的模板已经存在!");
}
// 3.1 根据选择的周次获取周的第一天作为模板生效日期
WeekDate weekDate = new WeekDate(year);
DateBean dateBean = weekDate.getDateMap().get(week);
java.sql.Date effectiveDate = DateUtil.extractSqlDate(dateBean.getStartCalendar());
template.setEffectiveDate(effectiveDate);
// 3.2、保存模板对象到数据库
template.setImportDate(new Date());
template.setVersion(year + "-" + week);
getTemplateManager().saveEntity(template);
templateId = template.getId();
// 3.3、设置上一版本的模板失效日期为此模板生效日期的前一天
T preVersionTemplate = getTemplateManager().findPreVersionTemplate(year, week);
if (preVersionTemplate != null) {
logger.debug("根据{年={},周={}},查询出上一版本的大客周报模板为:{}", new Object[] { year, week, preVersionTemplate });
// 设置上一版本的失效日期
Calendar expiryDateCalendar = Calendar.getInstance();
expiryDateCalendar.setTime(effectiveDate);
expiryDateCalendar.add(Calendar.DATE, -1);
java.sql.Date expiryDate = DateUtil.extractSqlDate(expiryDateCalendar);
preVersionTemplate.setExpiryDate(expiryDate);
getTemplateManager().saveEntity(preVersionTemplate);
logger.debug("设置大客周报模板失效日期为:{},模板对象:{}", expiryDate, preVersionTemplate);
}
}
logger.info("开始解析模板:{}", templateFileName);
// 准备部门ID和部门名称映射
deptManager.initOrganizations(OrganizationUtil.SUPER_UNIT_ID);
resolve.setTemplateId(template.getId());
ExcelTemplateData<TT, TF> templateData = resolve.readTemplate();
// 4.1、保存模板任务项
List<TT> tasks = (List<TT>) templateData.getTasks();
getTaskManager().saveEntity(tasks);
// 4.2、保存部门任务分配
List<OrgTask> orgTasks = new ArrayList<OrgTask>();
for (TT task : tasks) {
List<OrgTask> tempOrgTasks = task.getOrgTasks();
for (OrgTask orgTask : tempOrgTasks) {
orgTask.getId().setTaskId(task.getId());
orgTask.setTaskParentId(task.getParent() == null ? null : task.getParent().getId());
orgTask.setTemplateId(templateId);
}
orgTasks.addAll(tempOrgTasks);
}
getOrgTaskManager().saveOrgTasks(orgTasks);
// 4.3、保存模板自定义字段
List<TF> fields = (List<TF>) templateData.getFields();
// 4.4、设置字段对应的模板
for (TF field : fields) {
field.setTemplate(template);
}
getFieldManager().saveEntity(fields);
// 4.5、保存自定义字段索引位置
List<CustomFieldIndexOfTemplate> indexs = templateData.getIndexs();
for (CustomFieldIndexOfTemplate index : indexs) {
index.setTemplateId(templateId);
indexManager.saveEntity(index);
}
// 5、加载任务项信息到内存数据库
TemplateUtil.initWeeklyTaskMapper(templateId, ProjectType.c919);
logger.info("导入模板成功:{}", template);
}
/**
* 获取解析对象
* @return 模板解析对象
* @throws IOException 读取模板文件时
* @throws FileNotFoundException 找不到模板文件时
* @see {@link ExcelTemplateResolve#createReaderUsePoi}
*/
protected abstract ExcelTemplateResolve<TT, TOT, TF> getResolve() throws FileNotFoundException, IOException;
/**
* 检查模板是否可以被导入
* @param year 年份
* @param week 月份
* @return
* @throws ServiceException 业务异常
* @throws Exception 系统异常
*/
public boolean canImportTemplate(Integer year, Integer week) throws ServiceException, Exception {
// 1、判断唯一版本
T template = getTemplateManager().findTemplate(year, week);
if (template != null) {
throw new ServiceException("已经存在" + year + "年" + week + "周的模板");
}
String lastVersion = getTemplateManager().getLastVersion();
if (StringUtils.isNotBlank(lastVersion)) {
lastVersion = StringUtils.defaultString(lastVersion).replaceAll("-", "");
if (StringUtils.isNumeric(lastVersion)) {
Integer integerLastVersion = new Integer(lastVersion);
Integer selectYearWeek = new Integer(year + "" + week);
if (selectYearWeek <= integerLastVersion) {
throw new ServiceException(year + "年第" + week + "周之后已经存在版本,不可导入。");
}
} else {
throw new Exception("得到的版本不能转换为数字");
}
}
// 2、判断是否被日志使用
Boolean checkTemplateUsedByDailyLog = checkTemplateUsedByDailyLog(year, week);
if (checkTemplateUsedByDailyLog) {
throw new ServiceException("此周次已有日志使用了模板,不可覆盖!");
}
return true;
}
/**
* 检查模板是否被日志使用
* @param year 年份
* @param week 月份
* @throws ServiceException 业务异常,作为提示信息
* @throws ParseException
*/
@Transactional(readOnly = true)
public Boolean checkTemplateUsedByDailyLog(Integer year, Integer week) throws ServiceException, ParseException {
T enableTemplate = getTemplateManager().findEnableTemplate(year, week);
if (enableTemplate == null) {
logger.debug("没有找到{年={},周={}}可用的的{}周报模板", new Object[] { year, week, getProjectType().name() });
return false;
} else {
java.sql.Date maxLogDate = dailyWorkLogManager.getMaxLogDate(getProjectType(), enableTemplate.getId());
if (maxLogDate == null) {
logger.debug("{年={},周={}}{}周报模板未被使用", new Object[] { year, week, getProjectType().name() });
return false;
} else {
WeekDate weekDate = new WeekDate(year);
DateBean dateBean = weekDate.getDateMap().get(week);
java.sql.Date startDate = DateUtil.extractSqlDate(dateBean.getStartCalendar());
if (startDate.getTime() > maxLogDate.getTime()) {
return false;
}
logger.debug("{年={},周={}}{}周报模板被日志使用,最后使用日期:{}", new Object[] { year, week, getProjectType().name(),
maxLogDate });
throw new ServiceException("本周已有日志,最后使用日期为:" + maxLogDate);
}
}
}
/**
* 删除模板以及相关联的任务项、自定义字段、部门任务分配
*
* @param templateId 模板ID
*
* @throws ServiceException 业务异常
* @throws Exception 系统异常
*/
@Transactional(rollbackFor = {ServiceException.class, Exception.class})
public void deleteTemplate(Long templateId) throws ServiceException, Exception {
// 1.1 检查模板是否存在
T weeklyTemplate = getTemplateManager().getEntity(templateId);
if (weeklyTemplate == null) {
throw new ServiceException("模板不存在,模板ID=" + templateId);
}
// 1.2、 检查是否可以删除(判断此模板是否被使用)
java.sql.Date maxLogDate = dailyWorkLogManager.getMaxLogDate(getProjectType(), weeklyTemplate.getId());
if (maxLogDate != null) {
throw new ServiceException("此模板已被日志使用,最后使用日期为:" + maxLogDate + ",删除失败!");
}
// 2.1、删除模板任务项
getTaskManager().deleteTasks(templateId);
// 2.2、删除自定义字段
getFieldManager().deleteFields(templateId);
// 2.3、删除自定义字段位置信息
indexManager.delete(templateId, getProjectType(), ReportType.weekly);
// 2.4、删除部门任务分配
getOrgTaskManager().deleteOrgTasks(templateId);
// 2.5、设置上一个版本的实效日期
T preVersionTemplate = getTemplateManager().findPreVersionTemplate(weeklyTemplate.getYear(), weeklyTemplate.getWeek());
if (preVersionTemplate != null) {
preVersionTemplate.setExpiryDate(null);
getTemplateManager().saveEntity(preVersionTemplate);
}
// 2.6、删除模板对象
getTemplateManager().deleteEntity(weeklyTemplate);
// 3、删除内存缓存
TemplateUtil.cleanWeeklyTemplateTaskMapper(templateId, getProjectType());
}
/**
* 导入前初始化及检查
* @param template 模板对象
* @throws ServiceException 业务异常
* @throws Exception 系统异常
*/
private void checkAndInit(T template) throws ServiceException, Exception {
if (template == null) {
throw new Exception("模板对象为空");
}
year = template.getYear();
week = template.getWeek();
if (year == null) {
throw new ServiceException("导入模板的年份不能为空");
}
if (week == null) {
throw new ServiceException("导入模板的周次不能为空");
}
}
/**
* 解析前回调
* @param template
*/
public abstract void beforeResolve(T template);
/**
* 解析完成后回调
* @param template
*/
public abstract void resolveComplete(T template);
/**
* 获取模板实体管理类
* @return
*/
protected abstract CommonTemplateManager<T> getTemplateManager();
/**
* 获取任务实体管理类
* @return
*/
protected abstract WeeklyTemplateTaskManager<TT> getTaskManager();
/**
* 获取模板自定义字段实体管理类
* @return
*/
protected abstract WeeklyTemplateFieldManager<TF> getFieldManager();
/**
* 获取部门和任务项的关系实体管理类
* @return
*/
protected abstract WeeklyTemplateOrgTaskManager<T, TOT, TT, GT> getOrgTaskManager();
/**
* 获取项目类型
* @return
*/
protected abstract ProjectType getProjectType();
}