Browse Source

BUG修改

master
parent
commit
621adc3ca8
  1. 30
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/item/ItemController.java
  2. 72
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/item/vo/ItemBaseVO.java
  3. 107
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/item/vo/ItemExcelVO.java
  4. 60
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/item/vo/ItemExportReqVO.java
  5. 57
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/item/vo/ItemPageReqVO.java
  6. 31
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/item/vo/ItemRespVO.java
  7. 4
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/item/vo/ItemUpdateReqVO.java
  8. 8
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/location/LocationController.java
  9. 6
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/location/vo/LocationBaseVO.java
  10. 15
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/location/vo/LocationExcelVO.java
  11. 9
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/location/vo/LocationExportReqVO.java
  12. 7
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/location/vo/LocationPageReqVO.java
  13. 8
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/location/vo/LocationReqVO.java
  14. 3
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/locationarea/vo/LocationAreaBaseVO.java
  15. 5
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/locationarea/vo/LocationAreaExcelVO.java
  16. 3
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/locationarea/vo/LocationAreaExportReqVO.java
  17. 3
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/locationarea/vo/LocationAreaPageReqVO.java
  18. 2
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/convert/item/ItemConvert.java
  19. 88
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/dal/dataobject/item/ItemDO.java
  20. 8
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/dal/dataobject/location/LocationDO.java
  21. 4
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/dal/dataobject/locationarea/LocationAreaDO.java
  22. 7
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/dal/mysql/location/LocationMapper.java
  23. 2
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/dal/mysql/locationarea/LocationAreaMapper.java
  24. 1
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/deviceitem/DeviceItemServiceImpl.java
  25. 14
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/item/ItemService.java
  26. 31
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/item/ItemServiceImpl.java
  27. 36
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/itemaccounts/ItemAccountsServiceImpl.java
  28. 12
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/itemapplyrequest/ItemApplyRequestMainServiceImpl.java
  29. 6
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/itemmaintenancerecord/ItemMaintenanceRecordServiceImpl.java
  30. 8
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/itemorder/ItemOrderMainServiceImpl.java
  31. 3
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/location/LocationServiceImpl.java
  32. 6
      win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/transaction/TransactionServiceImpl.java

30
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/item/ItemController.java

@ -11,15 +11,19 @@ import com.win.module.eam.dal.dataobject.item.ItemDO;
import com.win.module.eam.service.item.ItemService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@ -179,4 +183,30 @@ public class ItemController {
return success(ItemConvert.INSTANCE.convertList(pageResult));
}
@PostMapping("/import")
@Operation(summary = "导入备件基本信息")
@Parameters({
@Parameter(name = "file", description = "Excel 文件", required = true),
@Parameter(name = "mode", description = "导入模式1更新2追加3覆盖", example = "1"),
@Parameter(name = "updatePart", description = "部分更新,默认为 true", example = "true")
})
@PreAuthorize("@ss.hasPermission('basic:item:import')")
public CommonResult<Map<String, Object>> importExcel(HttpServletResponse response,
@RequestParam("file") MultipartFile file,
@RequestParam(value = "mode") Integer mode,
@RequestParam(value = "updatePart", required = false, defaultValue = "false") Boolean updatePart) throws Exception {
List<ItemExcelVO> list = ExcelUtils.read(file, ItemExcelVO.class);
List<ItemExcelVO> errorList = itemService.importItemList(list, mode, updatePart);
Map<String, Object> returnMap = new HashMap<>();
returnMap.put("errorCount", errorList.size());
if(!errorList.isEmpty()) {
String url = ExcelUtils.writeLocalFile("备件基本信息导入错误数据" + LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) + ".xlsx", "错误列表", errorList);
returnMap.put("errorFile", url);
}
return success(returnMap);
}
}

72
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/item/vo/ItemBaseVO.java

@ -13,78 +13,58 @@ import java.math.BigDecimal;
@Data
public class ItemBaseVO {
@Schema(description = "id", example = "id")
private Long id;
@Schema(description = "编号唯一标识", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "零件编码", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "零件编码不能为空")
private String number;
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
@NotNull(message = "名称不能为空")
@Schema(description = "零件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
@NotNull(message = "零件名称不能为空")
private String name;
@Schema(description = "品牌")
private String brand;
@Schema(description = "规格型号")
private String specifications;
@Schema(description = "是否存储TRUE/FALSE")
private String isConstant;
@Schema(description = "科目")
private String subject;
@Schema(description = "科目代码代码枚举工具、易耗品、备品备件、机物料")
private String subjectCode;
@Schema(description = "类别")
private String category;
@Schema(description = "区域")
private String region;
@Schema(description = "枚举分类 A、B、C")
private String classification;
@Schema(description = "单位", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "单位不能为空")
@Schema(description = "单位")
private String uom;
@Schema(description = "单价", example = "29374")
private BigDecimal singlePrice;
@Schema(description = "供应商名称", example = "芋艿")
private String supplierName;
@Schema(description = "重采购点")
private Long reprocurement;
@Schema(description = "生产厂家(品牌)")
private String brand;
@Schema(description = "最高库存")
private Integer maxInventory;
@Schema(description = "安全库存")
private Long safetyStock;
@Schema(description = "最低库存")
private Integer minInventory;
@Schema(description = "成本中心")
private String cost;
@Schema(description = "采购周期(周)")
private Integer procurementCycle;
@Schema(description = "采购员")
private String purchaser;
@Schema(description = "ABC分类")
private String classification;
@Schema(description = "财务")
private String financer;
@Schema(description = "使用地点")
private String usePlace;
@Schema(description = "是否框架协议TRUE/FALSE")
private String isFramework;
@Schema(description = "项目")
private String project;
@Schema(description = "是否以旧换新TRUE/FALSE")
private String isRadeIn;
@Schema(description = "价格", example = "4")
private BigDecimal price;
@Schema(description = "描述")
private String describes;
@Schema(description = "地点ID", example = "1166")
@Schema(description = "地点ID", example = "3312")
private String siteId;
@Schema(description = "是否可用")
private String available;
@Schema(description = "并发乐观锁", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "并发乐观锁不能为空")
private Integer concurrencyStamp;
}

107
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/item/vo/ItemExcelVO.java

@ -7,6 +7,9 @@ import com.win.framework.excel.core.convert.DictConvert;
import com.win.module.eam.enums.DictTypeConstants;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 备件 Excel VO
*
@ -15,99 +18,61 @@ import lombok.Data;
@Data
public class ItemExcelVO {
@ExcelProperty("备件编号")
@ColumnWidth(value = 20)
@ExcelProperty("id")
private Long id;
@ExcelProperty("零件编码")
private String number;
@ExcelProperty("备件名称")
@ColumnWidth(value = 20)
@ExcelProperty("零件名称")
private String name;
@ExcelProperty("规格型号")
@ColumnWidth(value = 20)
private String specifications;
@ExcelProperty(value = "是否常储", converter = DictConvert.class)
@DictFormat(DictTypeConstants.TRUE_FALSE)
@ColumnWidth(value = 20)
private String isConstant;
@ExcelProperty("单位")
private String uom;
@ExcelProperty(value = "科目", converter = DictConvert.class)
@DictFormat(DictTypeConstants.ITEM_SUBJECT)
@ColumnWidth(value = 20)
private String subject;
@ExcelProperty("供应商名称")
private String supplierName;
@ExcelProperty("科目代码")
@ColumnWidth(value = 20)
@ExcelProperty("生产厂家(品牌)")
private String brand;
private String subjectCode;
@ExcelProperty("最高库存")
private Integer maxInventory;
@ExcelProperty(value = "单位", converter = DictConvert.class)
@DictFormat(DictTypeConstants.UOM)
@ColumnWidth(value = 20)
private String uom;
@ExcelProperty("最低库存")
private Integer minInventory;
@ExcelProperty(value = "类别", converter = DictConvert.class)
@DictFormat(DictTypeConstants.ITEM_CATEGORY)
@ColumnWidth(value = 20)
private String category;
@ExcelProperty("采购周期(周)")
private Integer procurementCycle;
@ExcelProperty(value = "备件分类", converter = DictConvert.class)
@DictFormat(DictTypeConstants.CLASSIFICATION)
@ColumnWidth(value = 20)
@ExcelProperty("ABC分类")
private String classification;
@ExcelProperty(value = "区域", converter = DictConvert.class)
@DictFormat(DictTypeConstants.ITEM_REGION)
@ColumnWidth(value = 20)
private String region;
@ExcelProperty("使用地点")
private String usePlace;
@ExcelProperty("重采购点")
@ColumnWidth(value = 20)
private Long reprocurement;
@ExcelProperty("项目")
private String project;
@ExcelProperty("安全库存")
@ColumnWidth(value = 20)
private Long safetyStock;
@ExcelProperty("价格")
private BigDecimal price;
@ExcelProperty("成本中心")
@ColumnWidth(value = 20)
private String cost;
@ExcelProperty("采购员")
@ColumnWidth(value = 20)
private String purchaser;
@ExcelProperty("财务")
@ColumnWidth(value = 20)
private String financer;
@ExcelProperty("描述")
private String describes;
@ExcelProperty(value = "是否以旧换新", converter = DictConvert.class)
@DictFormat(DictTypeConstants.TRUE_FALSE)
@ColumnWidth(value = 20)
private String isRadeIn;
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@ExcelProperty(value = "是否框架协议", converter = DictConvert.class)
@DictFormat(DictTypeConstants.TRUE_FALSE)
@ColumnWidth(value = 20)
private String isFramework;
@ExcelProperty("地点ID")
private String siteId;
@ExcelProperty(value = "是否可用", converter = DictConvert.class)
@DictFormat(DictTypeConstants.TRUE_FALSE)
@ColumnWidth(value = 20)
@ExcelProperty("是否可用")
private String available;
// /**
// * 创建时间
// */
// @ExcelProperty("创建时间")
// @ColumnWidth(value = 20)
// private LocalDateTime createTime;
@ExcelProperty("描述")
@ColumnWidth(value = 20)
private String describes;
@ExcelProperty("并发乐观锁")
private Integer concurrencyStamp;
}

60
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/item/vo/ItemExportReqVO.java

@ -2,18 +2,72 @@ package com.win.module.eam.controller.item.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import static com.win.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 备件 Excel 导出 Request VO,参数和 ItemPageReqVO 是一致的")
@Data
public class ItemExportReqVO {
@Schema(description = "编号唯一标识")
@Schema(description = "零件编码")
private String number;
@Schema(description = "名称")
@Schema(description = "零件名称", example = "王五")
private String name;
@Schema(description = "名称")
@Schema(description = "规格型号")
private String specifications;
@Schema(description = "单位")
private String uom;
@Schema(description = "供应商名称", example = "芋艿")
private String supplierName;
@Schema(description = "生产厂家(品牌)")
private String brand;
@Schema(description = "最高库存")
private Integer maxInventory;
@Schema(description = "最低库存")
private Integer minInventory;
@Schema(description = "采购周期(周)")
private Integer procurementCycle;
@Schema(description = "ABC分类")
private String classification;
@Schema(description = "使用地点")
private String usePlace;
@Schema(description = "项目")
private String project;
@Schema(description = "价格", example = "4")
private BigDecimal price;
@Schema(description = "描述")
private String describes;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "地点ID", example = "3312")
private String siteId;
@Schema(description = "是否可用")
private String available;
@Schema(description = "并发乐观锁")
private Integer concurrencyStamp;
}

57
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/item/vo/ItemPageReqVO.java

@ -5,6 +5,12 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import static com.win.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 备件分页 Request VO")
@Data
@ -12,13 +18,60 @@ import lombok.ToString;
@ToString(callSuper = true)
public class ItemPageReqVO extends PageParam {
@Schema(description = "编号唯一标识")
@Schema(description = "零件编码")
private String number;
@Schema(description = "名称")
@Schema(description = "零件名称", example = "王五")
private String name;
@Schema(description = "规格型号")
private String specifications;
@Schema(description = "单位")
private String uom;
@Schema(description = "供应商名称", example = "芋艿")
private String supplierName;
@Schema(description = "生产厂家(品牌)")
private String brand;
@Schema(description = "最高库存")
private Integer maxInventory;
@Schema(description = "最低库存")
private Integer minInventory;
@Schema(description = "采购周期(周)")
private Integer procurementCycle;
@Schema(description = "ABC分类")
private String classification;
@Schema(description = "使用地点")
private String usePlace;
@Schema(description = "项目")
private String project;
@Schema(description = "价格", example = "4")
private BigDecimal price;
@Schema(description = "描述")
private String describes;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "地点ID", example = "3312")
private String siteId;
@Schema(description = "是否可用")
private String available;
@Schema(description = "并发乐观锁")
private Integer concurrencyStamp;
}

31
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/item/vo/ItemRespVO.java

@ -15,35 +15,8 @@ import java.util.Map;
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ItemRespVO extends ItemBaseVO {
@Schema(description = "备件库存(账内和账外的和)")
private BigDecimal qty;
@Schema(description = "库位编码")
private String locationNumber;
@Schema(description = "库区编码")
private String areaNumber;
@Schema(description = "是否账内账外")
private String isInAccount;
@Schema(description = "备件编码")
private String itemNumber;
@Schema(description = "备件名称")
private String itemName;
@Schema(description = "采购订单已入库数量")
private BigDecimal deliveryQty;
@Schema(description = "采购订单申请数量")
private BigDecimal applyQty;
@Schema(description = "描述")
private String describes;
@Schema(description = "存放库位list")
private List<Map<String,Object>> list;
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1284")
private Long id;
@Schema(description = "创建时间")
private LocalDateTime createTime;

4
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/item/vo/ItemUpdateReqVO.java

@ -12,7 +12,9 @@ import java.util.List;
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ItemUpdateReqVO extends ItemBaseVO {
private Long id;
private List<String> deviceNumber;
private String itemNumber;
private String itemNumber;
}

8
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/location/LocationController.java

@ -6,6 +6,7 @@ import com.win.framework.common.pojo.PageResult;
import com.win.framework.dict.core.util.DictFrameworkUtils;
import com.win.framework.excel.core.util.ExcelUtils;
import com.win.framework.operatelog.core.annotations.OperateLog;
import com.win.module.eam.controller.item.vo.ItemExcelVO;
import com.win.module.eam.controller.location.vo.*;
import com.win.module.eam.convert.location.LocationConvert;
import com.win.module.eam.dal.dataobject.location.LocationDO;
@ -13,15 +14,19 @@ import com.win.module.eam.enums.DictTypeConstants;
import com.win.module.eam.service.location.LocationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@ -156,4 +161,7 @@ public class LocationController {
return success(LocationConvert.INSTANCE.convertList(locationDOS));
}
}

6
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/location/vo/LocationBaseVO.java

@ -29,12 +29,6 @@ public class LocationBaseVO {
@NotNull(message = "库区编号不能为空")
private String areaNumber;
@Schema(description = "类型", example = "2")
private String type;
@Schema(description = "是否账内账外默认TRUE账内FALSE账外", example = "21786")
private String isInAccount;
@Schema(description = "地点ID", example = "23633")
private String siteId;

15
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/location/vo/LocationExcelVO.java

@ -27,21 +27,6 @@ public class LocationExcelVO {
@ColumnWidth(value = 20)
private String areaNumber;
@ExcelProperty(value = "类型", converter = DictConvert.class)
@DictFormat(DictTypeConstants.LOCATION_AREA_TYPE)
@ColumnWidth(value = 20)
private String type;
@ExcelProperty(value = "是否账内", converter = DictConvert.class)
@DictFormat(DictTypeConstants.TRUE_FALSE)
@ColumnWidth(value = 20)
private String isInAccount;
@ExcelProperty(value = "是否可用", converter = DictConvert.class)
@DictFormat(DictTypeConstants.TRUE_FALSE)
@ColumnWidth(value = 20)
private String available;
@ExcelProperty("描述")
@ColumnWidth(value = 30)
private String description;

9
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/location/vo/LocationExportReqVO.java

@ -21,13 +21,4 @@ public class LocationExportReqVO {
@Schema(description = "库区编号")
private String areaNumber;
@Schema(description = "类型", example = "2")
private String type;
@Schema(description = "是否账内账外默认TRUE账内FALSE账外", example = "21786")
private String isInAccount;
@Schema(description = "并发乐观锁")
private Integer concurrencyStamp;
}

7
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/location/vo/LocationPageReqVO.java

@ -1,5 +1,6 @@
package com.win.module.eam.controller.location.vo;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
@ -23,12 +24,6 @@ public class LocationPageReqVO extends PageParam {
@Schema(description = "库区编号")
private String areaNumber;
@Schema(description = "类型", example = "2")
private String type;
@Schema(description = "是否账内账外默认TRUE账内FALSE账外", example = "21786")
private String isInAccount;
@Schema(description = "并发乐观锁")
private Integer concurrencyStamp;

8
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/location/vo/LocationReqVO.java

@ -1,5 +1,6 @@
package com.win.module.eam.controller.location.vo;
import com.baomidou.mybatisplus.annotation.Version;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.ToString;
@ -21,13 +22,6 @@ public class LocationReqVO{
@Schema(description = "库区编号")
private String areaNumber;
@Schema(description = "类型", example = "2")
private String type;
@Schema(description = "是否账内账外默认TRUE账内FALSE账外", example = "21786")
private String isInAccount;
@Schema(description = "并发乐观锁")
private Integer concurrencyStamp;
}

3
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/locationarea/vo/LocationAreaBaseVO.java

@ -25,9 +25,6 @@ public class LocationAreaBaseVO {
@Schema(description = "描述", example = "你猜")
private String description;
@Schema(description = "类型枚举辅材库、备品备件库、工具库、专用耗材库、易耗品库", example = "2")
private String type;
@Schema(description = "地点ID", example = "19003")
private String siteId;

5
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/locationarea/vo/LocationAreaExcelVO.java

@ -23,11 +23,6 @@ public class LocationAreaExcelVO {
@ColumnWidth(value = 20)
private String name;
@ExcelProperty(value = "类型", converter = DictConvert.class)
@DictFormat(DictTypeConstants.LOCATION_AREA_TYPE)
@ColumnWidth(value = 20)
private String type;
@ExcelProperty(value = "是否可用", converter = DictConvert.class)
@DictFormat(DictTypeConstants.TRUE_FALSE)
@ColumnWidth(value = 20)

3
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/locationarea/vo/LocationAreaExportReqVO.java

@ -13,9 +13,6 @@ public class LocationAreaExportReqVO {
@Schema(description = "名称", example = "王五")
private String name;
@Schema(description = "类型枚举辅材库、备品备件库、工具库、专用耗材库、易耗品库", example = "2")
private String type;
@Schema(description = "是否可用")
private String available;

3
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/locationarea/vo/LocationAreaPageReqVO.java

@ -18,9 +18,6 @@ public class LocationAreaPageReqVO extends PageParam {
@Schema(description = "名称", example = "王五")
private String name;
@Schema(description = "类型枚举辅材库、备品备件库、工具库、专用耗材库、易耗品库", example = "2")
private String type;
@Schema(description = "是否可用")
private String available;

2
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/convert/item/ItemConvert.java

@ -23,6 +23,8 @@ public interface ItemConvert {
ItemDO convert(ItemCreateReqVO bean);
ItemDO convert(ItemExcelVO bean);
ItemDO convert(ItemUpdateReqVO bean);
ItemRespVO convert(ItemDO bean);

88
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/dal/dataobject/item/ItemDO.java

@ -32,83 +32,61 @@ public class ItemDO extends BaseDO {
@TableId
private Long id;
/**
* 编号唯一标识
* 零件编码
*/
private String number;
/**
* 名称
* 零件名称
*/
private String name;
/**
* 品牌
*/
private String brand;
/**
* 规格型号
*/
private String specifications;
/**
* 是否存储TRUE/FALSE
*/
private String isConstant;
/**
* 是否全局TRUE/FALSE
*/
private String isOverall;
/**
* 科目代码枚举工具易耗品机物料备品备件辅材
*/
private String subject;
/**
* 科目代码
*/
private String subjectCode;
/**
* 区域
* 单位
*/
private String region;
private String uom;
/**
* 枚举分类 ABC
* 供应商名称
*/
private String classification;
private String supplierName;
/**
* 单位
* 生产厂家(品牌)
*/
private String uom;
private String brand;
/**
* 单价
* 最高库存
*/
private BigDecimal singlePrice;
private Integer maxInventory;
/**
* 重点采购
* 最低库存
*/
private Long reprocurement;
private Integer minInventory;
/**
* 安全库存
* 采购周期
*/
private Long safetyStock;
private Integer procurementCycle;
/**
* 成本中心
* ABC分类
*/
private String cost;
private String classification;
/**
* 采购员
* 使用地点
*/
private String purchaser;
private String usePlace;
/**
* 财务
* 项目
*/
private String financer;
private String project;
/**
* 是否框架协议TRUE/FALSE
* 价格
*/
private String isFramework;
private BigDecimal price;
/**
* 是否以旧换新TRUE/FALSE
* 描述
*/
private String isRadeIn;
private String describes;
/**
* 地点ID
*/
@ -120,26 +98,8 @@ public class ItemDO extends BaseDO {
/**
* 并发乐观锁
*/
@Version
private Integer concurrencyStamp;
/**
* 采购时间
*/
private LocalDateTime purchaseTime;
/**
* 库龄
*/
private Long stockAge;
/**
* 类别
*/
private String category;
/**
* 描述
*/
private String describes;
/**
* 库存数量
*/

8
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/dal/dataobject/location/LocationDO.java

@ -44,14 +44,6 @@ public class LocationDO extends BaseDO {
* 库区编号
*/
private String areaNumber;
/**
* 类型
*/
private String type;
/**
* 是否账内账外默认TRUE账内FALSE账外
*/
private String isInAccount;
/**
* 地点ID
*/

4
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/dal/dataobject/locationarea/LocationAreaDO.java

@ -38,10 +38,6 @@ public class LocationAreaDO extends BaseDO {
* 描述
*/
private String description;
/**
* 类型枚举辅材库备品备件库工具库专用耗材库易耗品库
*/
private String type;
/**
* 地点ID
*/

7
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/dal/mysql/location/LocationMapper.java

@ -28,8 +28,6 @@ public interface LocationMapper extends BaseMapperX<LocationDO> {
.likeIfPresent(LocationDO::getName, reqVO.getName())
.eqIfPresent(LocationDO::getDescription, reqVO.getDescription())
.eqIfPresent(LocationDO::getAreaNumber, reqVO.getAreaNumber())
.eqIfPresent(LocationDO::getType, reqVO.getType())
.eqIfPresent(LocationDO::getIsInAccount, reqVO.getIsInAccount())
.eqIfPresent(LocationDO::getConcurrencyStamp, reqVO.getConcurrencyStamp())
.orderByDesc(LocationDO::getId));
}
@ -40,9 +38,6 @@ public interface LocationMapper extends BaseMapperX<LocationDO> {
.likeIfPresent(LocationDO::getName, reqVO.getName())
.eqIfPresent(LocationDO::getDescription, reqVO.getDescription())
.eqIfPresent(LocationDO::getAreaNumber, reqVO.getAreaNumber())
.eqIfPresent(LocationDO::getType, reqVO.getType())
.eqIfPresent(LocationDO::getIsInAccount, reqVO.getIsInAccount())
.eqIfPresent(LocationDO::getConcurrencyStamp, reqVO.getConcurrencyStamp())
.orderByDesc(LocationDO::getId));
}
@ -53,8 +48,6 @@ public interface LocationMapper extends BaseMapperX<LocationDO> {
.likeIfPresent(LocationDO::getName, reqVO.getName())
.eqIfPresent(LocationDO::getDescription, reqVO.getDescription())
.eqIfPresent(LocationDO::getAreaNumber, reqVO.getAreaNumber())
.eqIfPresent(LocationDO::getType, reqVO.getType())
.eqIfPresent(LocationDO::getIsInAccount, reqVO.getIsInAccount())
.eqIfPresent(LocationDO::getConcurrencyStamp, reqVO.getConcurrencyStamp())
.orderByDesc(LocationDO::getId));
}

2
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/dal/mysql/locationarea/LocationAreaMapper.java

@ -24,7 +24,6 @@ public interface LocationAreaMapper extends BaseMapperX<LocationAreaDO> {
return selectPage(reqVO, new LambdaQueryWrapperX<LocationAreaDO>()
.eqIfPresent(LocationAreaDO::getNumber, reqVO.getNumber())
.likeIfPresent(LocationAreaDO::getName, reqVO.getName())
.eqIfPresent(LocationAreaDO::getType, reqVO.getType())
.eqIfPresent(LocationAreaDO::getAvailable, reqVO.getAvailable())
.orderByDesc(LocationAreaDO::getId));
}
@ -33,7 +32,6 @@ public interface LocationAreaMapper extends BaseMapperX<LocationAreaDO> {
return selectList(new LambdaQueryWrapperX<LocationAreaDO>()
.eqIfPresent(LocationAreaDO::getNumber, reqVO.getNumber())
.likeIfPresent(LocationAreaDO::getName, reqVO.getName())
.eqIfPresent(LocationAreaDO::getType, reqVO.getType())
.eqIfPresent(LocationAreaDO::getAvailable, reqVO.getAvailable())
.orderByDesc(LocationAreaDO::getId));
}

1
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/deviceitem/DeviceItemServiceImpl.java

@ -101,7 +101,6 @@ public class DeviceItemServiceImpl implements DeviceItemService {
QueryWrapper<ItemDO> itemDOQueryWrapper = new QueryWrapper<>();
itemDOQueryWrapper.eq("number", deviceItemDO.getItemNumber());
ItemDO itemDO = itemMapper.selectOne(itemDOQueryWrapper);
itemDO.setIsOverall(BooleanTypeEnum.F.getCode());
itemMapper.updateById(itemDO);
deviceItemMapper.deleteByItemNumberDeviceNumber(deviceItemDO);
}

14
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/item/ItemService.java

@ -2,10 +2,7 @@ package com.win.module.eam.service.item;
import com.win.framework.common.pojo.CustomConditions;
import com.win.framework.common.pojo.PageResult;
import com.win.module.eam.controller.item.vo.ItemCreateReqVO;
import com.win.module.eam.controller.item.vo.ItemExportReqVO;
import com.win.module.eam.controller.item.vo.ItemPageReqVO;
import com.win.module.eam.controller.item.vo.ItemUpdateReqVO;
import com.win.module.eam.controller.item.vo.*;
import com.win.module.eam.dal.dataobject.item.ItemDO;
import javax.validation.Valid;
@ -130,4 +127,13 @@ public interface ItemService {
*/
List<ItemDO> getItemNoPage(ItemPageReqVO pageReqVO);
/**
* 导入备件主信息
*
* @param datas 导入备件主信息列表
* @param mode 导入模式1更新2追加3覆盖
* @param updatePart 是否支持更新
* @return 导入结果
*/
public List<ItemExcelVO> importItemList(List<ItemExcelVO> datas, Integer mode, boolean updatePart);
}

31
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/item/ItemServiceImpl.java

@ -1,15 +1,13 @@
package com.win.module.eam.service.item;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.win.framework.common.exception.util.ServiceExceptionUtil;
import com.win.framework.common.pojo.CustomConditions;
import com.win.framework.common.pojo.PageResult;
import com.win.module.eam.controller.item.vo.ItemCreateReqVO;
import com.win.module.eam.controller.item.vo.ItemExportReqVO;
import com.win.module.eam.controller.item.vo.ItemPageReqVO;
import com.win.module.eam.controller.item.vo.ItemUpdateReqVO;
import com.win.module.eam.controller.item.vo.*;
import com.win.module.eam.convert.item.ItemConvert;
import com.win.module.eam.dal.dataobject.item.ItemDO;
import com.win.module.eam.dal.dataobject.itemaccounts.ItemAccountsDO;
@ -72,7 +70,6 @@ public class ItemServiceImpl implements ItemService {
item.setNumber(number);
item.setCreateTime(LocalDateTime.now());
//是否全局,备件没匹配设备时,默认是全局的
item.setIsOverall(BooleanTypeEnum.Y.getCode());
itemMapper.insert(item);
// 返回
return item.getId();
@ -259,5 +256,29 @@ public class ItemServiceImpl implements ItemService {
return itemMapper.selectNoPage(pageReqVO);
}
@Override
public List<ItemExcelVO> importItemList(List<ItemExcelVO> datas, Integer mode, boolean updatePart) {
if (CollUtil.isEmpty(datas)) {
throw exception(ITEM_NOT_EXISTS);
}
List<ItemExcelVO> errorList = new ArrayList<>();
datas.forEach(item -> {
if(errorList == null){
// 判断如果不存在,在进行插入
QueryWrapper<ItemDO> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("number", item.getNumber());
ItemDO obj = itemMapper.selectOne(queryWrapper);
if (obj == null&& mode != 3) {
itemMapper.insert(ItemConvert.INSTANCE.convert(item));
}
else if (obj != null && mode != 2) {// 如果存在,判断是否允许更新
ItemDO itemDO = ItemConvert.INSTANCE.convert(item);
itemDO.setId(obj.getId());
itemMapper.updateById(obj);
}
}
});
return errorList;
}
}

36
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/itemaccounts/ItemAccountsServiceImpl.java

@ -109,24 +109,24 @@ public class ItemAccountsServiceImpl implements ItemAccountsService {
itemAccountsDO.setName(itemDO.getName());
itemAccountsDO.setBrand(itemDO.getBrand());
itemAccountsDO.setSpecifications(itemDO.getSpecifications());
itemAccountsDO.setIsConstant(itemDO.getIsConstant());
itemAccountsDO.setIsOverall(itemDO.getIsOverall());
itemAccountsDO.setSubject(itemDO.getSubject());
itemAccountsDO.setSubjectCode(itemDO.getSubjectCode());
itemAccountsDO.setRegion(itemDO.getRegion());
itemAccountsDO.setClassification(itemDO.getClassification());
itemAccountsDO.setUom(itemDO.getUom());
itemAccountsDO.setSinglePrice(itemDO.getSinglePrice());
itemAccountsDO.setReprocurement(itemDO.getReprocurement());
itemAccountsDO.setSafetyStock(itemDO.getSafetyStock());
itemAccountsDO.setCost(itemDO.getCost());
itemAccountsDO.setPurchaser(itemDO.getPurchaser());
itemAccountsDO.setFinancer(itemDO.getFinancer());
itemAccountsDO.setIsFramework(itemDO.getIsFramework());
itemAccountsDO.setIsRadeIn(itemDO.getIsRadeIn());
itemAccountsDO.setPurchaseTime(itemDO.getPurchaseTime());
itemAccountsDO.setStockAge(itemDO.getStockAge());
itemAccountsDO.setCategory(itemDO.getCategory());
// itemAccountsDO.setIsConstant(itemDO.getIsConstant());
// itemAccountsDO.setIsOverall(itemDO.getIsOverall());
// itemAccountsDO.setSubject(itemDO.getSubject());
// itemAccountsDO.setSubjectCode(itemDO.getSubjectCode());
// itemAccountsDO.setRegion(itemDO.getRegion());
// itemAccountsDO.setClassification(itemDO.getClassification());
// itemAccountsDO.setUom(itemDO.getUom());
// itemAccountsDO.setSinglePrice(itemDO.getSinglePrice());
// itemAccountsDO.setReprocurement(itemDO.getReprocurement());
// itemAccountsDO.setSafetyStock(itemDO.getSafetyStock());
// itemAccountsDO.setCost(itemDO.getCost());
// itemAccountsDO.setPurchaser(itemDO.getPurchaser());
// itemAccountsDO.setFinancer(itemDO.getFinancer());
// itemAccountsDO.setIsFramework(itemDO.getIsFramework());
// itemAccountsDO.setIsRadeIn(itemDO.getIsRadeIn());
// itemAccountsDO.setPurchaseTime(itemDO.getPurchaseTime());
// itemAccountsDO.setStockAge(itemDO.getStockAge());
// itemAccountsDO.setCategory(itemDO.getCategory());
itemAccountsDO.setDescribes(itemDO.getDescribes());
}
}

12
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/itemapplyrequest/ItemApplyRequestMainServiceImpl.java

@ -117,7 +117,7 @@ public class ItemApplyRequestMainServiceImpl implements ItemApplyRequestMainServ
detailsDo.setNumber(number);
List<ItemDO> itemDOS = itemMapper.selectList("number", detailsDo.getItemNumber());
BigDecimal qty = detailsDo.getQty();
sums = sums.add(itemDOS.get(0).getSinglePrice()==null?BigDecimal.ZERO:itemDOS.get(0).getSinglePrice().multiply(qty));
// sums = sums.add(itemDOS.get(0).getSinglePrice()==null?BigDecimal.ZERO:itemDOS.get(0).getSinglePrice().multiply(qty));
detailsDo.setItemNumber(detailsDo.getItemNumber());//备件号
detailsDo.setQty(qty);//申领数量
detailsDo.setMasterId(itemApplyMain.getId());
@ -166,7 +166,7 @@ public class ItemApplyRequestMainServiceImpl implements ItemApplyRequestMainServ
detailsDo.setNumber(updateReqVO.getNumber());
List<ItemDO> itemDOS = itemMapper.selectList("number", detailsDo.getItemNumber());
BigDecimal qty = detailsDo.getQty();
sums = sums.add(itemDOS.get(0).getSinglePrice().multiply(qty));
// sums = sums.add(itemDOS.get(0).getSinglePrice().multiply(qty));
detailsDo.setItemNumber(detailsDo.getItemNumber());//备件号
detailsDo.setQty(qty);//申领数量
detailsDo.setType(detailsDo.getType());//设备模具类型
@ -211,7 +211,6 @@ public class ItemApplyRequestMainServiceImpl implements ItemApplyRequestMainServ
String locationNumber = map.get("locationNumber").toString();//库位
LocationDO locationDO = locationMapper.scanCodeByNumber(locationNumber);
String areaNumber = locationDO.getAreaNumber();//库区
String isInAccount = locationDO.getIsInAccount();//是否账内账外
BigDecimal qty2 = locationDO.getQty();//台账内库存数
if(new BigDecimal(qty).compareTo(qty2)>0){
throw exception(OUT_BIG_INVENTORY);// 出库数量大于库存
@ -248,7 +247,6 @@ public class ItemApplyRequestMainServiceImpl implements ItemApplyRequestMainServ
transactionCreateReqVO.setLocationNumber(locationNumber);
transactionCreateReqVO.setAreaNumber(areaNumber);
transactionCreateReqVO.setTransactionType("OUT");
transactionCreateReqVO.setIsInAccount(isInAccount);
transactionCreateReqVO.setQty(new BigDecimal(qty));
transactionCreateReqVO.setDescribes(reavo.getDescribes());
transactionCreateReqVO.setAssociatedNumber(applyMainDO1.getNumber());
@ -301,18 +299,14 @@ public class ItemApplyRequestMainServiceImpl implements ItemApplyRequestMainServ
String qty = map.get("qty").toString();//归还数量
String locationNumber = map.get("locationNumber").toString();//库位
LocationDO locationDO = locationMapper.scanCodeByNumber(locationNumber);
if(!"FALSE".equals(locationDO.getIsInAccount())){//备件归还的库位必须是账外库
throw exception(ITEM_RETURN_FALSE);
}
String areaNumber = locationDO.getAreaNumber();
String isInAccount = locationDO.getIsInAccount();
//添加库存事务
TransactionCreateReqVO transactionCreateReqVO = new TransactionCreateReqVO();
transactionCreateReqVO.setItemNumber(itemNumber);
transactionCreateReqVO.setLocationNumber(locationNumber);
transactionCreateReqVO.setAreaNumber(areaNumber);
transactionCreateReqVO.setTransactionType("IN");
transactionCreateReqVO.setIsInAccount(isInAccount);
transactionCreateReqVO.setQty(new BigDecimal(qty));
transactionCreateReqVO.setDescribes(reavo.getDescribes());//描述
transactionCreateReqVO.setOperator(reavo.getReverterId());

6
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/itemmaintenancerecord/ItemMaintenanceRecordServiceImpl.java

@ -73,13 +73,9 @@ public class ItemMaintenanceRecordServiceImpl implements ItemMaintenanceRecordSe
createReqVO.setQty(new BigDecimal(map.get("qty").toString()));
String locationNumber = map.get("locationNumber").toString();//库位
LocationDO locationDO = locationMapper.scanCodeByNumber(locationNumber);
if(!"FALSE".equals(locationDO.getIsInAccount())){//备件维修的库位必须是账外库
throw exception(PURCHASE_ITEM_ORDER_TRUE);
}
String areaNumber = locationDO.getAreaNumber();
createReqVO.setAreaNumber(areaNumber);
String isInAccount = locationDO.getIsInAccount();
createReqVO.setIsInAccount(isInAccount);
// 插入
ItemMaintenanceRecordDO itemMaintenance = ItemMaintenanceRecordConvert.INSTANCE.convert(createReqVO);
String number = serialNumberApi.generateCode(RuleCodeEnum.BJWX_RECORD.getCode());

8
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/itemorder/ItemOrderMainServiceImpl.java

@ -84,8 +84,6 @@ public class ItemOrderMainServiceImpl implements ItemOrderMainService {
itemDOQueryWrapper.eq("number", itemOrderDetailDO.getItemNumber());
ItemDO itemDO = itemMapper.selectOne(itemDOQueryWrapper);
if(itemDO!=null){
itemDO.setSinglePrice(itemOrderDetailDO.getSinglePrice());
itemDO.setSinglePrice(itemOrderDetailDO.getSinglePrice());
itemMapper.updateById(itemDO);
}
// ItemAccountsDO itemAccountsDO = new ItemAccountsDO();
@ -224,11 +222,8 @@ public class ItemOrderMainServiceImpl implements ItemOrderMainService {
String qty = map.get("qty").toString();//入库数量
String locationNumber = map.get("locationNumber").toString();//库位
LocationDO locationDO = locationMapper.scanCodeByNumber(locationNumber);
if(!"TRUE".equals(locationDO.getIsInAccount())){//采购入库的库位必须是账内库
throw exception(PURCHASE_ITEM_ORDER_TRUE);
}
String areaNumber = locationDO.getAreaNumber();
String isInAccount = locationDO.getIsInAccount();
//往申领工单子表中插入
queryWrapper.eq("master_id", reavo.getId());
queryWrapper.eq("item_number", itemNumber);
@ -266,7 +261,6 @@ public class ItemOrderMainServiceImpl implements ItemOrderMainService {
transactionCreateReqVO.setLocationNumber(locationNumber);
transactionCreateReqVO.setAreaNumber(areaNumber);
transactionCreateReqVO.setTransactionType("IN");
transactionCreateReqVO.setIsInAccount(isInAccount);
transactionCreateReqVO.setQty(new BigDecimal(qty));
transactionCreateReqVO.setDescribes(reavo.getDescribes());
transactionCreateReqVO.setAssociatedNumber(itemOrderMainDO.getNumber());

3
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/location/LocationServiceImpl.java

@ -133,8 +133,6 @@ public class LocationServiceImpl implements LocationService {
throw exception(APPLAY_ITEM_EXCLUDE);//该备件不在申领范围内
}
//校验优先账外库出库
String isInAccount = locationDO.getIsInAccount();
if ("TRUE".equals(isInAccount)) {//账内库需要先查询是否有账外库,有账外库且库存不为0的时候需要提醒用账外库
QueryWrapper<ItemAccountsDO> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("item_number", itemNumber);
queryWrapper.eq("is_in_account", "FALSE");
@ -161,7 +159,6 @@ public class LocationServiceImpl implements LocationService {
throw exception(FALSE_LOCATION_ACCOUNT_EXISTS);//该备件有账外库且库存大于0
}
}
}
BigDecimal applyQty = itemApplyRequestDetailDO.getQty();//申领数量
if (applyQty == null) {
applyQty = BigDecimal.ZERO;

6
win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/transaction/TransactionServiceImpl.java

@ -341,12 +341,6 @@ public class TransactionServiceImpl implements TransactionService {
List<ItemDO> itemDOS = itemMapper.selectList(query);
if (!itemDOS.isEmpty()) {
ItemDO itemDO = itemDOS.get(0);
long reprocurement = itemDO.getReprocurement();
long safetyStock = itemDO.getSafetyStock();
if (reprocurement <= l) {//库存达到重采购点需要给oa发送消息
long num = safetyStock - l;//给oa发送数量
System.out.println("向oa发送消息:" + num);
}
}
}
}

Loading…
Cancel
Save