fix:修改仓库出库单据接口

main
HuangHuiKang 13 hours ago
parent 11f59d3cb5
commit e349181c17

@ -25,7 +25,6 @@ import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutApproveRecord
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemDO;
import cn.iocoder.yudao.module.erp.enums.ErpStockOutStatusEnum;
import cn.iocoder.yudao.module.erp.enums.ErpStockOutUsageTypeEnum;
import cn.iocoder.yudao.module.erp.service.mold.MoldBrandService;
import cn.iocoder.yudao.module.erp.service.mold.MoldService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
@ -274,7 +273,6 @@ public class ErpStockOutController {
Map<Long, List<cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO>> pageMoldListMap) {
ErpStockOutRespVO stockOutVO = BeanUtils.toBean(stockOut, ErpStockOutRespVO.class);
stockOutVO.setStatusName(getStockOutStatusName(stockOut.getStatus()));
stockOutVO.setOutUsageTypeName(ErpStockOutUsageTypeEnum.getNameByType(stockOut.getOutUsageType()));
Map<Long, AdminUserRespDTO> userMap = pageUserMap != null ? pageUserMap : adminUserApi.getUserMap(convertListByFlatMap(
Collections.singletonList(stockOut), item -> Stream.of(NumberUtils.parseLong(item.getCreator()),
item.getResponserId(), item.getAuditUserId())));
@ -325,6 +323,26 @@ public class ErpStockOutController {
}));
stockOutVO.setProductNames(CollUtil.join(stockOutVO.getItems(), ",", ErpStockOutRespVO.Item::getProductName));
}
if (CollUtil.isNotEmpty(stockOutVO.getItems())) {
ErpStockOutRespVO.Item firstItem = stockOutVO.getItems().get(0);
stockOutVO.setOutUsageType(firstItem.getOutUsageType());
stockOutVO.setOutUsageTypeName(firstItem.getOutUsageTypeName());
stockOutVO.setRepairId(firstItem.getRepairId());
stockOutVO.setRepairName(firstItem.getRepairName());
stockOutVO.setRepairDeviceId(firstItem.getRepairDeviceId());
stockOutVO.setRepairDeviceName(firstItem.getRepairDeviceName());
stockOutVO.setMaintenanceId(firstItem.getMaintenanceId());
stockOutVO.setMaintenanceName(firstItem.getMaintenanceName());
} else {
stockOutVO.setOutUsageType(null);
stockOutVO.setOutUsageTypeName(null);
stockOutVO.setRepairId(null);
stockOutVO.setRepairName(null);
stockOutVO.setRepairDeviceId(null);
stockOutVO.setRepairDeviceName(null);
stockOutVO.setMaintenanceId(null);
stockOutVO.setMaintenanceName(null);
}
if (stockOut.getCustomerId() != null) {
Map<Long, ErpCustomerDO> customerMap = pageCustomerMap != null ? pageCustomerMap
: customerService.getCustomerMap(Collections.singleton(stockOut.getCustomerId()));

@ -32,7 +32,7 @@ public class ErpStockInPageReqVO extends PageParam {
@Schema(description = "状态", example = "10")
@InEnum(ErpStockInStatusEnum.class)
private Integer status;
private List<Integer> statusList;
@Schema(description = "入库类型", example = "其它入库")
private String inType;

@ -41,7 +41,7 @@ public class ErpStockOutPageReqVO extends PageParam {
@Schema(description = "状态", example = "10")
@InEnum(ErpStockOutStatusEnum.class)
private Integer status;
private List<Integer> statusList;
@Schema(description = "审核人编号", example = "1")
private Long auditUserId;

@ -181,6 +181,30 @@ public class ErpStockOutRespVO {
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
private BigDecimal count;
@Schema(description = "出库用途", example = "1")
private Integer outUsageType;
@Schema(description = "出库用途名称", example = "维修领用")
private String outUsageTypeName;
@Schema(description = "维修单编号", example = "1001")
private Long repairId;
@Schema(description = "维修单名称快照", example = "设备维修单A")
private String repairName;
@Schema(description = "维修单设备编号", example = "2001")
private Long repairDeviceId;
@Schema(description = "维修单设备名称快照", example = "设备A")
private String repairDeviceName;
@Schema(description = "保养单编号", example = "3001")
private Long maintenanceId;
@Schema(description = "保养单名称快照", example = "设备保养单A")
private String maintenanceName;
@Schema(description = "备注", example = "备注信息")
private String remark;

@ -1,18 +1,15 @@
package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import cn.iocoder.yudao.module.erp.enums.ErpStockOutUsageTypeEnum;
@Schema(description = "管理后台 - ERP 其它出库单新增/修改 Request VO")
@Data
public class ErpStockOutSaveReqVO {
@ -29,20 +26,6 @@ public class ErpStockOutSaveReqVO {
@Schema(description = "出库类型", example = "其他出库")
private String outType;
@Schema(description = "出库用途", example = "1")
@InEnum(ErpStockOutUsageTypeEnum.class)
@NotNull(message = "出库用途不能为空")
private Integer outUsageType;
@Schema(description = "维修单编号", example = "1001")
private Long repairId;
@Schema(description = "维修单设备编号", example = "2001")
private Long repairDeviceId;
@Schema(description = "保养单编号", example = "3001")
private Long maintenanceId;
@Schema(description = "出库时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "出库时间不能为空")
private LocalDateTime outTime;
@ -56,40 +39,11 @@ public class ErpStockOutSaveReqVO {
@Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc")
private String fileUrl;
@Schema(description = "出库项列表", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "出库项列表", implementation = ErpStockOutSaveReqVOItem.class)
@NotEmpty(message = "出库项列表不能为空")
@Valid
private List<Item> items;
private List<ErpStockOutSaveReqVOItem> items;
@Schema(description = "计划单 Code", example = "PLAN20240601")
private String planCode;
@Data
public static class Item {
@Schema(description = "出库项编号", example = "11756")
private Long id;
@Schema(description = "模具组 id", example = "101")
private Long moldSetId;
@Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113")
private Long warehouseId;
@Schema(description = "库区编号", example = "1")
private Long areaId;
@Schema(description = "产品 id", example = "3113")
private Long productId;
@Schema(description = "产品单价", example = "100.00")
private BigDecimal productPrice;
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
private BigDecimal count;
@Schema(description = "备注", example = "备注信息")
private String remark;
}
}

@ -0,0 +1,52 @@
package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.erp.enums.ErpStockOutUsageTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
@Schema(description = "ERP 其它出库单明细项")
@Data
public class ErpStockOutSaveReqVOItem {
@Schema(description = "出库项编号", example = "11756")
private Long id;
@Schema(description = "模具组 id", example = "101")
private Long moldSetId;
@Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113")
private Long warehouseId;
@Schema(description = "库区编号", example = "1")
private Long areaId;
@Schema(description = "产品 id", example = "3113")
private Long productId;
@Schema(description = "产品单价", example = "100.00")
private BigDecimal productPrice;
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
private BigDecimal count;
@Schema(description = "出库用途", example = "1")
@InEnum(ErpStockOutUsageTypeEnum.class)
@NotNull(message = "出库用途不能为空")
private Integer outUsageType;
@Schema(description = "维修单编号", example = "1001")
private Long repairId;
@Schema(description = "维修单设备编号", example = "2001")
private Long repairDeviceId;
@Schema(description = "保养单编号", example = "3001")
private Long maintenanceId;
@Schema(description = "备注", example = "备注信息")
private String remark;
}

@ -48,36 +48,6 @@ public class ErpStockOutDO extends BaseDO {
private Long responserId;
//@Schema(description = "出库类型", example = "随便")
private String outType;
/**
*
*
* {@link cn.iocoder.yudao.module.erp.enums.ErpStockOutUsageTypeEnum}
*/
private Integer outUsageType;
/**
*
*/
private String repairName;
/**
*
*/
private Long repairId;
/**
*
*/
private Long repairDeviceId;
/**
*
*/
private String repairDeviceName;
/**
*
*/
private Long maintenanceId;
/**
*
*/
private String maintenanceName;
/**
*
*/

@ -37,6 +37,40 @@ public class ErpStockOutItemDO extends BaseDO {
* {@link ErpStockOutDO#getId()}
*/
private Long outId;
/**
*
*
* {@link cn.iocoder.yudao.module.erp.enums.ErpStockOutUsageTypeEnum}
*/
private Integer outUsageType;
/**
*
*/
private String outUsageTypeName;
/**
*
*/
private Long repairId;
/**
*
*/
private String repairName;
/**
*
*/
private Long repairDeviceId;
/**
*
*/
private String repairDeviceName;
/**
*
*/
private Long maintenanceId;
/**
*
*/
private String maintenanceName;
/**
*
*

@ -21,7 +21,7 @@ public interface ErpStockInMapper extends BaseMapperX<ErpStockInDO> {
.likeIfPresent(ErpStockInDO::getNo, reqVO.getNo())
.eqIfPresent(ErpStockInDO::getSupplierId, reqVO.getSupplierId())
.betweenIfPresent(ErpStockInDO::getInTime, reqVO.getInTime())
.eqIfPresent(ErpStockInDO::getStatus, reqVO.getStatus())
.inIfPresent(ErpStockInDO::getStatus, reqVO.getStatusList())
.eqIfPresent(ErpStockInDO::getInType, reqVO.getInType())
.inIfPresent(ErpStockInDO::getInType, reqVO.getInTypeList())
.likeIfPresent(ErpStockInDO::getRemark, reqVO.getRemark())

@ -25,7 +25,7 @@ public interface ErpStockOutMapper extends BaseMapperX<ErpStockOutDO> {
.eqIfPresent(ErpStockOutDO::getOutType, reqVO.getOutType())
.inIfPresent(ErpStockOutDO::getOutType, reqVO.getOutTypeList())
.betweenIfPresent(ErpStockOutDO::getOutTime, reqVO.getOutTime())
.eqIfPresent(ErpStockOutDO::getStatus, reqVO.getStatus())
.inIfPresent(ErpStockOutDO::getStatus, reqVO.getStatusList())
.likeIfPresent(ErpStockOutDO::getRemark, reqVO.getRemark())
.eqIfPresent(ErpStockOutDO::getCreator, reqVO.getCreator())
.eqIfPresent(ErpStockOutDO::getAuditUserId, reqVO.getAuditUserId())

@ -14,6 +14,7 @@ import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProduc
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutAuditReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVOItem;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSubmitReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutApproveRecordDO;
@ -132,15 +133,14 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
.setStatus(status)
.setTotalCount(getSumValue(stockOutItems, ErpStockOutItemDO::getCount, BigDecimal::add))
.setTotalPrice(getSumValue(stockOutItems, ErpStockOutItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)));
fillUsageSnapshot(stockOut, createReqVO.getOutUsageType(), createReqVO.getRepairId(),
createReqVO.getRepairDeviceId(), createReqVO.getMaintenanceId());
fillUsageSnapshot(stockOutItems, createReqVO.getItems());
stockOutMapper.insert(stockOut);
stockOutItems.forEach(item -> item.setOutId(stockOut.getId()));
stockOutItemMapper.insertBatch(stockOutItems);
if (createReqVO.getOutType().equals("模具出库")) {
//修改模具组状态
for (ErpStockOutSaveReqVO.Item item : createReqVO.getItems()) {
for (ErpStockOutSaveReqVOItem item : createReqVO.getItems()) {
MoldBrandDO moldBrandDO = moldBrandMapper.selectById(item.getMoldSetId());
moldBrandDO.setStatus(MoldBrandStatusEnum.STANDBY.getStatus());
moldBrandMapper.updateById(moldBrandDO);
@ -176,8 +176,7 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
.setNeedAudit(needAudit)
.setTotalCount(getSumValue(stockOutItems, ErpStockOutItemDO::getCount, BigDecimal::add))
.setTotalPrice(getSumValue(stockOutItems, ErpStockOutItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)));
fillUsageSnapshot(updateObj, updateReqVO.getOutUsageType(), updateReqVO.getRepairId(),
updateReqVO.getRepairDeviceId(), updateReqVO.getMaintenanceId());
fillUsageSnapshot(stockOutItems, updateReqVO.getItems());
stockOutMapper.updateById(updateObj);
updateStockOutItemList(updateReqVO.getId(), stockOutItems);
}
@ -415,29 +414,33 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
return !AUDIT_CONFIG_DISABLE_VALUE.equals(configApi.getConfigValueByCategoryAndKey(AUDIT_CONFIG_CATEGORY, AUDIT_CONFIG_KEY));
}
private void fillUsageSnapshot(ErpStockOutDO stockOut, Integer outUsageType, Long repairId,
Long repairDeviceId, Long maintenanceId) {
stockOut.setOutUsageType(outUsageType);
stockOut.setRepairId(null);
stockOut.setRepairName(null);
stockOut.setRepairDeviceId(null);
stockOut.setRepairDeviceName(null);
stockOut.setMaintenanceId(null);
stockOut.setMaintenanceName(null);
if (ErpStockOutUsageTypeEnum.REPAIR_RECEIVE.getType().equals(outUsageType) && repairId != null) {
DvRepairRespDTO repair = dvRepairApi.getDvRepair(repairId);
if (repair != null) {
stockOut.setRepairId(repair.getId());
stockOut.setRepairName(repair.getRepairName());
stockOut.setRepairDeviceId(repairDeviceId != null ? repairDeviceId : repair.getMachineryId());
stockOut.setRepairDeviceName(repair.getMachineryName());
}
} else if (ErpStockOutUsageTypeEnum.MAINTENANCE_RECEIVE.getType().equals(outUsageType) && maintenanceId != null) {
TicketManagementRespDTO maintenance = ticketManagementApi.getTicketManagement(maintenanceId);
if (maintenance != null) {
stockOut.setMaintenanceId(maintenance.getId());
stockOut.setMaintenanceName(maintenance.getPlanNo());
private void fillUsageSnapshot(List<ErpStockOutItemDO> stockOutItems, List<ErpStockOutSaveReqVOItem> items) {
for (int i = 0; i < stockOutItems.size(); i++) {
ErpStockOutItemDO stockOutItem = stockOutItems.get(i);
ErpStockOutSaveReqVOItem item = items.get(i);
stockOutItem.setOutUsageType(item.getOutUsageType());
stockOutItem.setOutUsageTypeName(ErpStockOutUsageTypeEnum.getNameByType(item.getOutUsageType()));
stockOutItem.setRepairId(null);
stockOutItem.setRepairName(null);
stockOutItem.setRepairDeviceId(null);
stockOutItem.setRepairDeviceName(null);
stockOutItem.setMaintenanceId(null);
stockOutItem.setMaintenanceName(null);
if (ErpStockOutUsageTypeEnum.REPAIR_RECEIVE.getType().equals(item.getOutUsageType()) && item.getRepairId() != null) {
DvRepairRespDTO repair = dvRepairApi.getDvRepair(item.getRepairId());
if (repair != null) {
stockOutItem.setRepairId(repair.getId());
stockOutItem.setRepairName(repair.getRepairName());
stockOutItem.setRepairDeviceId(item.getRepairDeviceId() != null ? item.getRepairDeviceId() : repair.getMachineryId());
stockOutItem.setRepairDeviceName(repair.getMachineryName());
}
} else if (ErpStockOutUsageTypeEnum.MAINTENANCE_RECEIVE.getType().equals(item.getOutUsageType()) && item.getMaintenanceId() != null) {
TicketManagementRespDTO maintenance = ticketManagementApi.getTicketManagement(item.getMaintenanceId());
if (maintenance != null) {
stockOutItem.setMaintenanceId(maintenance.getId());
stockOutItem.setMaintenanceName(maintenance.getPlanNo());
}
}
}
}
@ -454,13 +457,13 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
.build());
}
private List<ErpStockOutItemDO> validateStockOutItems(List<ErpStockOutSaveReqVO.Item> list, String outType) {
private List<ErpStockOutItemDO> validateStockOutItems(List<ErpStockOutSaveReqVOItem> list, String outType) {
validateWarehouseAreas(list);
if (Objects.equals(outType, "模具出库")) {
List<MoldBrandDO> moldList = moldBrandService.validMoldList(convertSet(list, ErpStockOutSaveReqVO.Item::getMoldSetId));
List<MoldBrandDO> moldList = moldBrandService.validMoldList(convertSet(list, ErpStockOutSaveReqVOItem::getMoldSetId));
Map<Long, MoldBrandDO> moldMap = convertMap(moldList, MoldBrandDO::getId);
Map<Long, WarehouseAreaDO> areaMap = warehouseAreaService.getWarehouseAreaMap(
convertSet(list, ErpStockOutSaveReqVO.Item::getAreaId));
convertSet(list, ErpStockOutSaveReqVOItem::getAreaId));
return convertList(list, item -> {
MoldBrandDO moldBrand = moldMap.get(item.getMoldSetId());
return ErpStockOutItemDO.builder()
@ -475,26 +478,39 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
.productPrice(item.getProductPrice())
.count(item.getCount())
.totalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount()))
.outUsageType(item.getOutUsageType())
.outUsageTypeName(ErpStockOutUsageTypeEnum.getNameByType(item.getOutUsageType()))
.repairId(item.getRepairId())
.repairDeviceId(item.getRepairDeviceId())
.maintenanceId(item.getMaintenanceId())
.remark(item.getRemark())
.build();
});
}
List<ErpProductDO> productList = productService.validProductList(convertSet(list, ErpStockOutSaveReqVO.Item::getProductId));
List<ErpProductDO> productList = productService.validProductList(convertSet(list, ErpStockOutSaveReqVOItem::getProductId));
Map<Long, ErpProductDO> productMap = convertMap(productList, ErpProductDO::getId);
Map<Long, WarehouseAreaDO> areaMap = warehouseAreaService.getWarehouseAreaMap(
convertSet(list, ErpStockOutSaveReqVO.Item::getAreaId));
convertSet(list, ErpStockOutSaveReqVOItem::getAreaId));
return convertList(list, item -> BeanUtils.toBean(item, ErpStockOutItemDO.class, target -> target
.setAreaName(areaMap.containsKey(target.getAreaId()) ? areaMap.get(target.getAreaId()).getAreaName() : null)
.setProductUnitId(productMap.get(target.getProductId()).getUnitId())
.setTotalPrice(MoneyUtils.priceMultiply(target.getProductPrice(), target.getCount()))));
.setTotalPrice(MoneyUtils.priceMultiply(target.getProductPrice(), target.getCount()))
.setOutUsageType(item.getOutUsageType())
.setOutUsageTypeName(ErpStockOutUsageTypeEnum.getNameByType(item.getOutUsageType()))
.setRepairId(item.getRepairId())
.setRepairDeviceId(item.getRepairDeviceId())
.setRepairName(null)
.setRepairDeviceName(null)
.setMaintenanceId(item.getMaintenanceId())
.setMaintenanceName(null)));
}
private void validateWarehouseAreas(List<ErpStockOutSaveReqVO.Item> list) {
private void validateWarehouseAreas(List<ErpStockOutSaveReqVOItem> list) {
Map<Long, ErpWarehouseDO> warehouseMap = convertMap(
warehouseService.validWarehouseList(convertSet(list, ErpStockOutSaveReqVO.Item::getWarehouseId)),
warehouseService.validWarehouseList(convertSet(list, ErpStockOutSaveReqVOItem::getWarehouseId)),
ErpWarehouseDO::getId);
Map<Long, WarehouseAreaDO> areaMap = warehouseAreaService.getWarehouseAreaMap(
convertSet(list, ErpStockOutSaveReqVO.Item::getAreaId));
convertSet(list, ErpStockOutSaveReqVOItem::getAreaId));
list.forEach(item -> {
if (item.getAreaId() == null) {
return;

@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.erp.controller.admin.autocode.util.AutoCodeUtil;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSaveReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVOItem;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpWarehouseMapper;
@ -260,7 +261,7 @@ public class PlanServiceImpl implements PlanService {
itemRequisitionService.updateItemRequisition(saveReqVO);
// 创建入领料出库单
ErpStockOutSaveReqVO stockOut = new ErpStockOutSaveReqVO();
List<ErpStockOutSaveReqVO.Item> itemList = new ArrayList<>();
List<ErpStockOutSaveReqVOItem> itemList = new ArrayList<>();
stockOut.setOutTime(LocalDateTime.now());
stockOut.setOutType("领料出库");
@ -270,7 +271,7 @@ public class PlanServiceImpl implements PlanService {
.last("limit 1")
);
for (ItemRequisitionAndStock requisition : list) {
ErpStockOutSaveReqVO.Item item = new ErpStockOutSaveReqVO.Item();
ErpStockOutSaveReqVOItem item = new ErpStockOutSaveReqVOItem();
item.setWarehouseId(warehouse.getId());
item.setProductId(requisition.getItemId());
item.setCount(calculateLossNumber(requisition.getItemId(), requisition.getNumber(), bomYieldRateMap, createReqVO.getIsCalculateLoss()));

Loading…
Cancel
Save