yun-zuoyi
WYnneaoapc 6 years ago
commit c93dd66cd9

@ -3,6 +3,7 @@ package cn.estsh.i3plus.pojo.base.enumutil;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
import java.util.Date;
/**
@ -2284,7 +2285,7 @@ public class BlockFormEnumUtil {
LONG(21, "Long", "长整型", "java.lang.Long", Long.class,PROPERTY_CONTROL_TYPE.NUMBER,SQL_WHERE.EQUAL,"0"),
DOUBLE(30, "Double", "大浮点型", "java.lang.Double", Double.class,PROPERTY_CONTROL_TYPE.NUMBER,SQL_WHERE.EQUAL,"0.0"),
FLOAT(31, "Float", "小浮点型", "java.lang.Float", Float.class,PROPERTY_CONTROL_TYPE.NUMBER,SQL_WHERE.EQUAL,"0.0"),
BIG_DECIMAL(32, "Double", "大浮点型", "java.math.BigDecimal", Double.class,PROPERTY_CONTROL_TYPE.NUMBER,SQL_WHERE.EQUAL,"0.0"),
BIG_DECIMAL(32, "BigDecimal", "大浮点型", "java.math.BigDecimal", BigDecimal.class,PROPERTY_CONTROL_TYPE.NUMBER,SQL_WHERE.EQUAL,"0.0"),
BOOLEAN(40, "Boolean", "布尔值", "java.lang.Boolean", Boolean.class,PROPERTY_CONTROL_TYPE.RADIO,SQL_WHERE.EQUAL,null),
BYTE(50, "Byte", "字节", "java.lang.Byte", Byte.class,PROPERTY_CONTROL_TYPE.TEXT,SQL_WHERE.EQUAL,null),
DATE_TIME(12, "String", "日期时分秒", "java.sql.Timestamp", String.class,PROPERTY_CONTROL_TYPE.DATE_TIME,SQL_WHERE.BETWEEN,null,"yyyy-MM-dd hh:mm:ss");

@ -14,6 +14,101 @@ public class MesEnumUtil {
/**
* Mes
*/
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum ORGANIZATION_INIT_DATA {
MES_CONFIG("MesConfig", "MES_CONFIG", "配置表"),
MES_NUMBER_RULE("MesNumberRule", "MES_NUMBER_RULE", "编码规则表"),
MES_STEP("MesStep", "MES_STEP", "工步"),
MES_STEP_PARAM("MesStepParam", "MES_STEP_PARAM", "工步参数表"),
MES_PCN_SYNC_CFG("MesPcnSyncCfg", "MES_PCN_SYNC_CFG", "同步配置"),
MES_BUTTON_STATUS("MesButtonStatus", "MES_BUTTON_STATUS", "按钮状态配置表"),
MES_WORK_CELL_PARAM("MesWorkCellParam", "MES_WORK_CELL_PARAM", "工作单元参数"),
MES_STATUS_CFG("MesStatusCfg", "MES_STATUS_CFG", "状态配置"),
MES_EVENT("MesEvent", "MES_EVENT", "事件清单"),
MES_METHOD("MesMethod", "MES_METHOD", "方法清单"),
MES_ACTION("MesAction", "MES_ACTION", "动作"),
MES_EVENT_ACTION("MesEventAction", "MES_EVENT_ACTION", "事件动作配置"),
MES_ACTION_METHOD("MesActionMethod", "MES_ACTION_METHOD", "动作方法配置");
private String value;
private String code;
private String description;
ORGANIZATION_INIT_DATA(String value, String code, String description) {
this.value = value;
this.code = code;
this.description = description;
}
public String getValue() {
return value;
}
public String getDescription() {
return description;
}
// 根据value返回枚举类型,主要在switch中使用
public static ORGANIZATION_INIT_DATA getByValue(String value) {
for (ORGANIZATION_INIT_DATA mesInsertExcel : values()) {
if (mesInsertExcel.getValue().equals(value)) {
return mesInsertExcel;
}
}
return null;
}
public static String valueOfDescription(int val) {
String tmp = null;
for (int i = 0; i < values().length; i++) {
if (values()[i].value.equals(val)) {
tmp = values()[i].description;
}
}
return tmp;
}
}
/**
* Mes
*/
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum OBJECT_CFG_IS_SAVE {
SAVE(1, "存储"),
NO_SAVE(2, "不存储");
private int value;
private String description;
OBJECT_CFG_IS_SAVE(int value, String description) {
this.value = value;
this.description = description;
}
public int getValue() {
return value;
}
public String getDescription() {
return description;
}
public static String valueOfDescription(int val) {
String tmp = null;
for (int i = 0; i < values().length; i++) {
if (values()[i].value == val) {
tmp = values()[i].description;
}
}
return tmp;
}
}
/**
* Mes
*/
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
@ -2719,7 +2814,8 @@ public class MesEnumUtil {
OPC_LINK_CALLBACK(140, "OPC_LINK", "OPC_LINK_CALLBACK"),
SUPPLY_SWITCH(150,"SUPPLY_SWITCH",""),
PCN_LOGIN(160, "PCN_LOGIN",""),
PCN_MENU(170, "PCN_MENU","");
PCN_MENU(170, "PCN_MENU",""),
PCN_MODULE(180, "PCN_MODULE","");
private int value;

@ -543,7 +543,8 @@ public class WmsEnumUtil {
IN_STORE(10, "IN", "入库"),
OUT_STORE(20, "OUT", "出库"),
MOVE_STORE(30, "MOVE", "移库"),
OTHER(40, "OTHER", "其他");
OTHER(40, "OTHER", "其他"),
NC_HANDLE(50, "NC_HANDLE", "NC处理");
private int value;
private String code;
@ -627,7 +628,18 @@ public class WmsEnumUtil {
VDA_ONE_PICKING_GOODS(280, "VDA_ONE_PICKING_GOODS", "VDA单箱领料"),
VDA_QC(290, "VDA_QC", "VDA质检"),
VDA_SN_SPLIT(300, "VDA_SN_SPLIT", "VDA物料拆分"),
VDA_SN_MERGE(310, "VDA_SN_MERGE", "VDA物料合并");
VDA_SN_MERGE(310, "VDA_SN_MERGE", "VDA物料合并"),
KT_RECEPTION(320, "KT_RECEPTION", "KT让步接收"),
KT_SCRAP(330, "KT_SCRAP", "KT报废"),
KT_QUARANTINE(330, "KT_QUARANTINE", "KT报废"),
KT_BACK_QUARANTINE(340, "KT_BACK_QUARANTINE", "KT反隔离"),
KT_DEFINITE_FAIL(350, "KT_DEFINITE_FAIL", "KT不合格"),
KT_RETURN(360, "KT_RETURN", "KT退货"),
KT_REWORK(370, "KT_REWORK", "KT返工"),
KT_MISCALCULATION(380, "KT_MISCALCULATION", "KT误判"),
KT_SORTING(390, "KT_SORTING", "KT分选"),
VDA_STATIC_CS(320,"VDA_STATIC_CS", "静态盘点"),
VDA_CS_SEARCH(340,"VDA_CS_SEARCH", "VDA盘点查询") ;
private int value;
@ -808,8 +820,8 @@ public class WmsEnumUtil {
VDA_SN_SPLIT("VDA_SN_SPLIT", "VDA条码拆分"),
VDA_SN_("VDA_SN_MERGE", "VDA条码合并"),
VDA_SCAN_QUERY("VDA_SCAN_QUERY", "VDA扫描查询"),
VDA_TRANSACTION_QUERY("VDA_TRANSACTION_QUERY","VDA事务查询");
VDA_TRANSACTION_QUERY("VDA_TRANSACTION_QUERY","VDA事务查询"),
VDA_STATIC_CS("VDA_STATIC_CS", "VDA静态盘点");
private String value;
private String description;
@ -1976,7 +1988,8 @@ public class WmsEnumUtil {
LOCATE(30, "LOCATE", "库位对象"),
MATERIAL(40, "MATERIAL", "物料对象"),
TRANS_TYPE(50, "TRANS_TYPE", "交易代码对象"),
BUSI_TYPE(60, "BUSI_TYPE", "业务类型对象");
BUSI_TYPE(60, "BUSI_TYPE", "业务类型对象"),
BUSI_OPERATION_TYPE(70, "BUSI_OPERATION_TYPE", "业务操作对象");
private String code;
private String description;
@ -2317,6 +2330,56 @@ public class WmsEnumUtil {
return tmp;
}
}
/**
* NC
*/
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum BUSI_OPERATION_TYPE {
//收货改数
GOODS_CHANGE_NUMBER(10, "GOODS_CHANGE_NUMBER", "收货改数") ;
private int value;
private String code;
private String description;
BUSI_OPERATION_TYPE(int value, String code, String description) {
this.value = value;
this.code = code;
this.description = description;
}
public int getValue() {
return value;
}
public String getDescription() {
return description;
}
public String getCode() {
return code;
}
public static String valueOf(int val) {
String tmp = null;
for (int i = 0; i < values().length; i++) {
if (values()[i].value == val) {
tmp = values()[i].description;
}
}
return tmp;
}
public static int descOf(String desc) {
int tmp = 1;
for (int i = 0; i < values().length; i++) {
if (values()[i].description.equals(desc)) {
tmp = values()[i].value;
}
}
return tmp;
}
}
/**
*
@ -3497,10 +3560,7 @@ public class WmsEnumUtil {
public enum REC_STATUS {
UNRECEIVED("UNRECEIVED", "未收货"),
COMPLETE_RECEIPT("COMPLETE_RECEIPT", "完成收货"),
PARTIAL_RECEIPT("PARTIAL_RECEIPT", "部分收货"),
OVER_RECEIVED_GOODS("OVER_RECEIVED_GOODS", "超量收货"),
OTHER("ELSE", "其他"),
;
PARTIAL_RECEIPT("PARTIAL_RECEIPT", "部分收货");
private String value;
private String description;
@ -4006,4 +4066,39 @@ public class WmsEnumUtil {
return tmp;
}
}
/**
* MQ
*/
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum SPEC_LEVEL {
FIRST_LEVEL(10, "一层"), SECOND_LEVEL(20, "二层"), THIRD_LEVEL(30, "三层"), FOURTH_LEVEL(40, "四层"), FIFTH_LEVEL(50, "五层");
private int value;
private String description;
SPEC_LEVEL(int value, String description) {
this.value = value;
this.description = description;
}
public int getValue() {
return value;
}
public String getDescription() {
return description;
}
public static String valueOf(int val) {
String tmp = null;
for (int i = 0; i < values().length; i++) {
if (values()[i].value == val) {
tmp = values()[i].description;
}
}
return tmp;
}
}
}

@ -51,8 +51,18 @@ public class MesPcnSysUserOffline extends BaseBean {
private Integer userType;
@Lob
@Column(name="LOGIN_INFO")
@ApiParam(value ="登陆信息" , access ="登陆信息")
private String loginInfo;
@Lob
@Column(name="MENU_LIST")
@ApiParam(value ="菜单" , access ="菜单")
private String menuList;
@Lob
@Column(name="MODULE_LIST")
@ApiParam(value ="模块" , access ="模块")
private String moduleList;
}

@ -52,7 +52,7 @@ public class MesObjectCfg extends BaseBean {
private String pojoAttr;
@Column(name = "IS_SAVE")
@ApiParam("是否保存 1存 2不存")
@ApiParam("是否存储")
private Integer isSave;
}

@ -1718,11 +1718,14 @@ public class MesHqlPack {
if (!StringUtils.isEmpty(mesCustOrder.getPartNo())) {
DdlPreparedPack.getStringLikerPack(mesCustOrder.getPartNo(), "partNo", packBean);
}
if (!StringUtils.isEmpty(mesCustOrder.getOrderNo())) {
DdlPreparedPack.getStringLikerPack(mesCustOrder.getOrderNo(), "orderNo", packBean);
}
if (!StringUtils.isEmpty(mesCustOrder.getCustCode())) {
DdlPreparedPack.getStringEqualPack(mesCustOrder.getCustCode(), "custCode", packBean);
DdlPreparedPack.getStringLikerPack(mesCustOrder.getCustCode(), "custCode", packBean);
}
if (!StringUtils.isEmpty(mesCustOrder.getCustOrderNo())) {
DdlPreparedPack.getStringEqualPack(mesCustOrder.getCustOrderNo(), "custOrderNo", packBean);
DdlPreparedPack.getStringLikerPack(mesCustOrder.getCustOrderNo(), "custOrderNo", packBean);
}
if (!StringUtils.isEmpty(mesCustOrder.getCreateUser())) {
DdlPreparedPack.getStringLikerPack(mesCustOrder.getCreateUser(), "createUser", packBean);
@ -1737,6 +1740,10 @@ public class MesHqlPack {
mesCustOrder.getOrderTimeStart(),
mesCustOrder.getOrderTimeEnd(),
"orderDate", packBean, true);
DdlPreparedPack.timeBuilder(
mesCustOrder.getCreateDateTimeStart(),
mesCustOrder.getCreateDateTimeEnd(),
"createDatetime", packBean, true);
return packBean;
}
}

@ -0,0 +1,51 @@
package cn.estsh.i3plus.pojo.wms.bean;
import cn.estsh.i3plus.pojo.base.annotation.AnnoOutputColumn;
import cn.estsh.i3plus.pojo.base.bean.BaseBean;
import cn.estsh.i3plus.pojo.base.enumutil.WmsEnumUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiParam;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Transient;
/**
* @Description :
* @Reference :
* @Author : gcj
* @CreateDate : 2019-11-07 16:06
* @Modify:
**/
@Data
@Entity
@DynamicInsert
@DynamicUpdate
@EqualsAndHashCode(callSuper = true)
@Table(name = "WMS_CONTAINER_TYPE")
@Api("容器类型")
public class WmsContainerType extends BaseBean {
private static final long serialVersionUID = 4849044986767609347L;
@Column(name = "CT_CODE",unique = true)
@ApiParam(value = "容器类型代码")
private String ctCode;
@Column(name = "CT_NAME")
@ApiParam(value = "容器类型名称")
private String ctName;
@Column(name = "USE_LIMIT")
@ApiParam(value = "使用期限")
private Integer useLimit;
@Column(name = "IS_RECYCLE")
@ApiParam(value = "是否回收")
@AnnoOutputColumn(refClass = WmsEnumUtil.TRUE_OR_FALSE.class, refForeignKey = "value", value = "description")
private Integer isRecycle;
}

@ -233,14 +233,14 @@ public class WmsMoveSn extends BaseBean {
this.refSrc = refSrc;
}
public WmsMoveSn(String partNo, String srcLocateNo, String destLocateNo, String createUser, String createDatetime, Integer busiTypeCode, Double qty) {
public WmsMoveSn(String partNo, String srcLocateNo, String destLocateNo, String createUser, String createDatetime, Integer busiTypeCode, Double destQty) {
this.partNo = partNo;
this.srcLocateNo = srcLocateNo;
this.destLocateNo = destLocateNo;
this.createUser = createUser;
this.createDatetime = createDatetime;
this.busiTypeCode = busiTypeCode;
this.qty = qty;
this.destQty = destQty;
}
public WmsMoveSn(String organizeCode, String orderNo, Integer item, String partNo, String partNameRdd,

@ -0,0 +1,64 @@
package cn.estsh.i3plus.pojo.wms.bean;
import cn.estsh.i3plus.pojo.base.bean.BaseBean;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiParam;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Transient;
/**
* @Description :
* @Reference :
* @Author :
* @CreateDate : 2019-11-07 16:06
* @Modify:
**/
@Data
@Entity
@DynamicInsert
@DynamicUpdate
@EqualsAndHashCode(callSuper = true)
@Table(name = "WMS_PACKAGE_SPEC")
@Api("包装规格")
public class WmsPackageSpec extends BaseBean {
private static final long serialVersionUID = 4849044986767609445L;
@Column(name = "SPEC_CODE",unique = true)
@ApiParam(value = "包装规格代码")
private String specCode;
@Column(name = "SPEC_NAME")
@ApiParam(value = "包装规格名称")
private String specName;
@Column(name = "QTY")
@ApiParam(value = "包装数量")
private Double qty;
@Column(name = "PARENT_SPEC")
@ApiParam(value = "上级规格")
private String parentSpec;
@Column(name = "SPEC_LEVEL")
@ApiParam(value = "规格层级")
private String specLevel;
@Column(name = "IS_MIXED")
@ApiParam(value = "是否混包")
private Integer isMixed;
@Column(name = "POCKET_TYPE")
@ApiParam(value = "默认容器类型")
private String pocketType;
@ApiParam(value = "上级规格名称")
@Transient
private String parentName;
}

@ -194,6 +194,19 @@ public class WmsPart extends BaseBean {
public WmsPart() {
}
public Double getQty() {
return qty == null? 0:qty;
}
public Double getMin() {
return min == null? 0: min;
}
public Double getMax() {
return max == null? 0:max;
}
public WmsPart(String partNo, String partName, Double maxQty, Double minQty, Double cqty, String partType) {
this.partNo = partNo;
this.partName = partName;

@ -0,0 +1,68 @@
package cn.estsh.i3plus.pojo.wms.bean;
import cn.estsh.i3plus.pojo.base.annotation.AnnoOutputColumn;
import cn.estsh.i3plus.pojo.base.bean.BaseBean;
import cn.estsh.i3plus.pojo.base.enumutil.WmsEnumUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiParam;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
/**
* @Description :
* @Reference :
* @Author :
* @CreateDate : 2019-11-07 16:06
* @Modify:
**/
@Data
@Entity
@DynamicInsert
@DynamicUpdate
@EqualsAndHashCode(callSuper = true)
@Table(name = "WMS_PART_PACKAGE")
@Api("物料包装关系")
public class WmsPartPackage extends BaseBean {
private static final long serialVersionUID = 4849044986767609345L;
@Column(name = "PART_NO",unique = true)
@ApiParam(value = "物料编码")
private String partNo;
@Column(name = "SPEC_CODE")
@ApiParam(value = "包装规格代码")
private String specCode;
@Column(name = "SNP_QTY")
@ApiParam(value = "单包装数量")
private String snpQty;
@Column(name = "BOX_QTY")
@ApiParam(value = "包装箱数")
private String boxQty;
@Column(name = "IS_DEFAULT")
@ApiParam(value = "是否默认包规")
private String isDefault;
@Column(name = "IS_MIXED")
@ApiParam(value = "是否混包")
private String isMixed;
@Column(name = "IS_PRINT")
@ApiParam(value = "是否打印包装清单")
private String isPrint;
@Column(name = "TEMPLATE_NO")
@ApiParam(value = "包装清单模板")
private String templateNo;
@Column(name = "POCKET_TYPE")
@ApiParam(value = "容器类型")
private String pocketType;
}

@ -0,0 +1,27 @@
package cn.estsh.i3plus.pojo.wms.dto;
import cn.estsh.i3plus.pojo.base.common.Pager;
import cn.estsh.i3plus.pojo.wms.bean.WmsPartPackage;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiParam;
import lombok.Data;
import java.util.List;
/**
* @Description :
* @Reference :
* @Author : gcj
* @CreateDate : 2019-11-07 16:06
* @Modify:
**/
@Data
@Api("物料包装关系入参")
public class PartPackagDto{
@ApiParam(value = "物料编码")
private String partNo;
@ApiParam(value = "工厂代码")
private List<WmsPartPackage> partPackages;
}

@ -2,15 +2,27 @@ package cn.estsh.i3plus.pojo.wms.dto;
import cn.estsh.i3plus.pojo.base.common.Pager;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiParam;
import lombok.Data;
/**
* @Description :
* @Reference :
* @Author : gcj
* @CreateDate : 2019-11-07 16:06
* @Modify:
**/
@Data
@Api("库存预警入参")
public class QuanWarnDto extends Pager {
@ApiParam(value = "工厂代码")
private String organizeCode;
@ApiParam(value = "是否选择")
private Integer checked;
@ApiParam(value = "物料编码")
private String partNo;
@ApiParam(value = "物料类型")
private String partType;
public Integer getChecked() {

@ -45,6 +45,9 @@ public class WmsDataAuthModel extends BaseBean {
@ApiParam("业务类型列表")
private List<String> busiTypeList;
@ApiParam("业务类型列表")
private List<String> busiOperationTypeList;
@ApiParam(
value = "新增操作",
example = "0"

@ -0,0 +1,43 @@
package cn.estsh.i3plus.pojo.wms.modelbean;
import cn.estsh.i3plus.pojo.base.bean.BaseBean;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiParam;
import lombok.Data;
import javax.persistence.Entity;
/**
* @Description : model
* @Reference :
* @Author : qianhuasheng
* @CreateDate : 2019-10-31 20:04
* @Modify:
**/
@Data
@Entity
@Api("静态盘点查询输出model")
public class WmsStaticCsModel extends BaseBean {
public WmsStaticCsModel(String staticStr,String orderNo, String locateNo, String sn, double qty ) {
this.orderNo = orderNo;
this.locateNo = locateNo;
this.sn = sn;
this.qty = qty;
this.staticStr = staticStr;
}
@ApiParam(value = "订单号")
private String orderNo;
@ApiParam(value = "库存号")
private String locateNo;
@ApiParam(value = "条码")
private String sn;
@ApiParam(value = "数量")
private double qty;
@ApiParam(value = "状态")
private String staticStr;
public WmsStaticCsModel() {
}
}

@ -0,0 +1,16 @@
package cn.estsh.i3plus.pojo.wms.repository;
import cn.estsh.i3plus.pojo.base.jpa.dao.BaseRepository;
import cn.estsh.i3plus.pojo.wms.bean.WmsContainerType;
import org.springframework.stereotype.Repository;
/**
* @Description :Repository
* @Reference :
* @Author : gcj
* @CreateDate : 2019-11-08 10:19
* @Modify:
**/
@Repository
public interface WmsContainerTypeRepository extends BaseRepository<WmsContainerType, Long> {
}

@ -0,0 +1,17 @@
package cn.estsh.i3plus.pojo.wms.repository;
import cn.estsh.i3plus.pojo.base.jpa.dao.BaseRepository;
import cn.estsh.i3plus.pojo.wms.bean.WmsContainerType;
import cn.estsh.i3plus.pojo.wms.bean.WmsPackageSpec;
import org.springframework.stereotype.Repository;
/**
* @Description :Repository
* @Reference :
* @Author : gcj
* @CreateDate : 2019-11-08 10:19
* @Modify:
**/
@Repository
public interface WmsPackageSpecRepository extends BaseRepository<WmsPackageSpec, Long> {
}

@ -0,0 +1,17 @@
package cn.estsh.i3plus.pojo.wms.repository;
import cn.estsh.i3plus.pojo.base.jpa.dao.BaseRepository;
import cn.estsh.i3plus.pojo.wms.bean.WmsPackageSpec;
import cn.estsh.i3plus.pojo.wms.bean.WmsPartPackage;
import org.springframework.stereotype.Repository;
/**
* @Description :Repository
* @Reference :
* @Author : gcj
* @CreateDate : 2019-11-08 10:19
* @Modify:
**/
@Repository
public interface WmsPartPackageRepository extends BaseRepository<WmsPartPackage, Long> {
}
Loading…
Cancel
Save