add bom
parent
71dca95ea3
commit
91f459df6c
@ -0,0 +1,44 @@
|
||||
package cn.iocoder.yudao.module.mes.controller.admin.bom.vo;
|
||||
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import java.math.BigDecimal;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 产品BOM分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class BomPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "BOM编码")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "BOM版本")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "产品ID", example = "5633")
|
||||
private Long productId;
|
||||
|
||||
@Schema(description = "单位ID", example = "24261")
|
||||
private Long unitId;
|
||||
|
||||
@Schema(description = "成品率%")
|
||||
private BigDecimal yieldRate;
|
||||
|
||||
@Schema(description = "备注", example = "你说的对")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "是否启用")
|
||||
private Boolean isEnable;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package cn.iocoder.yudao.module.mes.controller.admin.bom.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import com.alibaba.excel.annotation.*;
|
||||
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
||||
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
||||
|
||||
@Schema(description = "管理后台 - 产品BOM Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class BomRespVO {
|
||||
|
||||
@Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "23849")
|
||||
@ExcelProperty("ID")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "BOM编码", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("BOM编码")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "BOM版本", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("BOM版本")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "5633")
|
||||
@ExcelProperty("产品ID")
|
||||
private Long productId;
|
||||
|
||||
@Schema(description = "单位ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "24261")
|
||||
@ExcelProperty("单位ID")
|
||||
private Long unitId;
|
||||
|
||||
@Schema(description = "成品率%")
|
||||
@ExcelProperty("成品率%")
|
||||
private BigDecimal yieldRate;
|
||||
|
||||
@Schema(description = "备注", example = "你说的对")
|
||||
@ExcelProperty("备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty(value = "是否启用", converter = DictConvert.class)
|
||||
@DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
|
||||
private Boolean isEnable;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package cn.iocoder.yudao.module.mes.controller.admin.bom.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import cn.iocoder.yudao.module.mes.dal.dataobject.bom.BomDetailDO;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Schema(description = "管理后台 - 产品BOM新增/修改 Request VO")
|
||||
@Data
|
||||
public class BomSaveReqVO {
|
||||
|
||||
@Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "23849")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "BOM编码", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "BOM编码不能为空")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "BOM版本", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "BOM版本不能为空")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "5633")
|
||||
@NotNull(message = "产品ID不能为空")
|
||||
private Long productId;
|
||||
|
||||
@Schema(description = "单位ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "24261")
|
||||
@NotNull(message = "单位ID不能为空")
|
||||
private Long unitId;
|
||||
|
||||
@Schema(description = "成品率%")
|
||||
private BigDecimal yieldRate;
|
||||
|
||||
@Schema(description = "备注", example = "你说的对")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "是否启用不能为空")
|
||||
private Boolean isEnable;
|
||||
|
||||
@Schema(description = "产品BOM明细列表")
|
||||
private List<BomDetailDO> bomDetails;
|
||||
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package cn.iocoder.yudao.module.mes.dal.dataobject.bom;
|
||||
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
|
||||
/**
|
||||
* 产品BOM DO
|
||||
*
|
||||
* @author 内蒙必硕
|
||||
*/
|
||||
@TableName("mes_bom")
|
||||
@KeySequence("mes_bom_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BomDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* BOM编码
|
||||
*/
|
||||
private String code;
|
||||
/**
|
||||
* BOM版本
|
||||
*/
|
||||
private String version;
|
||||
/**
|
||||
* 产品ID
|
||||
*/
|
||||
private Long productId;
|
||||
/**
|
||||
* 单位ID
|
||||
*/
|
||||
private Long unitId;
|
||||
/**
|
||||
* 成品率%
|
||||
*/
|
||||
private BigDecimal yieldRate;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 是否启用
|
||||
*
|
||||
* 枚举 {@link TODO infra_boolean_string 对应的类}
|
||||
*/
|
||||
private Boolean isEnable;
|
||||
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
package cn.iocoder.yudao.module.mes.dal.dataobject.bom;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
|
||||
/**
|
||||
* 产品BOM明细 DO
|
||||
*
|
||||
* @author 内蒙必硕
|
||||
*/
|
||||
@TableName("mes_bom_detail")
|
||||
@KeySequence("mes_bom_detail_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BomDetailDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 产品ID
|
||||
*/
|
||||
private Long productId;
|
||||
/**
|
||||
* 单位ID
|
||||
*/
|
||||
private Long unitId;
|
||||
/**
|
||||
* BOM ID
|
||||
*/
|
||||
private Long bomId;
|
||||
/**
|
||||
* 用量
|
||||
*/
|
||||
private BigDecimal usageNumber;
|
||||
/**
|
||||
* 损耗率%
|
||||
*/
|
||||
private BigDecimal yieldRate;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 是否启用
|
||||
*
|
||||
* 枚举 {@link TODO infra_boolean_string 对应的类}
|
||||
*/
|
||||
private Boolean isEnable;
|
||||
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package cn.iocoder.yudao.module.mes.dal.mysql.bom;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.module.mes.dal.dataobject.bom.BomDetailDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 产品BOM明细 Mapper
|
||||
*
|
||||
* @author 内蒙必硕
|
||||
*/
|
||||
@Mapper
|
||||
public interface BomDetailMapper extends BaseMapperX<BomDetailDO> {
|
||||
|
||||
default List<BomDetailDO> selectListByBomId(Long bomId) {
|
||||
return selectList(BomDetailDO::getBomId, bomId);
|
||||
}
|
||||
|
||||
default int deleteByBomId(Long bomId) {
|
||||
return delete(BomDetailDO::getBomId, bomId);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package cn.iocoder.yudao.module.mes.dal.mysql.bom;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.module.mes.dal.dataobject.bom.BomDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import cn.iocoder.yudao.module.mes.controller.admin.bom.vo.*;
|
||||
|
||||
/**
|
||||
* 产品BOM Mapper
|
||||
*
|
||||
* @author 内蒙必硕
|
||||
*/
|
||||
@Mapper
|
||||
public interface BomMapper extends BaseMapperX<BomDO> {
|
||||
|
||||
default PageResult<BomDO> selectPage(BomPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<BomDO>()
|
||||
.eqIfPresent(BomDO::getCode, reqVO.getCode())
|
||||
.eqIfPresent(BomDO::getVersion, reqVO.getVersion())
|
||||
.eqIfPresent(BomDO::getProductId, reqVO.getProductId())
|
||||
.eqIfPresent(BomDO::getUnitId, reqVO.getUnitId())
|
||||
.eqIfPresent(BomDO::getYieldRate, reqVO.getYieldRate())
|
||||
.eqIfPresent(BomDO::getRemark, reqVO.getRemark())
|
||||
.eqIfPresent(BomDO::getIsEnable, reqVO.getIsEnable())
|
||||
.betweenIfPresent(BomDO::getCreateTime, reqVO.getCreateTime())
|
||||
.orderByDesc(BomDO::getId));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,156 @@
|
||||
package cn.iocoder.yudao.module.mes.service.bom;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
|
||||
|
||||
import cn.iocoder.yudao.module.mes.controller.admin.bom.vo.*;
|
||||
import cn.iocoder.yudao.module.mes.dal.dataobject.bom.BomDO;
|
||||
import cn.iocoder.yudao.module.mes.dal.mysql.bom.BomMapper;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.hutool.core.util.RandomUtil.*;
|
||||
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
||||
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
|
||||
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* {@link BomServiceImpl} 的单元测试类
|
||||
*
|
||||
* @author 内蒙必硕
|
||||
*/
|
||||
@Import(BomServiceImpl.class)
|
||||
public class BomServiceImplTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private BomServiceImpl bomService;
|
||||
|
||||
@Resource
|
||||
private BomMapper bomMapper;
|
||||
|
||||
@Test
|
||||
public void testCreateBom_success() {
|
||||
// 准备参数
|
||||
BomSaveReqVO createReqVO = randomPojo(BomSaveReqVO.class).setId(null);
|
||||
|
||||
// 调用
|
||||
Long bomId = bomService.createBom(createReqVO);
|
||||
// 断言
|
||||
assertNotNull(bomId);
|
||||
// 校验记录的属性是否正确
|
||||
BomDO bom = bomMapper.selectById(bomId);
|
||||
assertPojoEquals(createReqVO, bom, "id");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateBom_success() {
|
||||
// mock 数据
|
||||
BomDO dbBom = randomPojo(BomDO.class);
|
||||
bomMapper.insert(dbBom);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
BomSaveReqVO updateReqVO = randomPojo(BomSaveReqVO.class, o -> {
|
||||
o.setId(dbBom.getId()); // 设置更新的 ID
|
||||
});
|
||||
|
||||
// 调用
|
||||
bomService.updateBom(updateReqVO);
|
||||
// 校验是否更新正确
|
||||
BomDO bom = bomMapper.selectById(updateReqVO.getId()); // 获取最新的
|
||||
assertPojoEquals(updateReqVO, bom);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateBom_notExists() {
|
||||
// 准备参数
|
||||
BomSaveReqVO updateReqVO = randomPojo(BomSaveReqVO.class);
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> bomService.updateBom(updateReqVO), BOM_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteBom_success() {
|
||||
// mock 数据
|
||||
BomDO dbBom = randomPojo(BomDO.class);
|
||||
bomMapper.insert(dbBom);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
Long id = dbBom.getId();
|
||||
|
||||
// 调用
|
||||
bomService.deleteBom(id);
|
||||
// 校验数据不存在了
|
||||
assertNull(bomMapper.selectById(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteBom_notExists() {
|
||||
// 准备参数
|
||||
Long id = randomLongId();
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> bomService.deleteBom(id), BOM_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
|
||||
public void testGetBomPage() {
|
||||
// mock 数据
|
||||
BomDO dbBom = randomPojo(BomDO.class, o -> { // 等会查询到
|
||||
o.setCode(null);
|
||||
o.setVersion(null);
|
||||
o.setProductId(null);
|
||||
o.setUnitId(null);
|
||||
o.setYieldRate(null);
|
||||
o.setRemark(null);
|
||||
o.setIsEnable(null);
|
||||
o.setCreateTime(null);
|
||||
});
|
||||
bomMapper.insert(dbBom);
|
||||
// 测试 code 不匹配
|
||||
bomMapper.insert(cloneIgnoreId(dbBom, o -> o.setCode(null)));
|
||||
// 测试 version 不匹配
|
||||
bomMapper.insert(cloneIgnoreId(dbBom, o -> o.setVersion(null)));
|
||||
// 测试 productId 不匹配
|
||||
bomMapper.insert(cloneIgnoreId(dbBom, o -> o.setProductId(null)));
|
||||
// 测试 unitId 不匹配
|
||||
bomMapper.insert(cloneIgnoreId(dbBom, o -> o.setUnitId(null)));
|
||||
// 测试 yieldRate 不匹配
|
||||
bomMapper.insert(cloneIgnoreId(dbBom, o -> o.setYieldRate(null)));
|
||||
// 测试 remark 不匹配
|
||||
bomMapper.insert(cloneIgnoreId(dbBom, o -> o.setRemark(null)));
|
||||
// 测试 isEnable 不匹配
|
||||
bomMapper.insert(cloneIgnoreId(dbBom, o -> o.setIsEnable(null)));
|
||||
// 测试 createTime 不匹配
|
||||
bomMapper.insert(cloneIgnoreId(dbBom, o -> o.setCreateTime(null)));
|
||||
// 准备参数
|
||||
BomPageReqVO reqVO = new BomPageReqVO();
|
||||
reqVO.setCode(null);
|
||||
reqVO.setVersion(null);
|
||||
reqVO.setProductId(null);
|
||||
reqVO.setUnitId(null);
|
||||
reqVO.setYieldRate(null);
|
||||
reqVO.setRemark(null);
|
||||
reqVO.setIsEnable(null);
|
||||
reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
|
||||
|
||||
// 调用
|
||||
PageResult<BomDO> pageResult = bomService.getBomPage(reqVO);
|
||||
// 断言
|
||||
assertEquals(1, pageResult.getTotal());
|
||||
assertEquals(1, pageResult.getList().size());
|
||||
assertPojoEquals(dbBom, pageResult.getList().get(0));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
|
||||
-- 将该删表 SQL 语句,添加到 yudao-module-mes-biz 模块的 test/resources/sql/clean.sql 文件里
|
||||
DELETE FROM "mes_bom";
|
||||
|
||||
-- 将该删表 SQL 语句,添加到 yudao-module-mes-biz 模块的 test/resources/sql/clean.sql 文件里
|
||||
DELETE FROM "mes_bom_detail";
|
||||
@ -0,0 +1,38 @@
|
||||
CREATE TABLE IF NOT EXISTS "mes_bom"
|
||||
(
|
||||
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||
"code" varchar NOT NULL,
|
||||
"version" varchar NOT NULL,
|
||||
"product_id" bigint NOT NULL,
|
||||
"unit_id" bigint NOT NULL,
|
||||
"yield_rate" varchar,
|
||||
"remark" varchar,
|
||||
"is_enable" bit NOT NULL,
|
||||
"creator" varchar DEFAULT '',
|
||||
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updater" varchar DEFAULT '',
|
||||
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
"deleted" bit NOT NULL DEFAULT FALSE,
|
||||
"tenant_id" bigint,
|
||||
PRIMARY KEY ("id")
|
||||
) COMMENT '产品BOM表';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "mes_bom_detail"
|
||||
(
|
||||
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||
"product_id" bigint NOT NULL,
|
||||
"unit_id" bigint NOT NULL,
|
||||
"bom_id" bigint NOT NULL,
|
||||
"usage_number" varchar NOT NULL,
|
||||
"yield_rate" varchar,
|
||||
"remark" varchar,
|
||||
"is_enable" bit,
|
||||
"creator" varchar DEFAULT '',
|
||||
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updater" varchar DEFAULT '',
|
||||
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
"deleted" bit NOT NULL DEFAULT FALSE,
|
||||
"tenant_id" bigint,
|
||||
PRIMARY KEY ("id")
|
||||
) COMMENT '产品BOM明细表';
|
||||
|
||||
Loading…
Reference in New Issue