diff --git a/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBill.java b/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBill.java index ebc46fc8e4..7e31971995 100644 --- a/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBill.java +++ b/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBill.java @@ -76,11 +76,27 @@ public class AsBusreserveBill extends BaseEntity { private String mobile; // 联系电话 @ApiModelProperty("车牌号") private String vehMark; // 车牌号 + @ApiModelProperty("车架号") + private String vinNo; // 车牌号 @ApiModelProperty("车型") private String vehModel; // 车型 @ApiModelProperty("使用组织sid") private String useOrgSid; // 使用组织sid @ApiModelProperty("创建组织sid") private String createOrgSid; // 创建组织sid + @ApiModelProperty("使用组织") + private String useOrgName; // 使用组织 + @ApiModelProperty("创建组织") + private String createOrgName; // 创建组织 + @ApiModelProperty("组织全路径") + private String orgSidPath; // 组织全路径 + @ApiModelProperty("跟踪记录") + private String trackLogs; // 跟踪记录 + @ApiModelProperty("制单部门sid") + private String createDeptSid; // 制单部门sid + @ApiModelProperty("制单部门") + private String createDept; // 制单部门 + @ApiModelProperty("客户单位") + private String customerOrg; // 客户单位 } diff --git a/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBillDetailsVo.java b/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBillDetailsVo.java index c67e066aac..ceb6d46925 100644 --- a/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBillDetailsVo.java +++ b/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBillDetailsVo.java @@ -57,7 +57,10 @@ public class AsBusreserveBillDetailsVo implements Vo { private String sid; // sid private String createBySid; // sid + private String orgPath; private String remarks; // 备注 + @ApiModelProperty("制单时间") + private String createTime; // 制单人姓名 @ApiModelProperty("制单人姓名") private String createByName; // 制单人姓名 @ApiModelProperty("单据编号") @@ -79,12 +82,22 @@ public class AsBusreserveBillDetailsVo implements Vo { private String mobile; // 联系电话 @ApiModelProperty("车牌号") private String vehMark; // 车牌号 + @ApiModelProperty("车架号") + private String vinNo; // 车牌号 @ApiModelProperty("车型") private String vehModel; // 车型 @ApiModelProperty("使用组织sid") private String useOrgSid; // 使用组织sid @ApiModelProperty("创建组织sid") private String createOrgSid; // 创建组织sid + @ApiModelProperty("跟踪记录") + private String trackLogs; // 跟踪记录 + @ApiModelProperty("制单部门sid") + private String createDeptSid; // 制单部门sid + @ApiModelProperty("制单部门") + private String createDept; // 制单部门 + @ApiModelProperty("客户单位") + private String customerOrg; // 客户单位 private List sitemVos = new ArrayList<>(); } \ No newline at end of file diff --git a/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBillDto.java b/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBillDto.java index 6712bfa16b..dd360bab8a 100644 --- a/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBillDto.java +++ b/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBillDto.java @@ -57,9 +57,12 @@ public class AsBusreserveBillDto implements Dto { private String sid; // sid private String createBySid; // sid + private String orgPath; private String remarks; // 备注 @ApiModelProperty("制单人姓名") private String createByName; // 制单人姓名 + @ApiModelProperty("制单时间") + private String createTime; // 制单人姓名 @ApiModelProperty("单据编号") private String billNo; // 单据编号 private String reserveStart; // 预约时间开始 @@ -79,12 +82,22 @@ public class AsBusreserveBillDto implements Dto { private String mobile; // 联系电话 @ApiModelProperty("车牌号") private String vehMark; // 车牌号 + @ApiModelProperty("车架号") + private String vinNo; // 车牌号 @ApiModelProperty("车型") private String vehModel; // 车型 @ApiModelProperty("使用组织sid") private String useOrgSid; // 使用组织sid @ApiModelProperty("创建组织sid") private String createOrgSid; // 创建组织sid + @ApiModelProperty("跟踪记录") + private String trackLogs; // 跟踪记录 + @ApiModelProperty("制单部门sid") + private String createDeptSid; // 制单部门sid + @ApiModelProperty("制单部门") + private String createDept; // 制单部门 + @ApiModelProperty("客户单位") + private String customerOrg; // 客户单位 private List sitemVos = new ArrayList<>(); diff --git a/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBillQuery.java b/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBillQuery.java index 255d02d0e1..6660a320f7 100644 --- a/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBillQuery.java +++ b/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBillQuery.java @@ -51,19 +51,30 @@ import lombok.Data; @ApiModel(value = "预约单 查询条件", description = "预约单 查询条件") public class AsBusreserveBillQuery implements Query { + @ApiModelProperty("使用组织sid") + private String orgPath; + private String userSid; + @ApiModelProperty("菜单url") + private String menuUrl; + + private String useOrgName; // 分公司 + private String createDept; //制单部门 + private String createByName;//制单人 + private String billNo;//单据编号 + @ApiModelProperty("制单时间开始") + private String startCreateDate; // 制单时间开始 + private String endCreateDate; // 制单时间结束 + @ApiModelProperty("客户名称") + private String customerName; // 客户名称 + @ApiModelProperty("车牌号") + private String vehMark; // 车牌号 + @ApiModelProperty("车架号") + private String vinNo; // 车架号 + @ApiModelProperty("联系电话") + private String mobile; // 联系电话 @ApiModelProperty("预约时间开始") private String startDate; // 预约时间开始 private String endDate; // 预约时间开始 - @ApiModelProperty("客户名称") - private String customerName; // 客户名称 - @ApiModelProperty("联系电话") - private String mobile; // 联系电话 - @ApiModelProperty("车牌号") - private String vehMark; // 车牌号 - @ApiModelProperty("车型") - private String vehModel; // 车型 - @ApiModelProperty("使用组织sid") - private String useOrgSid; // 使用组织sid private String state; } diff --git a/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBillVo.java b/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBillVo.java index df9dcba1a5..4a2aea897c 100644 --- a/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBillVo.java +++ b/yxt-as/src/main/java/com/yxt/anrui/as/api/asbusreservebill/AsBusreserveBillVo.java @@ -52,27 +52,33 @@ import lombok.Data; public class AsBusreserveBillVo implements Vo { private String sid; // sid - + @ApiModelProperty("单据编号") + private String billNo; // 单据编号 + private String state; // 1未完成 0已完成 2作废 + @ApiModelProperty("分公司") + private String useOrgName; // 分公司 + @ApiModelProperty("制单部门") + private String createDept; // 制单部门 @ApiModelProperty("制单人姓名") private String createByName; // 制单人姓名 - @ApiModelProperty("单据编号") - private String billNo; // 单据编号 - private String reserveStart; // 预约时间开始 + @ApiModelProperty("制单日期") + @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") + private Date createTime; // 制单日期 + @ApiModelProperty("客户名称") + private String customerName; // 客户名称 + @ApiModelProperty("车牌号") + private String vehMark; // 车牌号 + @ApiModelProperty("联系电话") + private String mobile; // 联系电话 + @ApiModelProperty("预约时间开始") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + private Date reserveStart; // 预约时间开始 @ApiModelProperty("预约时间截止") - private String reserveEnd; // 预约时间截止 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + private Date reserveEnd; // 预约时间截止 @ApiModelProperty("预约服务顾问") private String waitorName; // 预约服务顾问 @ApiModelProperty("预约设备") private String reserveEquip; // 预约设备 - @ApiModelProperty("客户名称") - private String customerName; // 客户名称 - @ApiModelProperty("联系电话") - private String mobile; // 联系电话 - @ApiModelProperty("车牌号") - private String vehMark; // 车牌号 - @ApiModelProperty("车型") - private String vehModel; // 车型 private String remarks; - private String state; // 1未完成 0已完成 - } diff --git a/yxt-as/src/main/java/com/yxt/anrui/as/api/ascustomervehicle/AsCustomerCrmVehVo.java b/yxt-as/src/main/java/com/yxt/anrui/as/api/ascustomervehicle/AsCustomerCrmVehVo.java index 097d5827a6..6e544bc108 100644 --- a/yxt-as/src/main/java/com/yxt/anrui/as/api/ascustomervehicle/AsCustomerCrmVehVo.java +++ b/yxt-as/src/main/java/com/yxt/anrui/as/api/ascustomervehicle/AsCustomerCrmVehVo.java @@ -15,4 +15,10 @@ public class AsCustomerCrmVehVo implements Vo { private String customerSid; // 客户sid @ApiModelProperty("车牌号") private String vehMark; // 车牌号 + @ApiModelProperty("车架号") + private String vinNo; // 车架号 + @ApiModelProperty("车型sid") + private String vehModelSid; + @ApiModelProperty("车型") + private String vehModel; } diff --git a/yxt-as/src/main/java/com/yxt/anrui/as/api/enums/AsBillTypeEnum.java b/yxt-as/src/main/java/com/yxt/anrui/as/api/enums/AsBillTypeEnum.java index bd195db98f..a57be3f562 100644 --- a/yxt-as/src/main/java/com/yxt/anrui/as/api/enums/AsBillTypeEnum.java +++ b/yxt-as/src/main/java/com/yxt/anrui/as/api/enums/AsBillTypeEnum.java @@ -7,7 +7,8 @@ package com.yxt.anrui.as.api.enums; */ public enum AsBillTypeEnum { - WXGD("WXD", "维修工单"); + WXGD("WXD", "维修工单"), + YYD("YYD", "预约单"); diff --git a/yxt-as/src/main/java/com/yxt/anrui/as/biz/asbusreservebill/AsBusreserveBillMapper.java b/yxt-as/src/main/java/com/yxt/anrui/as/biz/asbusreservebill/AsBusreserveBillMapper.java index 8b84cffed0..36df67fd02 100644 --- a/yxt-as/src/main/java/com/yxt/anrui/as/biz/asbusreservebill/AsBusreserveBillMapper.java +++ b/yxt-as/src/main/java/com/yxt/anrui/as/biz/asbusreservebill/AsBusreserveBillMapper.java @@ -62,4 +62,6 @@ public interface AsBusreserveBillMapper extends BaseMapper { @Select("select * from as_busreserve_bill") List selectListVo(); + + int selectNum(String bill); } \ No newline at end of file diff --git a/yxt-as/src/main/java/com/yxt/anrui/as/biz/asbusreservebill/AsBusreserveBillMapper.xml b/yxt-as/src/main/java/com/yxt/anrui/as/biz/asbusreservebill/AsBusreserveBillMapper.xml index ae7e722634..b937e69acb 100644 --- a/yxt-as/src/main/java/com/yxt/anrui/as/biz/asbusreservebill/AsBusreserveBillMapper.xml +++ b/yxt-as/src/main/java/com/yxt/anrui/as/biz/asbusreservebill/AsBusreserveBillMapper.xml @@ -10,4 +10,9 @@ + \ No newline at end of file diff --git a/yxt-as/src/main/java/com/yxt/anrui/as/biz/asbusreservebill/AsBusreserveBillRest.java b/yxt-as/src/main/java/com/yxt/anrui/as/biz/asbusreservebill/AsBusreserveBillRest.java index 3af2a2f6d7..3a89b7fa23 100644 --- a/yxt-as/src/main/java/com/yxt/anrui/as/biz/asbusreservebill/AsBusreserveBillRest.java +++ b/yxt-as/src/main/java/com/yxt/anrui/as/biz/asbusreservebill/AsBusreserveBillRest.java @@ -100,4 +100,20 @@ public class AsBusreserveBillRest { AsBusreserveBillDetailsVo vo = asBusreserveBillService.fetchDetailsVoBySid(sid); return rb.success().setData(vo); } + + @ApiOperation("作废") + @PostMapping("/invalid") + public ResultBean invalid(@RequestParam("sid") String sid) { + ResultBean rb = ResultBean.fireFail(); + asBusreserveBillService.invalid(sid); + return rb.success(); + } + + @ApiOperation("保存跟踪记录") + @PostMapping("/saveTrackingRecord") + public ResultBean saveTrackingRecord(@RequestBody AsBusreserveBillDto dto) { + ResultBean rb = ResultBean.fireFail(); + asBusreserveBillService.saveTrackingRecord(dto); + return rb.success(); + } } diff --git a/yxt-as/src/main/java/com/yxt/anrui/as/biz/asbusreservebill/AsBusreserveBillService.java b/yxt-as/src/main/java/com/yxt/anrui/as/biz/asbusreservebill/AsBusreserveBillService.java index 1b690d6fc8..90410b1dac 100644 --- a/yxt-as/src/main/java/com/yxt/anrui/as/biz/asbusreservebill/AsBusreserveBillService.java +++ b/yxt-as/src/main/java/com/yxt/anrui/as/biz/asbusreservebill/AsBusreserveBillService.java @@ -26,11 +26,20 @@ package com.yxt.anrui.as.biz.asbusreservebill; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DateUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.yxt.anrui.as.api.asbusreservebill.*; import com.yxt.anrui.as.api.asbusreservebillsitem.AsBusreserveBillSitem; +import com.yxt.anrui.as.api.enums.AsBillTypeEnum; +import com.yxt.anrui.as.api.utils.AsRule; +import com.yxt.anrui.as.api.utils.domain.AsBillNo; import com.yxt.anrui.as.biz.asbusreservebillsitem.AsBusreserveBillSitemService; +import com.yxt.anrui.as.feign.portal.privilege.PrivilegeQuery; +import com.yxt.anrui.as.feign.portal.sysorganization.SysOrganizationFeign; +import com.yxt.anrui.as.feign.portal.sysorganization.SysOrganizationVo; +import com.yxt.anrui.as.feign.portal.sysstafforg.SysStaffOrgFeign; +import com.yxt.anrui.as.feign.portal.sysuser.SysUserFeign; import org.apache.commons.lang3.StringUtils; import com.yxt.common.base.service.MybatisBaseService; import com.yxt.common.base.utils.PagerUtil; @@ -64,14 +73,19 @@ public class AsBusreserveBillService extends MybatisBaseService createQueryWrapper(AsBusreserveBillQuery query) { // todo: 这里根据具体业务调整查询条件 // 多字段Like示例:qw.and(wrapper -> wrapper.like("name", query.getName()).or().like("remark", query.getName())); QueryWrapper qw = new QueryWrapper<>(); - if (StringUtils.isNotBlank(query.getUseOrgSid())) { - qw.eq("useOrgSid",query.getUseOrgSid()); - } +// if (StringUtils.isNotBlank(query.getUseOrgSid())) { +// qw.eq("useOrgSid",query.getUseOrgSid()); +// } if (StringUtils.isNotBlank(query.getState())) { qw.eq("state",query.getState()); } @@ -84,21 +98,116 @@ public class AsBusreserveBillService extends MybatisBaseService listPageVo(PagerQuery pq) { AsBusreserveBillQuery query = pq.getParams(); - QueryWrapper qw = createQueryWrapper(query); + QueryWrapper qw = new QueryWrapper<>(); + //========================================数据授权开始 + if (StringUtils.isNotBlank(query.getMenuUrl())) { + PrivilegeQuery privilegeQuery = new PrivilegeQuery(); + privilegeQuery.setOrgPath(query.getOrgPath()); + privilegeQuery.setMenuUrl(query.getMenuUrl()); + privilegeQuery.setUserSid(query.getUserSid()); + ResultBean defaultIdReltBean = sysUserFeign.selectPrivilegeLevel(privilegeQuery); + if (StringUtils.isNotBlank(defaultIdReltBean.getData())) { + //数据权限ID(1集团、2事业部、3分公司、4部门、5个人) + String orgSidPath = query.getOrgPath(); + orgSidPath = orgSidPath + "/"; + int i1 = orgSidPath.indexOf("/"); + int i2 = orgSidPath.indexOf("/", i1 + 1); + int i3 = orgSidPath.indexOf("/", i2 + 1); + int i4 = orgSidPath.indexOf("/", i3 + 1); + String orgLevelKey = defaultIdReltBean.getData(); + if ("1".equals(orgLevelKey)) { + orgSidPath = orgSidPath.substring(0, i1); + qw.like("orgSidPath", orgSidPath); + } else if ("2".equals(orgLevelKey)) { + orgSidPath = orgSidPath.substring(0, i2); + qw.like("orgSidPath", orgSidPath); + } else if ("3".equals(orgLevelKey)) { + orgSidPath = orgSidPath.substring(0, i3); + qw.like("orgSidPath", orgSidPath); + } else if ("4".equals(orgLevelKey)) { + orgSidPath = orgSidPath.substring(0, i4); + qw.like("orgSidPath", orgSidPath); + } else if ("5".equals(orgLevelKey)) { + qw.eq("createBySid", query.getUserSid()); + } else { + PagerVo p = new PagerVo<>(); + return p; + } + } else { + PagerVo p = new PagerVo<>(); + return p; + } + } + + if (StringUtils.isNotBlank(query.getState())) { + qw.eq("state",query.getState()); + } + if (StringUtils.isNotBlank(query.getUseOrgName())) { + qw.like("useOrgName",query.getUseOrgName()); + } + if (StringUtils.isNotBlank(query.getCreateDept())) { + qw.like("createDept",query.getCreateDept()); + } + if (StringUtils.isNotBlank(query.getCreateByName())) { + qw.like("createByName",query.getCreateByName()); + } + if (StringUtils.isNotBlank(query.getBillNo())) { + qw.like("billNo",query.getBillNo()); + } + + if (StringUtils.isNotBlank(query.getCustomerName())) { + qw.like("customerName",query.getCustomerName()); + } + if (StringUtils.isNotBlank(query.getVehMark())) { + qw.like("vehMark",query.getVehMark()); + } + + if (StringUtils.isNotBlank(query.getVinNo())) { + qw.like("vinNo",query.getVinNo()); + } + if (StringUtils.isNotBlank(query.getMobile())) { + qw.like("mobile",query.getMobile()); + } + String createStartTime = query.getStartCreateDate(); + String createEndTime = query.getEndCreateDate(); + qw.apply(StringUtils.isNotEmpty(createStartTime), "date_format (createTime,'%Y-%m-%d') >= date_format('" + createStartTime + "','%Y-%m-%d')"). + apply(StringUtils.isNotEmpty(createEndTime), "date_format (createTime,'%Y-%m-%d') <= date_format('" + createEndTime + "','%Y-%m-%d')" + ); + String startDate = query.getStartDate(); + String endDate = query.getEndDate(); + qw.apply(StringUtils.isNotEmpty(startDate), "date_format (reserveStart,'%Y-%m-%d') >= date_format('" + startDate + "','%Y-%m-%d')"). + apply(StringUtils.isNotEmpty(endDate), "date_format (reserveStart,'%Y-%m-%d') <= date_format('" + endDate + "','%Y-%m-%d')" + ); IPage page = PagerUtil.queryToPage(pq); IPage pagging = baseMapper.selectPageVo(page, qw); PagerVo p = PagerUtil.pageToVo(pagging, null); return p; } + /** + * 生成单据编号 + * + * @param orgSid + * @return + */ + public String getApplyCode(String orgSid) { + //获取分公司sid + ResultBean resultBean1 = sysOrganizationFeign.fetchBySid(orgSid); + String orgCode = resultBean1.getData().getOrgCode(); + AsBillNo b = new AsBillNo(); + b.setOrgCode(orgCode); + b.setBillType(AsBillTypeEnum.YYD.getBillType()); + String bill = AsRule.getBill(b); + int i = baseMapper.selectNum(bill); + String billNo = AsRule.getBillNo(bill, i); + return billNo; + } + public void saveOrUpdateDto(AsBusreserveBillDto dto) { String dtoSid = dto.getSid(); if (StringUtils.isNotBlank(dtoSid)) { @@ -118,6 +227,18 @@ public class AsBusreserveBillService extends MybatisBaseService orgSidByPath = sysStaffOrgFeign.getOrgSidByPath(orgPath); + if (orgSidByPath.getSuccess()) { + entity.setUseOrgSid(orgSidByPath.getData()); + entity.setCreateOrgSid(orgSidByPath.getData()); + SysOrganizationVo organizationVo = sysOrganizationFeign.fetchBySid(orgSidByPath.getData()).getData(); + entity.setCreateOrgName(organizationVo.getName()); + entity.setUseOrgName(organizationVo.getName()); + String applyCode = getApplyCode(orgSidByPath.getData()); + entity.setBillNo(applyCode); + } baseMapper.insert(entity); List sitemVos = dto.getSitemVos(); if (!sitemVos.isEmpty()) { @@ -151,23 +272,49 @@ public class AsBusreserveBillService extends MybatisBaseService sitemVos = new ArrayList<>(); - List asBusreserveBillSitems = asBusreserveBillSitemService.fetchByMainSid(sid); - if (!asBusreserveBillSitems.isEmpty()) { - for (AsBusreserveBillSitem asBusreserveBillSitem : asBusreserveBillSitems) { - AsbillSitemVo sitemVo = new AsbillSitemVo(); - BeanUtil.copyProperties(asBusreserveBillSitem, sitemVo); - sitemVos.add(sitemVo); + if (null != entity) { + BeanUtil.copyProperties(entity, vo); + vo.setCreateTime(DateUtil.formatDate(entity.getCreateTime())); + if (StringUtils.isNotBlank(entity.getOrgSidPath())) { + vo.setOrgPath(entity.getOrgSidPath()); + } + if (null != entity.getReserveStart()) { + vo.setReserveStart(sdf.format(entity.getReserveStart())); + } + if (null != entity.getReserveEnd()) { + vo.setReserveEnd(sdf.format(entity.getReserveEnd())); + } + List sitemVos = new ArrayList<>(); + List asBusreserveBillSitems = asBusreserveBillSitemService.fetchByMainSid(sid); + if (!asBusreserveBillSitems.isEmpty()) { + for (AsBusreserveBillSitem asBusreserveBillSitem : asBusreserveBillSitems) { + AsbillSitemVo sitemVo = new AsbillSitemVo(); + BeanUtil.copyProperties(asBusreserveBillSitem, sitemVo); + sitemVos.add(sitemVo); + } + vo.setSitemVos(sitemVos); } - vo.setSitemVos(sitemVos); } return vo; } + + public void invalid(String sid) { + AsBusreserveBill bill = fetchBySid(sid); + if (null != bill) { + bill.setState(2); + baseMapper.updateById(bill); + } + } + + public void saveTrackingRecord(AsBusreserveBillDto dto) { + if (StringUtils.isNotBlank(dto.getSid())) { + AsBusreserveBill bill = fetchBySid(dto.getSid()); + if (null != bill) { + if (StringUtils.isNotBlank(dto.getTrackLogs())) { + bill.setTrackLogs(dto.getTrackLogs()); + } + baseMapper.updateById(bill); + } + } + } } \ No newline at end of file