7 changed files with 920 additions and 0 deletions
-
80src/main/java/com/xujie/sys/modules/pms/controller/PartSparePurchaseImportController.java
-
69src/main/java/com/xujie/sys/modules/pms/data/PartSparePurchaseImportQueryData.java
-
109src/main/java/com/xujie/sys/modules/pms/entity/PartSparePurchaseImportEntity.java
-
22src/main/java/com/xujie/sys/modules/pms/mapper/PartSparePurchaseImportMapper.java
-
497src/main/java/com/xujie/sys/modules/pms/service/Impl/PartSparePurchaseImportServiceImpl.java
-
28src/main/java/com/xujie/sys/modules/pms/service/PartSparePurchaseImportService.java
-
115src/main/resources/mapper/pms/PartSparePurchaseImportMapper.xml
@ -0,0 +1,80 @@ |
|||
package com.xujie.sys.modules.pms.controller; |
|||
|
|||
import com.xujie.sys.common.utils.PageUtils; |
|||
import com.xujie.sys.common.utils.R; |
|||
import com.xujie.sys.modules.pms.data.PartSparePurchaseImportQueryData; |
|||
import com.xujie.sys.modules.pms.entity.PartSparePurchaseImportEntity; |
|||
import com.xujie.sys.modules.pms.service.PartSparePurchaseImportService; |
|||
import jakarta.servlet.http.HttpServletResponse; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
@Slf4j |
|||
@RestController |
|||
@RequestMapping("/pms/partspare/purchaseImport") |
|||
public class PartSparePurchaseImportController { |
|||
|
|||
@Autowired |
|||
private PartSparePurchaseImportService partSparePurchaseImportService; |
|||
|
|||
@PostMapping("/queryPage") |
|||
public R queryPage(@RequestBody PartSparePurchaseImportQueryData data) { |
|||
PageUtils page = partSparePurchaseImportService.queryPage(data); |
|||
return R.ok() |
|||
.put("page", page) |
|||
.put("summary", partSparePurchaseImportService.querySummary(data)); |
|||
} |
|||
|
|||
@PostMapping("/save") |
|||
public R save(@RequestBody PartSparePurchaseImportEntity data) { |
|||
partSparePurchaseImportService.saveData(data); |
|||
return R.ok("保存成功"); |
|||
} |
|||
|
|||
@PostMapping("/update") |
|||
public R update(@RequestBody PartSparePurchaseImportEntity data) { |
|||
partSparePurchaseImportService.updateData(data); |
|||
return R.ok("修改成功"); |
|||
} |
|||
|
|||
@PostMapping("/delete") |
|||
public R delete(@RequestBody Object[] ids) { |
|||
if (ids == null || ids.length == 0) { |
|||
return R.error("请先选择需要删除的数据"); |
|||
} |
|||
List<Long> idList = new ArrayList<>(); |
|||
for (Object id : ids) { |
|||
if (id == null) { |
|||
continue; |
|||
} |
|||
try { |
|||
idList.add(Long.parseLong(String.valueOf(id))); |
|||
} catch (Exception e) { |
|||
return R.error("删除参数错误,ID格式无效"); |
|||
} |
|||
} |
|||
if (idList.isEmpty()) { |
|||
return R.error("请先选择需要删除的数据"); |
|||
} |
|||
partSparePurchaseImportService.deleteData(idList.toArray(new Long[0])); |
|||
return R.ok("删除成功"); |
|||
} |
|||
|
|||
@PostMapping("/importExcel") |
|||
public R importExcel(@RequestParam("file") MultipartFile file, |
|||
@RequestParam("site") String site, |
|||
@RequestParam("buNo") String buNo) { |
|||
int count = partSparePurchaseImportService.importExcel(file, site, buNo); |
|||
return R.ok("导入成功").put("count", count); |
|||
} |
|||
|
|||
@GetMapping("/downloadTemplate") |
|||
public void downloadTemplate(HttpServletResponse response) { |
|||
partSparePurchaseImportService.downloadTemplate(response); |
|||
} |
|||
} |
|||
@ -0,0 +1,69 @@ |
|||
package com.xujie.sys.modules.pms.data; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonFormat; |
|||
import lombok.Data; |
|||
import org.springframework.format.annotation.DateTimeFormat; |
|||
|
|||
import java.math.BigDecimal; |
|||
import java.util.Date; |
|||
|
|||
/** |
|||
* 备件采购订单导入记录查询条件 |
|||
*/ |
|||
@Data |
|||
public class PartSparePurchaseImportQueryData { |
|||
|
|||
private String username; |
|||
|
|||
private String site; |
|||
|
|||
private String buNo; |
|||
|
|||
private String supplierName; |
|||
|
|||
private String currencyType; |
|||
|
|||
private String orderNo; |
|||
|
|||
private String itemCode; |
|||
|
|||
private String itemName; |
|||
|
|||
private String projectBu; |
|||
|
|||
private String requestNo; |
|||
|
|||
private String requestBy; |
|||
|
|||
private String importBy; |
|||
|
|||
private String sourceFileName; |
|||
|
|||
@DateTimeFormat(pattern = "yyyy-MM-dd") |
|||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") |
|||
private Date orderDateStart; |
|||
|
|||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
|||
private Date orderDateEnd; |
|||
|
|||
@DateTimeFormat(pattern = "yyyy-MM-dd") |
|||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") |
|||
private Date importDateStart; |
|||
|
|||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
|||
private Date importDateEnd; |
|||
|
|||
private BigDecimal qtyStart; |
|||
|
|||
private BigDecimal qtyEnd; |
|||
|
|||
private BigDecimal localTotalAmountStart; |
|||
|
|||
private BigDecimal localTotalAmountEnd; |
|||
|
|||
private Integer page = 1; |
|||
|
|||
private Integer limit = 20; |
|||
} |
|||
@ -0,0 +1,109 @@ |
|||
package com.xujie.sys.modules.pms.entity; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.IdType; |
|||
import com.baomidou.mybatisplus.annotation.TableField; |
|||
import com.baomidou.mybatisplus.annotation.TableId; |
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import com.fasterxml.jackson.annotation.JsonFormat; |
|||
import com.fasterxml.jackson.databind.annotation.JsonSerialize; |
|||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; |
|||
import lombok.Data; |
|||
import org.springframework.format.annotation.DateTimeFormat; |
|||
|
|||
import java.math.BigDecimal; |
|||
import java.util.Date; |
|||
|
|||
/** |
|||
* 备件采购订单导入记录实体 |
|||
*/ |
|||
@Data |
|||
@TableName("part_spare_purchase_import") |
|||
public class PartSparePurchaseImportEntity { |
|||
|
|||
@TableId(type = IdType.ASSIGN_ID) |
|||
@JsonSerialize(using = ToStringSerializer.class) |
|||
private Long id; |
|||
|
|||
private String site; |
|||
|
|||
@TableField("bu_no") |
|||
private String buNo; |
|||
|
|||
@TableField("order_date") |
|||
@DateTimeFormat(pattern = "yyyy-MM-dd") |
|||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") |
|||
private Date orderDate; |
|||
|
|||
@TableField("supplier_name") |
|||
private String supplierName; |
|||
|
|||
@TableField("currency_type") |
|||
private String currencyType; |
|||
|
|||
@TableField("order_no") |
|||
private String orderNo; |
|||
|
|||
@TableField("item_code") |
|||
private String itemCode; |
|||
|
|||
@TableField("item_name") |
|||
private String itemName; |
|||
|
|||
private BigDecimal qty; |
|||
|
|||
@TableField("local_unit_price") |
|||
private BigDecimal localUnitPrice; |
|||
|
|||
@TableField("local_amount") |
|||
private BigDecimal localAmount; |
|||
|
|||
@TableField("local_tax_amount") |
|||
private BigDecimal localTaxAmount; |
|||
|
|||
@TableField("local_total_amount") |
|||
private BigDecimal localTotalAmount; |
|||
|
|||
@TableField("unit_name") |
|||
private String unitName; |
|||
|
|||
@TableField("project_bu") |
|||
private String projectBu; |
|||
|
|||
@TableField("request_no") |
|||
private String requestNo; |
|||
|
|||
@TableField("request_by") |
|||
private String requestBy; |
|||
|
|||
@TableField("import_date") |
|||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
|||
private Date importDate; |
|||
|
|||
@TableField("import_by") |
|||
private String importBy; |
|||
|
|||
@TableField("source_file_name") |
|||
private String sourceFileName; |
|||
|
|||
private String remark; |
|||
|
|||
@TableField("created_by") |
|||
private String createdBy; |
|||
|
|||
@TableField("created_date") |
|||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
|||
private Date createdDate; |
|||
|
|||
@TableField("updated_by") |
|||
private String updatedBy; |
|||
|
|||
@TableField("updated_date") |
|||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
|||
private Date updatedDate; |
|||
|
|||
@TableField("is_deleted") |
|||
private String isDeleted; |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
package com.xujie.sys.modules.pms.mapper; |
|||
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|||
import com.baomidou.mybatisplus.core.metadata.IPage; |
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import com.xujie.sys.modules.pms.data.PartSparePurchaseImportQueryData; |
|||
import com.xujie.sys.modules.pms.entity.PartSparePurchaseImportEntity; |
|||
import org.apache.ibatis.annotations.Mapper; |
|||
import org.apache.ibatis.annotations.Param; |
|||
|
|||
import java.util.Map; |
|||
|
|||
@Mapper |
|||
public interface PartSparePurchaseImportMapper extends BaseMapper<PartSparePurchaseImportEntity> { |
|||
|
|||
IPage<PartSparePurchaseImportEntity> queryPage( |
|||
Page<PartSparePurchaseImportEntity> page, |
|||
@Param("query") PartSparePurchaseImportQueryData query |
|||
); |
|||
|
|||
Map<String, Object> querySummary(@Param("query") PartSparePurchaseImportQueryData query); |
|||
} |
|||
@ -0,0 +1,497 @@ |
|||
package com.xujie.sys.modules.pms.service.Impl; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.core.metadata.IPage; |
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|||
import com.xujie.sys.common.utils.PageUtils; |
|||
import com.xujie.sys.modules.pms.data.PartSparePurchaseImportQueryData; |
|||
import com.xujie.sys.modules.pms.entity.PartSparePurchaseImportEntity; |
|||
import com.xujie.sys.modules.pms.mapper.PartSparePurchaseImportMapper; |
|||
import com.xujie.sys.modules.pms.service.PartSparePurchaseImportService; |
|||
import com.xujie.sys.modules.sys.entity.SysUserEntity; |
|||
import jakarta.servlet.http.HttpServletResponse; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.poi.ss.usermodel.*; |
|||
import org.apache.poi.xssf.usermodel.XSSFWorkbook; |
|||
import org.apache.shiro.SecurityUtils; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.transaction.annotation.Transactional; |
|||
import org.springframework.util.StringUtils; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
import java.io.IOException; |
|||
import java.net.URLEncoder; |
|||
import java.math.BigDecimal; |
|||
import java.time.LocalDate; |
|||
import java.time.LocalDateTime; |
|||
import java.time.ZoneId; |
|||
import java.time.format.DateTimeFormatter; |
|||
import java.time.format.DateTimeFormatterBuilder; |
|||
import java.time.format.DateTimeParseException; |
|||
import java.time.temporal.TemporalAccessor; |
|||
import java.util.*; |
|||
|
|||
@Slf4j |
|||
@Service |
|||
public class PartSparePurchaseImportServiceImpl extends ServiceImpl<PartSparePurchaseImportMapper, PartSparePurchaseImportEntity> |
|||
implements PartSparePurchaseImportService { |
|||
|
|||
private static final int IMPORT_BATCH_SIZE = 100; |
|||
|
|||
@Override |
|||
public PageUtils queryPage(PartSparePurchaseImportQueryData queryData) { |
|||
queryData.setUsername(getCurrentUsername()); |
|||
queryData.setBuNo(normalizeBuNo(queryData.getSite(), queryData.getBuNo())); |
|||
long pageNo = queryData.getPage() == null || queryData.getPage() < 1 ? 1 : queryData.getPage(); |
|||
long pageSize = queryData.getLimit() == null || queryData.getLimit() < 1 ? 20 : queryData.getLimit(); |
|||
IPage<PartSparePurchaseImportEntity> page = baseMapper.queryPage( |
|||
new Page<>(pageNo, pageSize), |
|||
queryData |
|||
); |
|||
return new PageUtils(page); |
|||
} |
|||
|
|||
@Override |
|||
public Map<String, BigDecimal> querySummary(PartSparePurchaseImportQueryData queryData) { |
|||
queryData.setUsername(getCurrentUsername()); |
|||
queryData.setBuNo(normalizeBuNo(queryData.getSite(), queryData.getBuNo())); |
|||
Map<String, Object> summary = baseMapper.querySummary(queryData); |
|||
Map<String, BigDecimal> result = new HashMap<>(2); |
|||
result.put("totalQty", toBigDecimal(summary == null ? null : summary.get("totalQty"))); |
|||
result.put("totalLocalTotalAmount", toBigDecimal(summary == null ? null : summary.get("totalLocalTotalAmount"))); |
|||
return result; |
|||
} |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void saveData(PartSparePurchaseImportEntity data) { |
|||
data.setBuNo(normalizeBuNo(data.getSite(), data.getBuNo())); |
|||
validateBaseData(data); |
|||
String username = getCurrentUsername(); |
|||
Date now = new Date(); |
|||
data.setId(null); |
|||
data.setImportDate(now); |
|||
data.setImportBy(username); |
|||
data.setCreatedBy(username); |
|||
data.setCreatedDate(now); |
|||
data.setUpdatedBy(username); |
|||
data.setUpdatedDate(now); |
|||
data.setIsDeleted("0"); |
|||
this.save(data); |
|||
} |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void updateData(PartSparePurchaseImportEntity data) { |
|||
if (data.getId() == null) { |
|||
throw new RuntimeException("参数错误:记录ID不能为空"); |
|||
} |
|||
data.setBuNo(normalizeBuNo(data.getSite(), data.getBuNo())); |
|||
validateBaseData(data); |
|||
PartSparePurchaseImportEntity dbData = this.getOne( |
|||
new LambdaQueryWrapper<PartSparePurchaseImportEntity>() |
|||
.eq(PartSparePurchaseImportEntity::getId, data.getId()) |
|||
.eq(PartSparePurchaseImportEntity::getIsDeleted, "0") |
|||
); |
|||
if (dbData == null) { |
|||
throw new RuntimeException("记录不存在或已删除,请刷新后重试"); |
|||
} |
|||
|
|||
dbData.setSite(data.getSite()); |
|||
dbData.setBuNo(data.getBuNo()); |
|||
dbData.setOrderDate(data.getOrderDate()); |
|||
dbData.setSupplierName(data.getSupplierName()); |
|||
dbData.setCurrencyType(data.getCurrencyType()); |
|||
dbData.setOrderNo(data.getOrderNo()); |
|||
dbData.setItemCode(data.getItemCode()); |
|||
dbData.setItemName(data.getItemName()); |
|||
dbData.setQty(data.getQty()); |
|||
dbData.setLocalUnitPrice(data.getLocalUnitPrice()); |
|||
dbData.setLocalAmount(data.getLocalAmount()); |
|||
dbData.setLocalTaxAmount(data.getLocalTaxAmount()); |
|||
dbData.setLocalTotalAmount(data.getLocalTotalAmount()); |
|||
dbData.setUnitName(data.getUnitName()); |
|||
dbData.setProjectBu(data.getProjectBu()); |
|||
dbData.setRequestNo(data.getRequestNo()); |
|||
dbData.setRequestBy(data.getRequestBy()); |
|||
dbData.setRemark(data.getRemark()); |
|||
dbData.setUpdatedBy(getCurrentUsername()); |
|||
dbData.setUpdatedDate(new Date()); |
|||
this.updateById(dbData); |
|||
} |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void deleteData(Long[] ids) { |
|||
if (ids == null || ids.length == 0) { |
|||
throw new RuntimeException("请先选择需要删除的数据"); |
|||
} |
|||
List<Long> idList = Arrays.asList(ids); |
|||
long existsCount = this.lambdaQuery() |
|||
.in(PartSparePurchaseImportEntity::getId, idList) |
|||
.count(); |
|||
if (existsCount == 0) { |
|||
throw new RuntimeException("记录不存在或已删除,请刷新后重试"); |
|||
} |
|||
boolean success = this.removeByIds(idList); |
|||
if (!success) { |
|||
throw new RuntimeException("删除失败,请稍后重试"); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public int importExcel(MultipartFile file, String site, String buNo) { |
|||
if (!StringUtils.hasText(site)) { |
|||
throw new RuntimeException("工厂不能为空"); |
|||
} |
|||
String normalizedBuNo = normalizeBuNo(site, buNo); |
|||
if (!StringUtils.hasText(normalizedBuNo)) { |
|||
throw new RuntimeException("BU不能为空"); |
|||
} |
|||
if (file == null || file.isEmpty()) { |
|||
throw new RuntimeException("上传文件不能为空"); |
|||
} |
|||
String fileName = file.getOriginalFilename(); |
|||
if (!StringUtils.hasText(fileName)) { |
|||
throw new RuntimeException("上传文件名不能为空"); |
|||
} |
|||
String lowerName = fileName.toLowerCase(); |
|||
if (!lowerName.endsWith(".xlsx") && !lowerName.endsWith(".xls")) { |
|||
throw new RuntimeException("请上传Excel文件(.xlsx 或 .xls)"); |
|||
} |
|||
|
|||
String username = getCurrentUsername(); |
|||
Date importTime = new Date(); |
|||
List<PartSparePurchaseImportEntity> rows = parseExcel(file, site, normalizedBuNo, fileName, username, importTime); |
|||
if (rows.isEmpty()) { |
|||
throw new RuntimeException("未读取到有效导入数据"); |
|||
} |
|||
this.saveBatch(rows, IMPORT_BATCH_SIZE); |
|||
return rows.size(); |
|||
} |
|||
|
|||
@Override |
|||
public void downloadTemplate(HttpServletResponse response) { |
|||
try (Workbook workbook = new XSSFWorkbook()) { |
|||
Sheet sheet = workbook.createSheet("采购订单导入"); |
|||
Row header = sheet.createRow(0); |
|||
String[] headers = { |
|||
"日期", "供应商", "币种", "订单编号", "存货编码", "存货名称", "数量", |
|||
"本币单价", "本币金额", "本币税额", "本币价税合计", "单位", |
|||
"项目目录(BU)", "请单编号", "请购员" |
|||
}; |
|||
for (int i = 0; i < headers.length; i++) { |
|||
Cell cell = header.createCell(i); |
|||
cell.setCellValue(headers[i]); |
|||
sheet.setColumnWidth(i, 18 * 256); |
|||
} |
|||
|
|||
Row sample = sheet.createRow(1); |
|||
sample.createCell(0).setCellValue("2026-04-02"); |
|||
sample.createCell(1).setCellValue("南海发展工程有限公司"); |
|||
sample.createCell(2).setCellValue("人民币"); |
|||
sample.createCell(3).setCellValue("CPMFL2026040019"); |
|||
sample.createCell(4).setCellValue("401.000000"); |
|||
sample.createCell(5).setCellValue("叉车手柄切片"); |
|||
sample.createCell(6).setCellValue("3"); |
|||
sample.createCell(7).setCellValue("1"); |
|||
sample.createCell(8).setCellValue("3"); |
|||
sample.createCell(9).setCellValue("0.39"); |
|||
sample.createCell(10).setCellValue("3.39"); |
|||
sample.createCell(11).setCellValue("起"); |
|||
sample.createCell(12).setCellValue("39"); |
|||
sample.createCell(13).setCellValue("CPMFL2026040019"); |
|||
sample.createCell(14).setCellValue("段晓浩"); |
|||
|
|||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); |
|||
response.setCharacterEncoding("UTF-8"); |
|||
response.setHeader( |
|||
"Content-Disposition", |
|||
"attachment;filename=" + URLEncoder.encode("采购订单导入模板.xlsx", "UTF-8") |
|||
); |
|||
workbook.write(response.getOutputStream()); |
|||
response.flushBuffer(); |
|||
} catch (Exception e) { |
|||
log.error("下载采购订单导入模板失败: {}", e.getMessage(), e); |
|||
throw new RuntimeException("下载模板失败: " + e.getMessage()); |
|||
} |
|||
} |
|||
|
|||
private List<PartSparePurchaseImportEntity> parseExcel( |
|||
MultipartFile file, |
|||
String site, |
|||
String buNo, |
|||
String sourceFileName, |
|||
String username, |
|||
Date importTime |
|||
) { |
|||
List<PartSparePurchaseImportEntity> result = new ArrayList<>(); |
|||
DataFormatter formatter = new DataFormatter(); |
|||
try (Workbook workbook = WorkbookFactory.create(file.getInputStream())) { |
|||
Sheet sheet = workbook.getSheetAt(0); |
|||
if (sheet == null) { |
|||
return result; |
|||
} |
|||
Row headerRow = sheet.getRow(0); |
|||
Map<String, Integer> headerMap = buildHeaderMap(headerRow, formatter); |
|||
HeaderIndex index = resolveHeaderIndex(headerMap); |
|||
|
|||
for (int i = 1; i <= sheet.getLastRowNum(); i++) { |
|||
Row row = sheet.getRow(i); |
|||
if (row == null || isEmptyRow(row, formatter)) { |
|||
continue; |
|||
} |
|||
PartSparePurchaseImportEntity entity = new PartSparePurchaseImportEntity(); |
|||
entity.setSite(site); |
|||
entity.setBuNo(buNo); |
|||
entity.setOrderDate(parseDateCell(row.getCell(index.orderDate), formatter)); |
|||
entity.setSupplierName(getCellString(row.getCell(index.supplierName), formatter)); |
|||
entity.setCurrencyType(getCellString(row.getCell(index.currencyType), formatter)); |
|||
entity.setOrderNo(getCellString(row.getCell(index.orderNo), formatter)); |
|||
entity.setItemCode(getCellString(row.getCell(index.itemCode), formatter)); |
|||
entity.setItemName(getCellString(row.getCell(index.itemName), formatter)); |
|||
entity.setQty(parseDecimal(row.getCell(index.qty), formatter)); |
|||
entity.setLocalUnitPrice(parseDecimal(row.getCell(index.localUnitPrice), formatter)); |
|||
entity.setLocalAmount(parseDecimal(row.getCell(index.localAmount), formatter)); |
|||
entity.setLocalTaxAmount(parseDecimal(row.getCell(index.localTaxAmount), formatter)); |
|||
entity.setLocalTotalAmount(parseDecimal(row.getCell(index.localTotalAmount), formatter)); |
|||
entity.setUnitName(getCellString(row.getCell(index.unitName), formatter)); |
|||
entity.setProjectBu(getCellString(row.getCell(index.projectBu), formatter)); |
|||
entity.setRequestNo(getCellString(row.getCell(index.requestNo), formatter)); |
|||
entity.setRequestBy(getCellString(row.getCell(index.requestBy), formatter)); |
|||
entity.setImportDate(importTime); |
|||
entity.setImportBy(username); |
|||
entity.setSourceFileName(sourceFileName); |
|||
entity.setCreatedBy(username); |
|||
entity.setCreatedDate(importTime); |
|||
entity.setUpdatedBy(username); |
|||
entity.setUpdatedDate(importTime); |
|||
entity.setIsDeleted("0"); |
|||
|
|||
// 至少有订单编号或存货编码才作为有效行 |
|||
if (!StringUtils.hasText(entity.getOrderNo()) && !StringUtils.hasText(entity.getItemCode())) { |
|||
continue; |
|||
} |
|||
validateBaseData(entity); |
|||
result.add(entity); |
|||
} |
|||
} catch (IOException e) { |
|||
throw new RuntimeException("解析Excel失败: " + e.getMessage()); |
|||
} catch (Exception e) { |
|||
throw new RuntimeException("导入失败: " + e.getMessage()); |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
private Map<String, Integer> buildHeaderMap(Row headerRow, DataFormatter formatter) { |
|||
Map<String, Integer> headerMap = new HashMap<>(); |
|||
if (headerRow == null) { |
|||
return headerMap; |
|||
} |
|||
for (int i = 0; i < headerRow.getLastCellNum(); i++) { |
|||
String value = normalizeHeader(getCellString(headerRow.getCell(i), formatter)); |
|||
if (StringUtils.hasText(value)) { |
|||
headerMap.put(value, i); |
|||
} |
|||
} |
|||
return headerMap; |
|||
} |
|||
|
|||
private HeaderIndex resolveHeaderIndex(Map<String, Integer> headerMap) { |
|||
HeaderIndex index = new HeaderIndex(); |
|||
index.orderDate = resolveColumn(headerMap, 1, "日期", "订单日期"); |
|||
index.supplierName = resolveColumn(headerMap, 2, "供应商", "供应商名称"); |
|||
index.currencyType = resolveColumn(headerMap, 3, "币种"); |
|||
index.orderNo = resolveColumn(headerMap, 4, "订单编号", "采购订单号"); |
|||
index.itemCode = resolveColumn(headerMap, 5, "存货编码", "物料编码"); |
|||
index.itemName = resolveColumn(headerMap, 6, "存货名称", "物料名称"); |
|||
index.qty = resolveColumn(headerMap, 7, "数量", "订单数量"); |
|||
index.localUnitPrice = resolveColumn(headerMap, 8, "本币单价"); |
|||
index.localAmount = resolveColumn(headerMap, 9, "本币金额"); |
|||
index.localTaxAmount = resolveColumn(headerMap, 10, "本币税额"); |
|||
index.localTotalAmount = resolveColumn(headerMap, 11, "本币价税合计"); |
|||
index.unitName = resolveColumn(headerMap, 12, "单位"); |
|||
index.projectBu = resolveColumn(headerMap, 13, "项目目录(bu)", "项目目录(bu)", "项目目录bu", "项目目录"); |
|||
index.requestNo = resolveColumn(headerMap, 14, "请单编号", "请购单号", "请购编号"); |
|||
index.requestBy = resolveColumn(headerMap, 15, "请购员", "请购人", "采购员"); |
|||
return index; |
|||
} |
|||
|
|||
private Integer resolveColumn(Map<String, Integer> headerMap, int fallbackIndex, String... aliases) { |
|||
for (String alias : aliases) { |
|||
Integer index = headerMap.get(normalizeHeader(alias)); |
|||
if (index != null) { |
|||
return index; |
|||
} |
|||
} |
|||
return fallbackIndex; |
|||
} |
|||
|
|||
private String normalizeHeader(String header) { |
|||
if (!StringUtils.hasText(header)) { |
|||
return ""; |
|||
} |
|||
return header.trim() |
|||
.replace("(", "(") |
|||
.replace(")", ")") |
|||
.replace(" ", "") |
|||
.toLowerCase(); |
|||
} |
|||
|
|||
private boolean isEmptyRow(Row row, DataFormatter formatter) { |
|||
int cells = row.getLastCellNum(); |
|||
for (int i = 0; i < cells; i++) { |
|||
if (StringUtils.hasText(getCellString(row.getCell(i), formatter))) { |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
private String getCellString(Cell cell, DataFormatter formatter) { |
|||
if (cell == null) { |
|||
return ""; |
|||
} |
|||
return formatter.formatCellValue(cell).trim(); |
|||
} |
|||
|
|||
private BigDecimal parseDecimal(Cell cell, DataFormatter formatter) { |
|||
String value = getCellString(cell, formatter); |
|||
if (!StringUtils.hasText(value)) { |
|||
return null; |
|||
} |
|||
String normalized = value.replace(",", "").replace(" ", ""); |
|||
if (!StringUtils.hasText(normalized)) { |
|||
return null; |
|||
} |
|||
try { |
|||
return new BigDecimal(normalized); |
|||
} catch (Exception e) { |
|||
throw new RuntimeException("数值格式错误: " + value); |
|||
} |
|||
} |
|||
|
|||
private Date parseDateCell(Cell cell, DataFormatter formatter) { |
|||
if (cell == null) { |
|||
return null; |
|||
} |
|||
if (cell.getCellType() == CellType.NUMERIC && DateUtil.isCellDateFormatted(cell)) { |
|||
return cell.getDateCellValue(); |
|||
} |
|||
String value = getCellString(cell, formatter); |
|||
if (!StringUtils.hasText(value)) { |
|||
return null; |
|||
} |
|||
return parseDateString(value); |
|||
} |
|||
|
|||
private Date parseDateString(String value) { |
|||
List<DateTimeFormatter> formatters = Arrays.asList( |
|||
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"), |
|||
DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"), |
|||
DateTimeFormatter.ofPattern("yyyy-MM-dd"), |
|||
DateTimeFormatter.ofPattern("yyyy/MM/dd"), |
|||
DateTimeFormatter.ofPattern("yyyyMMdd"), |
|||
new DateTimeFormatterBuilder() |
|||
.appendOptional(DateTimeFormatter.ofPattern("yyyy-M-d")) |
|||
.appendOptional(DateTimeFormatter.ofPattern("yyyy/M/d")) |
|||
.toFormatter() |
|||
); |
|||
for (DateTimeFormatter formatter : formatters) { |
|||
try { |
|||
TemporalAccessor accessor = formatter.parseBest(value, LocalDateTime::from, LocalDate::from); |
|||
if (accessor instanceof LocalDateTime) { |
|||
return Date.from(((LocalDateTime) accessor).atZone(ZoneId.systemDefault()).toInstant()); |
|||
} |
|||
if (accessor instanceof LocalDate) { |
|||
return Date.from(((LocalDate) accessor).atStartOfDay(ZoneId.systemDefault()).toInstant()); |
|||
} |
|||
} catch (DateTimeParseException ignored) { |
|||
} |
|||
} |
|||
throw new RuntimeException("日期格式错误: " + value); |
|||
} |
|||
|
|||
private BigDecimal toBigDecimal(Object value) { |
|||
if (value == null) { |
|||
return BigDecimal.ZERO; |
|||
} |
|||
if (value instanceof BigDecimal) { |
|||
return (BigDecimal) value; |
|||
} |
|||
if (value instanceof Number) { |
|||
return new BigDecimal(value.toString()); |
|||
} |
|||
String text = value.toString(); |
|||
if (!StringUtils.hasText(text)) { |
|||
return BigDecimal.ZERO; |
|||
} |
|||
try { |
|||
return new BigDecimal(text.trim()); |
|||
} catch (Exception e) { |
|||
return BigDecimal.ZERO; |
|||
} |
|||
} |
|||
|
|||
private String normalizeBuNo(String site, String buNo) { |
|||
if (!StringUtils.hasText(buNo)) { |
|||
return buNo; |
|||
} |
|||
String siteText = StringUtils.hasText(site) ? site.trim() : ""; |
|||
String buText = buNo.trim(); |
|||
if (!StringUtils.hasText(siteText)) { |
|||
return buText; |
|||
} |
|||
String prefix = siteText + "_"; |
|||
if (buText.startsWith(prefix)) { |
|||
return buText.substring(prefix.length()); |
|||
} |
|||
return buText; |
|||
} |
|||
|
|||
private void validateBaseData(PartSparePurchaseImportEntity data) { |
|||
if (!StringUtils.hasText(data.getSite())) { |
|||
throw new RuntimeException("工厂不能为空"); |
|||
} |
|||
if (!StringUtils.hasText(data.getBuNo())) { |
|||
throw new RuntimeException("BU不能为空"); |
|||
} |
|||
if (!StringUtils.hasText(data.getOrderNo())) { |
|||
throw new RuntimeException("订单编号不能为空"); |
|||
} |
|||
if (!StringUtils.hasText(data.getItemCode())) { |
|||
throw new RuntimeException("存货编码不能为空"); |
|||
} |
|||
if (data.getQty() != null && data.getQty().compareTo(BigDecimal.ZERO) < 0) { |
|||
throw new RuntimeException("数量不能小于0"); |
|||
} |
|||
} |
|||
|
|||
private String getCurrentUsername() { |
|||
Object principal = SecurityUtils.getSubject().getPrincipal(); |
|||
if (principal instanceof SysUserEntity) { |
|||
return ((SysUserEntity) principal).getUsername(); |
|||
} |
|||
return "system"; |
|||
} |
|||
|
|||
private static class HeaderIndex { |
|||
private Integer orderDate; |
|||
private Integer supplierName; |
|||
private Integer currencyType; |
|||
private Integer orderNo; |
|||
private Integer itemCode; |
|||
private Integer itemName; |
|||
private Integer qty; |
|||
private Integer localUnitPrice; |
|||
private Integer localAmount; |
|||
private Integer localTaxAmount; |
|||
private Integer localTotalAmount; |
|||
private Integer unitName; |
|||
private Integer projectBu; |
|||
private Integer requestNo; |
|||
private Integer requestBy; |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package com.xujie.sys.modules.pms.service; |
|||
|
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.xujie.sys.common.utils.PageUtils; |
|||
import com.xujie.sys.modules.pms.data.PartSparePurchaseImportQueryData; |
|||
import com.xujie.sys.modules.pms.entity.PartSparePurchaseImportEntity; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
import jakarta.servlet.http.HttpServletResponse; |
|||
import java.math.BigDecimal; |
|||
import java.util.Map; |
|||
|
|||
public interface PartSparePurchaseImportService extends IService<PartSparePurchaseImportEntity> { |
|||
|
|||
PageUtils queryPage(PartSparePurchaseImportQueryData queryData); |
|||
|
|||
Map<String, BigDecimal> querySummary(PartSparePurchaseImportQueryData queryData); |
|||
|
|||
void saveData(PartSparePurchaseImportEntity data); |
|||
|
|||
void updateData(PartSparePurchaseImportEntity data); |
|||
|
|||
void deleteData(Long[] ids); |
|||
|
|||
int importExcel(MultipartFile file, String site, String buNo); |
|||
|
|||
void downloadTemplate(HttpServletResponse response); |
|||
} |
|||
@ -0,0 +1,115 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
|||
<mapper namespace="com.xujie.sys.modules.pms.mapper.PartSparePurchaseImportMapper"> |
|||
|
|||
<sql id="queryWhereClause"> |
|||
<where> |
|||
a.is_deleted = '0' |
|||
and a.site in (select site from eam_access_site where username = #{query.username}) |
|||
and (a.site + '-' + a.bu_no) in (select * from dbo.query_bu(#{query.username})) |
|||
<if test="query.site != null and query.site != ''"> |
|||
and a.site = #{query.site} |
|||
</if> |
|||
<if test="query.buNo != null and query.buNo != ''"> |
|||
and a.bu_no = #{query.buNo} |
|||
</if> |
|||
<if test="query.supplierName != null and query.supplierName != ''"> |
|||
and a.supplier_name like '%' + #{query.supplierName} + '%' |
|||
</if> |
|||
<if test="query.currencyType != null and query.currencyType != ''"> |
|||
and a.currency_type = #{query.currencyType} |
|||
</if> |
|||
<if test="query.orderNo != null and query.orderNo != ''"> |
|||
and a.order_no like '%' + #{query.orderNo} + '%' |
|||
</if> |
|||
<if test="query.itemCode != null and query.itemCode != ''"> |
|||
and a.item_code like '%' + #{query.itemCode} + '%' |
|||
</if> |
|||
<if test="query.itemName != null and query.itemName != ''"> |
|||
and a.item_name like '%' + #{query.itemName} + '%' |
|||
</if> |
|||
<if test="query.projectBu != null and query.projectBu != ''"> |
|||
and a.project_bu like '%' + #{query.projectBu} + '%' |
|||
</if> |
|||
<if test="query.requestNo != null and query.requestNo != ''"> |
|||
and a.request_no like '%' + #{query.requestNo} + '%' |
|||
</if> |
|||
<if test="query.requestBy != null and query.requestBy != ''"> |
|||
and a.request_by like '%' + #{query.requestBy} + '%' |
|||
</if> |
|||
<if test="query.importBy != null and query.importBy != ''"> |
|||
and a.import_by like '%' + #{query.importBy} + '%' |
|||
</if> |
|||
<if test="query.sourceFileName != null and query.sourceFileName != ''"> |
|||
and a.source_file_name like '%' + #{query.sourceFileName} + '%' |
|||
</if> |
|||
<if test="query.orderDateStart != null"> |
|||
and a.order_date >= #{query.orderDateStart} |
|||
</if> |
|||
<if test="query.orderDateEnd != null"> |
|||
and a.order_date <= #{query.orderDateEnd} |
|||
</if> |
|||
<if test="query.importDateStart != null"> |
|||
and a.import_date >= #{query.importDateStart} |
|||
</if> |
|||
<if test="query.importDateEnd != null"> |
|||
and a.import_date <= #{query.importDateEnd} |
|||
</if> |
|||
<if test="query.qtyStart != null"> |
|||
and a.qty >= #{query.qtyStart} |
|||
</if> |
|||
<if test="query.qtyEnd != null"> |
|||
and a.qty <= #{query.qtyEnd} |
|||
</if> |
|||
<if test="query.localTotalAmountStart != null"> |
|||
and a.local_total_amount >= #{query.localTotalAmountStart} |
|||
</if> |
|||
<if test="query.localTotalAmountEnd != null"> |
|||
and a.local_total_amount <= #{query.localTotalAmountEnd} |
|||
</if> |
|||
</where> |
|||
</sql> |
|||
|
|||
<select id="queryPage" resultType="com.xujie.sys.modules.pms.entity.PartSparePurchaseImportEntity"> |
|||
select |
|||
a.id, |
|||
a.site, |
|||
a.bu_no as buNo, |
|||
a.order_date as orderDate, |
|||
a.supplier_name as supplierName, |
|||
a.currency_type as currencyType, |
|||
a.order_no as orderNo, |
|||
a.item_code as itemCode, |
|||
a.item_name as itemName, |
|||
a.qty, |
|||
a.local_unit_price as localUnitPrice, |
|||
a.local_amount as localAmount, |
|||
a.local_tax_amount as localTaxAmount, |
|||
a.local_total_amount as localTotalAmount, |
|||
a.unit_name as unitName, |
|||
a.project_bu as projectBu, |
|||
a.request_no as requestNo, |
|||
a.request_by as requestBy, |
|||
a.import_date as importDate, |
|||
a.import_by as importBy, |
|||
a.source_file_name as sourceFileName, |
|||
a.remark, |
|||
a.created_by as createdBy, |
|||
a.created_date as createdDate, |
|||
a.updated_by as updatedBy, |
|||
a.updated_date as updatedDate, |
|||
a.is_deleted as isDeleted |
|||
from part_spare_purchase_import a |
|||
<include refid="queryWhereClause"/> |
|||
order by a.import_date desc, a.id desc |
|||
</select> |
|||
|
|||
<select id="querySummary" resultType="java.util.HashMap"> |
|||
select |
|||
ISNULL(sum(a.qty), 0) as totalQty, |
|||
ISNULL(sum(a.local_total_amount), 0) as totalLocalTotalAmount |
|||
from part_spare_purchase_import a |
|||
<include refid="queryWhereClause"/> |
|||
</select> |
|||
|
|||
</mapper> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue