opt: 托盘叫料、取料
This commit is contained in:
@@ -124,5 +124,5 @@ public interface IStructattrService extends IService<Structattr> {
|
|||||||
*/
|
*/
|
||||||
List<MdPbStoragevehicleextDto> outBoundSectDiv(StrategyStructParam param);
|
List<MdPbStoragevehicleextDto> outBoundSectDiv(StrategyStructParam param);
|
||||||
|
|
||||||
List<Structattr> getByVehicleCode(String search, boolean flag);
|
List<Structattr> getByVehicleCode(String search, String lockType, boolean flag);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -427,12 +427,12 @@ public class StructattrServiceImpl extends ServiceImpl<StructattrMapper, Structa
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Structattr> getByVehicleCode(String search, boolean flag) {
|
public List<Structattr> getByVehicleCode(String search, String lockType, boolean flag) {
|
||||||
LambdaQueryWrapper<Structattr> query = new QueryWrapper<Structattr>().lambda()
|
LambdaQueryWrapper<Structattr> query = new QueryWrapper<Structattr>().lambda()
|
||||||
.eq(Structattr::getIs_used, IOSConstant.IS_DELETE_YES)
|
.eq(Structattr::getIs_used, IOSConstant.IS_DELETE_YES)
|
||||||
.eq(Structattr::getLock_type, IOSEnum.LOCK_TYPE.code("未锁定"))
|
.eq(Structattr::getLock_type, lockType)
|
||||||
.eq(Structattr::getIs_delete, IOSConstant.IS_DELETE_NO)
|
.eq(Structattr::getIs_delete, IOSConstant.IS_DELETE_NO)
|
||||||
.eq(Structattr::getStruct_code, search)
|
.eq(Structattr::getStoragevehicle_code, search)
|
||||||
.eq(flag, Structattr::getIs_emptyvehicle, "1");
|
.eq(flag, Structattr::getIs_emptyvehicle, "1");
|
||||||
return this.list(query);
|
return this.list(query);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,33 +163,62 @@ public class DefaultPdaBuildParamService implements PdaBuildParamService {
|
|||||||
JSONObject insertInvObj = new JSONObject();
|
JSONObject insertInvObj = new JSONObject();
|
||||||
JSONArray rows = param.getJSONArray("rows");
|
JSONArray rows = param.getJSONArray("rows");
|
||||||
JSONObject row = rows.getJSONObject(0);
|
JSONObject row = rows.getJSONObject(0);
|
||||||
List<String> list = new TreeList<>();
|
List<JSONObject> result = filterAndSumByMaterialIdAndPcsn(rows);
|
||||||
for (int i = 0; i < rows.size(); i++) {
|
List<JSONObject> rowList = new ArrayList<>();
|
||||||
JSONObject object = rows.getJSONObject(i);
|
for (JSONObject rowObj : result) {
|
||||||
if (!list.contains(object.getString("pcsn"))) {
|
List<JSONObject> temps = outBillService.getCanuseSpecifiedIvt(MapOf.of("stor_id", row.getString("stor_id")
|
||||||
list.add(object.getString("pcsn"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
List<TurnoverDetailDto> rowss = new ArrayList<>();
|
|
||||||
for (String s : list) {
|
|
||||||
List<TurnoverDetailDto> temps = outBillService.getCanuseSpecifiedIvt(MapOf.of("stor_id", row.getString("stor_id")
|
|
||||||
, "sect_id", row.getString("sect_id")
|
, "sect_id", row.getString("sect_id")
|
||||||
, "struct_code", row.getString("struct_code")
|
, "struct_code", row.getString("struct_code")
|
||||||
, "material_code", row.getString("material_code")
|
, "material_code", row.getString("material_code")
|
||||||
, "pcsn", s
|
, "pcsn", rowObj.getString("pcsn")
|
||||||
, "vehicle_code", row.getString("vehicle_code")));
|
, "vehicle_code", row.getString("vehicle_code")));
|
||||||
if (temps.size() > 0) {
|
if (temps.size() > 0) {
|
||||||
rowss.add(temps.get(0));
|
JSONObject temp = temps.get(0);
|
||||||
|
temp.put("plan_qty", rowObj.getString("qty"));
|
||||||
|
rowList.add(temp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
insertInvObj.put("stor_id", sectattr.getStor_id());
|
insertInvObj.put("stor_id", sectattr.getStor_id());
|
||||||
insertInvObj.put("bill_status", "10");
|
insertInvObj.put("bill_status", "10");
|
||||||
insertInvObj.put("bill_type", param.getString("bill_type"));
|
insertInvObj.put("bill_type", param.getString("bill_type"));
|
||||||
insertInvObj.put("biz_date", DateUtil.format(new Date(), "yyyy-MM-dd"));
|
insertInvObj.put("biz_date", DateUtil.format(new Date(), "yyyy-MM-dd"));
|
||||||
insertInvObj.put("tableData", rowss);
|
insertInvObj.put("tableData", rowList);
|
||||||
return insertInvObj;
|
return insertInvObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过滤统计material_id和pcsn相同的数据,并将qty相加
|
||||||
|
*/
|
||||||
|
public static List<JSONObject> filterAndSumByMaterialIdAndPcsn(JSONArray jsonArray) {
|
||||||
|
// 使用Stream进行分组,按material_id和pcsn作为组合键
|
||||||
|
Map<String, List<JSONObject>> groupedData = jsonArray.stream()
|
||||||
|
.map(obj -> (JSONObject) obj)
|
||||||
|
.collect(Collectors.groupingBy(obj ->
|
||||||
|
obj.getString("material_id") + "_" + obj.getString("pcsn")
|
||||||
|
));
|
||||||
|
|
||||||
|
// 对每个分组进行合并,累加qty
|
||||||
|
return groupedData.values().stream()
|
||||||
|
.map(group -> {
|
||||||
|
// 取第一个对象作为基础(保留除了qty外的其他信息)
|
||||||
|
JSONObject baseObj = new JSONObject(group.get(0));
|
||||||
|
|
||||||
|
// 计算该分组中所有对象的qty总和
|
||||||
|
int totalQty = group.stream()
|
||||||
|
.mapToInt(obj -> obj.getInteger("qty"))
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
// 更新qty为总和
|
||||||
|
baseObj.put("qty", totalQty);
|
||||||
|
|
||||||
|
// 如果需要,可以添加一个字段表示合并了多少条记录
|
||||||
|
baseObj.put("merged_count", group.size());
|
||||||
|
|
||||||
|
return baseObj;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject buildManuaOutDivData(JSONObject param, Sectattr outStructAttr, String invId) {
|
public JSONObject buildManuaOutDivData(JSONObject param, Sectattr outStructAttr, String invId) {
|
||||||
JSONObject outDivObj = new JSONObject();
|
JSONObject outDivObj = new JSONObject();
|
||||||
|
|||||||
@@ -9,13 +9,15 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.nl.common.exception.BadRequestException;
|
import org.nl.common.exception.BadRequestException;
|
||||||
|
import org.nl.common.utils.CodeUtil;
|
||||||
|
import org.nl.common.utils.IdUtil;
|
||||||
|
import org.nl.common.utils.MapOf;
|
||||||
import org.nl.common.utils.SecurityUtils;
|
import org.nl.common.utils.SecurityUtils;
|
||||||
import org.nl.wms.basedata_manage.service.IMdPbStoragevehicleextService;
|
import org.nl.wms.basedata_manage.enums.BaseDataEnum;
|
||||||
import org.nl.wms.basedata_manage.service.IMdPbStoragevehicleinfoService;
|
import org.nl.wms.basedata_manage.service.*;
|
||||||
import org.nl.wms.basedata_manage.service.IMdPdGroupbucketService;
|
|
||||||
import org.nl.wms.basedata_manage.service.ISectattrService;
|
|
||||||
import org.nl.wms.basedata_manage.service.dao.MdPbStoragevehicleext;
|
import org.nl.wms.basedata_manage.service.dao.MdPbStoragevehicleext;
|
||||||
import org.nl.wms.basedata_manage.service.dao.Sectattr;
|
import org.nl.wms.basedata_manage.service.dao.Sectattr;
|
||||||
|
import org.nl.wms.basedata_manage.service.dao.Structattr;
|
||||||
import org.nl.wms.pda.general_management.service.PdaBuildParamService;
|
import org.nl.wms.pda.general_management.service.PdaBuildParamService;
|
||||||
import org.nl.wms.pda.general_management.service.PdaWarehouseService;
|
import org.nl.wms.pda.general_management.service.PdaWarehouseService;
|
||||||
import org.nl.wms.pda.general_management.service.PdaProductionService;
|
import org.nl.wms.pda.general_management.service.PdaProductionService;
|
||||||
@@ -26,6 +28,7 @@ import org.nl.wms.sch_manage.service.dao.SchBasePoint;
|
|||||||
import org.nl.wms.sch_manage.service.dao.SchBaseTask;
|
import org.nl.wms.sch_manage.service.dao.SchBaseTask;
|
||||||
import org.nl.wms.sch_manage.service.util.AbstractTask;
|
import org.nl.wms.sch_manage.service.util.AbstractTask;
|
||||||
import org.nl.wms.sch_manage.service.util.TaskFactory;
|
import org.nl.wms.sch_manage.service.util.TaskFactory;
|
||||||
|
import org.nl.wms.sch_manage.service.util.tasks.PalletOutTask;
|
||||||
import org.nl.wms.sch_manage.service.util.tasks.PreProcessingInTask;
|
import org.nl.wms.sch_manage.service.util.tasks.PreProcessingInTask;
|
||||||
import org.nl.wms.warehouse_management.enums.IOSEnum;
|
import org.nl.wms.warehouse_management.enums.IOSEnum;
|
||||||
import org.nl.wms.warehouse_management.service.IMdPbGroupplateService;
|
import org.nl.wms.warehouse_management.service.IMdPbGroupplateService;
|
||||||
@@ -33,6 +36,11 @@ import org.nl.wms.warehouse_management.service.IOutBillService;
|
|||||||
import org.nl.wms.warehouse_management.service.IRawAssistIStorService;
|
import org.nl.wms.warehouse_management.service.IRawAssistIStorService;
|
||||||
import org.nl.wms.warehouse_management.service.VehicleInService;
|
import org.nl.wms.warehouse_management.service.VehicleInService;
|
||||||
import org.nl.wms.warehouse_management.service.dao.GroupPlate;
|
import org.nl.wms.warehouse_management.service.dao.GroupPlate;
|
||||||
|
import org.nl.wms.warehouse_management.service.dao.IOStorInv;
|
||||||
|
import org.nl.wms.warehouse_management.service.dao.IOStorInvDis;
|
||||||
|
import org.nl.wms.warehouse_management.service.dao.IOStorInvDtl;
|
||||||
|
import org.nl.wms.warehouse_management.service.dao.mapper.IOStorInvDisMapper;
|
||||||
|
import org.nl.wms.warehouse_management.service.dao.mapper.IOStorInvDtlMapper;
|
||||||
import org.redisson.api.RLock;
|
import org.redisson.api.RLock;
|
||||||
import org.redisson.api.RedissonClient;
|
import org.redisson.api.RedissonClient;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -41,9 +49,11 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.nl.common.utils.ValidationUtil.*;
|
import static org.nl.common.utils.ValidationUtil.*;
|
||||||
|
|
||||||
@@ -84,6 +94,14 @@ public class PdaProductionServiceImpl implements PdaProductionService {
|
|||||||
private TaskFactory taskFactory;
|
private TaskFactory taskFactory;
|
||||||
@Resource
|
@Resource
|
||||||
private RedissonClient redissonClient;
|
private RedissonClient redissonClient;
|
||||||
|
@Resource
|
||||||
|
private PalletOutTask palletOutTask;
|
||||||
|
@Resource
|
||||||
|
private IStructattrService structattrService;
|
||||||
|
@Resource
|
||||||
|
private IOStorInvDisMapper ioStorInvDisMapper;
|
||||||
|
@Resource
|
||||||
|
private IOStorInvDtlMapper ioStorInvDtlMapper;
|
||||||
@Override
|
@Override
|
||||||
public PdaResponse getGroupInfo(JSONObject param) {
|
public PdaResponse getGroupInfo(JSONObject param) {
|
||||||
// search;
|
// search;
|
||||||
@@ -111,12 +129,12 @@ public class PdaProductionServiceImpl implements PdaProductionService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PdaResponse confirmCallMaterial(JSONObject param) {
|
public PdaResponse confirmCallMaterial(JSONObject param) {
|
||||||
// point_code, rows,sect_code
|
// point_code, row,sect_code
|
||||||
log.info("手持托盘叫料:{}", param);
|
log.info("手持托盘叫料:{}", param);
|
||||||
if (ObjectUtil.isEmpty(param.get("point_code"))) {
|
if (ObjectUtil.isEmpty(param.get("point_code"))) {
|
||||||
throw new BadRequestException("请输入要料点!");
|
throw new BadRequestException("请输入要料点!");
|
||||||
}
|
}
|
||||||
if (ObjectUtil.isEmpty(param.get("rows"))) {
|
if (ObjectUtil.isEmpty(param.get("row"))) {
|
||||||
throw new BadRequestException("请选择呼叫的物料!");
|
throw new BadRequestException("请选择呼叫的物料!");
|
||||||
}
|
}
|
||||||
String pointCode = param.getString("point_code");
|
String pointCode = param.getString("point_code");
|
||||||
@@ -124,24 +142,13 @@ public class PdaProductionServiceImpl implements PdaProductionService {
|
|||||||
if (ObjectUtil.isEmpty(endPoint)) {
|
if (ObjectUtil.isEmpty(endPoint)) {
|
||||||
throw new BadRequestException("输入的点位不存在或者点位已被禁用, 请检查输入点位是否正确或是否被禁用!");
|
throw new BadRequestException("输入的点位不存在或者点位已被禁用, 请检查输入点位是否正确或是否被禁用!");
|
||||||
}
|
}
|
||||||
String sectCode = param.getString("sect_code");
|
JSONObject row = param.getJSONObject("row");
|
||||||
if (ObjectUtil.isEmpty(sectCode)) {
|
// 创建任务
|
||||||
throw new BadRequestException("请选择仓库!");
|
JSONObject taskParam = new JSONObject();
|
||||||
}
|
taskParam.put("point_code1", row.getString("struct_code"));
|
||||||
Sectattr outStructAttr = sectattrService.findByCode(sectCode, true);
|
taskParam.put("point_code2", param.getString("point_code"));
|
||||||
if (ObjectUtil.isEmpty(outStructAttr)) {
|
taskParam.put("vehicle_code", row.getString("vehicle_code"));
|
||||||
throw new BadRequestException("库区不存在或者被禁用!");
|
palletOutTask.create(taskParam);
|
||||||
}
|
|
||||||
// 1 创建出库单、明细、分配明细
|
|
||||||
param.put("bill_type", IOSEnum.OUT_BILL_TYPE.code("原辅料出库"));
|
|
||||||
JSONObject invObj = defaultPdaBuildParam.doBuildOutInvObj(param, outStructAttr);
|
|
||||||
String invId = outBillService.insertDtl(invObj);
|
|
||||||
// 2 调用分配
|
|
||||||
JSONObject divObj = defaultPdaBuildParam.buildManuaOutDivData(param, outStructAttr, invId);
|
|
||||||
outBillService.manualDiv(divObj);
|
|
||||||
// 3 创建任务
|
|
||||||
JSONObject jsonMst = defaultPdaBuildParam.buildOutAllSetData(endPoint, invId);
|
|
||||||
outBillService.allSetPoint(jsonMst);
|
|
||||||
return PdaResponse.requestOk("呼叫成功!");
|
return PdaResponse.requestOk("呼叫成功!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +158,7 @@ public class PdaProductionServiceImpl implements PdaProductionService {
|
|||||||
if (ObjectUtil.isEmpty(search)) {
|
if (ObjectUtil.isEmpty(search)) {
|
||||||
throw new BadRequestException("请输入袋号编码!");
|
throw new BadRequestException("请输入袋号编码!");
|
||||||
}
|
}
|
||||||
List<JSONObject> groups = groupplateService.getPalletView(search, "1");
|
List<JSONObject> groups = groupplateService.getPalletView(search, "2");
|
||||||
if (groups.size() != 1) {
|
if (groups.size() != 1) {
|
||||||
throw new BadRequestException(groups.size() == 0 ? "组袋记录不存在,请先组袋!" : "组袋记录信息有误,请查询并清理后重试!");
|
throw new BadRequestException(groups.size() == 0 ? "组袋记录不存在,请先组袋!" : "组袋记录信息有误,请查询并清理后重试!");
|
||||||
}
|
}
|
||||||
@@ -166,7 +173,10 @@ public class PdaProductionServiceImpl implements PdaProductionService {
|
|||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public PdaResponse takePalletMaterial(JSONObject param) {
|
public PdaResponse takePalletMaterial(JSONObject param) {
|
||||||
log.info("手持取物料: {}", param);
|
log.info("手持取物料: {}", param);
|
||||||
// search、rows
|
String currentUserId = SecurityUtils.getCurrentUserId();
|
||||||
|
String nickName = SecurityUtils.getCurrentNickName();
|
||||||
|
String now = DateUtil.now();
|
||||||
|
// search、rows、total_qty
|
||||||
String search = param.getString("search");
|
String search = param.getString("search");
|
||||||
// SchBasePoint point = pointService.getByPointCode(search, false);
|
// SchBasePoint point = pointService.getByPointCode(search, false);
|
||||||
// if (ObjectUtil.isNotEmpty(point)) {
|
// if (ObjectUtil.isNotEmpty(point)) {
|
||||||
@@ -177,39 +187,124 @@ public class PdaProductionServiceImpl implements PdaProductionService {
|
|||||||
}
|
}
|
||||||
storagevehicleinfoService.getByCode(search);
|
storagevehicleinfoService.getByCode(search);
|
||||||
JSONArray rows = param.getJSONArray("rows");
|
JSONArray rows = param.getJSONArray("rows");
|
||||||
|
// 找到托盘的仓位
|
||||||
|
List<Structattr> startPoints = structattrService
|
||||||
|
.getByVehicleCode(rows.getJSONObject(0).getString("vehicle_code")
|
||||||
|
, IOSEnum.LOCK_TYPE.code("其他锁"), false);
|
||||||
|
if (startPoints.size() == 0) {
|
||||||
|
throw new BadRequestException("未找到当前托盘的原始库位信息!");
|
||||||
|
}
|
||||||
|
Structattr structattr = startPoints.get(0);
|
||||||
|
Sectattr sectattr = sectattrService.findByCode(structattr.getSect_code(), false);
|
||||||
|
// 手动更新库存信息
|
||||||
|
// 1、创建出库单、明细、分配明细
|
||||||
|
// 1.1 单据表
|
||||||
|
String invId = IdUtil.getStringId();
|
||||||
|
IOStorInv ioStorInv = new IOStorInv();
|
||||||
|
ioStorInv.setIostorinv_id(invId);
|
||||||
|
ioStorInv.setBill_code(CodeUtil.getNewCode("OUT_STORE_CODE"));
|
||||||
|
ioStorInv.setBiz_date(DateUtil.format(new Date(), "yyyy-MM-dd"));
|
||||||
|
ioStorInv.setIo_type(IOSEnum.IO_TYPE.code("出库"));
|
||||||
|
ioStorInv.setDetail_count(1);
|
||||||
|
ioStorInv.setCreate_mode(IOSEnum.CREATE_MODE.code("终端产生"));
|
||||||
|
ioStorInv.setStor_id(structattr.getStor_id());
|
||||||
|
ioStorInv.setStor_code(structattr.getStor_code());
|
||||||
|
ioStorInv.setStor_name(structattr.getStor_name());
|
||||||
|
ioStorInv.setBill_status(IOSEnum.BILL_STATUS.code("完成"));
|
||||||
|
ioStorInv.setBill_type(IOSEnum.OUT_BILL_TYPE.code("原辅料出库"));
|
||||||
|
ioStorInv.setBuss_type(IOSEnum.OUT_BILL_TYPE.code("原辅料出库").substring(0, 4));
|
||||||
|
ioStorInv.setIs_delete(BaseDataEnum.IS_YES_NOT.code("否"));
|
||||||
|
ioStorInv.setIs_upload(BaseDataEnum.IS_YES_NOT.code("否"));
|
||||||
|
ioStorInv.setInput_optid(currentUserId);
|
||||||
|
ioStorInv.setInput_optname(nickName);
|
||||||
|
ioStorInv.setInput_time(now);
|
||||||
|
ioStorInv.setUpdate_optid(currentUserId);
|
||||||
|
ioStorInv.setUpdate_optname(nickName);
|
||||||
|
ioStorInv.setUpdate_time(now);
|
||||||
|
ioStorInv.setTotal_qty(param.getBigDecimal("total_qty"));
|
||||||
|
ioStorInv.setDetail_count(rows.size());
|
||||||
|
outBillService.save(ioStorInv);
|
||||||
|
// 扣除组盘数据
|
||||||
List<GroupPlate> needAddOrUpdGroups = new ArrayList<>();
|
List<GroupPlate> needAddOrUpdGroups = new ArrayList<>();
|
||||||
List<String> needDelGroups = new ArrayList<>();
|
List<String> needDelGroups = new ArrayList<>();
|
||||||
|
List<MdPbStoragevehicleext> vehicleObjs = storagevehicleextService.list(new LambdaQueryWrapper<MdPbStoragevehicleext>()
|
||||||
|
.eq(MdPbStoragevehicleext::getStoragevehicle_code, rows.getJSONObject(0).getString("vehicle_code")));
|
||||||
BigDecimal whileSub = new BigDecimal("0");
|
BigDecimal whileSub = new BigDecimal("0");
|
||||||
for (int i = 0; i < rows.size(); i++) {
|
for (int i = 0; i < rows.size(); i++) {
|
||||||
JSONObject row = rows.getJSONObject(i);
|
JSONObject row = rows.getJSONObject(i);
|
||||||
GroupPlate delGroup = groupplateService.getById(row.getString("group_id"));
|
GroupPlate delGroup = groupplateService.getById(row.getString("group_id"));
|
||||||
GroupPlate groupPlate = JSON.parseObject(row.toJSONString(), GroupPlate.class);
|
GroupPlate groupPlate = JSON.parseObject(row.toJSONString(), GroupPlate.class);
|
||||||
// groupPlate.setGroup_id(IdUtil.getStringId());
|
|
||||||
// groupPlate.setVehicle_code("");
|
|
||||||
// groupPlate.setStatus("0");
|
|
||||||
// groupPlate.setCreate_id(SecurityUtils.getCurrentUserId());
|
|
||||||
// groupPlate.setCreate_name(SecurityUtils.getCurrentNickName());
|
|
||||||
// groupPlate.setCreate_time(DateUtil.now());
|
|
||||||
// needAddOrUpdGroups.add(groupPlate);
|
|
||||||
// 其他需要删除
|
// 其他需要删除
|
||||||
delGroup.setQty(delGroup.getQty().subtract(groupPlate.getQty()));
|
delGroup.setQty(delGroup.getQty().subtract(groupPlate.getQty()));
|
||||||
if (delGroup.getQty().equals(new BigDecimal("0"))) {
|
if (delGroup.getQty().compareTo(BigDecimal.ZERO) == 0) {
|
||||||
needDelGroups.add(delGroup.getGroup_id());
|
needDelGroups.add(delGroup.getGroup_id());
|
||||||
} else {
|
} else {
|
||||||
needAddOrUpdGroups.add(delGroup);
|
needAddOrUpdGroups.add(delGroup);
|
||||||
}
|
}
|
||||||
whileSub.add(groupPlate.getQty());
|
whileSub.add(groupPlate.getQty());
|
||||||
|
// 1.2 单据明细
|
||||||
|
IOStorInvDtl dtl = new IOStorInvDtl();
|
||||||
|
dtl.setIostorinvdtl_id(IdUtil.getStringId());
|
||||||
|
dtl.setIostorinv_id(invId);
|
||||||
|
dtl.setSeq_no("1");
|
||||||
|
dtl.setMaterial_id(row.getString("material_code"));
|
||||||
|
dtl.setPcsn(groupPlate.getPcsn());
|
||||||
|
dtl.setBill_status(IOSEnum.BILL_STATUS.code("完成"));
|
||||||
|
dtl.setQty_unit_id(groupPlate.getQty_unit_id());
|
||||||
|
dtl.setQty_unit_name(groupPlate.getQty_unit_name());
|
||||||
|
dtl.setPlan_qty(groupPlate.getQty());
|
||||||
|
dtl.setAssign_qty(groupPlate.getQty());
|
||||||
|
dtl.setUnassign_qty(BigDecimal.ZERO);
|
||||||
|
ioStorInvDtlMapper.insert(dtl);
|
||||||
|
// 1.3 分配明细
|
||||||
|
IOStorInvDis ioStorInvDis = new IOStorInvDis();
|
||||||
|
ioStorInvDis.setIostorinvdis_id(IdUtil.getStringId());
|
||||||
|
ioStorInvDis.setIostorinv_id(dtl.getIostorinv_id());
|
||||||
|
ioStorInvDis.setIostorinvdtl_id(dtl.getIostorinvdtl_id());
|
||||||
|
ioStorInvDis.setSeq_no("1");
|
||||||
|
ioStorInvDis.setSect_id(structattr.getSect_id());
|
||||||
|
ioStorInvDis.setPcsn(groupPlate.getPcsn());
|
||||||
|
ioStorInvDis.setMaterial_id(row.getString("material_id"));
|
||||||
|
ioStorInvDis.setSect_name(structattr.getSect_name());
|
||||||
|
ioStorInvDis.setSect_code(structattr.getSect_code());
|
||||||
|
ioStorInvDis.setStruct_id(structattr.getStruct_id());
|
||||||
|
ioStorInvDis.setStruct_name(structattr.getStruct_name());
|
||||||
|
ioStorInvDis.setStruct_code(structattr.getStruct_code());
|
||||||
|
ioStorInvDis.setStoragevehicle_code(row.getString("vehicle_code"));
|
||||||
|
ioStorInvDis.setIs_issued(BaseDataEnum.IS_YES_NOT.code("否"));
|
||||||
|
ioStorInvDis.setQty_unit_id(groupPlate.getQty_unit_id());
|
||||||
|
ioStorInvDis.setQty_unit_name(groupPlate.getQty_unit_name());
|
||||||
|
ioStorInvDis.setWork_status(IOSEnum.INBILL_DIS_STATUS.code("完成"));
|
||||||
|
ioStorInvDis.setPlan_qty(groupPlate.getQty());
|
||||||
|
ioStorInvDisMapper.insert(ioStorInvDis);
|
||||||
|
vehicleObjs.stream()
|
||||||
|
.filter(vehicle ->
|
||||||
|
vehicle.getStoragevehicle_code().equals(row.getString("vehicle_code")) &&
|
||||||
|
vehicle.getMaterial_id().equals(row.getString("material_id")) &&
|
||||||
|
vehicle.getPcsn().equals(row.getString("pcsn")))
|
||||||
|
.findFirst()
|
||||||
|
.ifPresent(vehicle -> {
|
||||||
|
BigDecimal newQty = vehicle.getCanuse_qty().subtract(row.getBigDecimal("qty"));
|
||||||
|
vehicle.setCanuse_qty(newQty.max(BigDecimal.ZERO));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
List<MdPbStoragevehicleext> zeroQtyVehicles = vehicleObjs.stream()
|
||||||
|
.filter(vehicle -> vehicle.getCanuse_qty().compareTo(BigDecimal.ZERO) == 0)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<MdPbStoragevehicleext> nonZeroQtyVehicles = vehicleObjs.stream()
|
||||||
|
.filter(vehicle -> vehicle.getCanuse_qty().compareTo(BigDecimal.ZERO) != 0)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
groupplateService.saveOrUpdateBatch(needAddOrUpdGroups);
|
groupplateService.saveOrUpdateBatch(needAddOrUpdGroups);
|
||||||
groupplateService.removeByIds(needDelGroups);
|
groupplateService.removeByIds(needDelGroups);
|
||||||
// 托盘数量修改
|
// 托盘数量修改
|
||||||
MdPbStoragevehicleext vehicleObj = storagevehicleextService.getOne(new LambdaQueryWrapper<MdPbStoragevehicleext>()
|
if (nonZeroQtyVehicles.size() > 0) {
|
||||||
.eq(MdPbStoragevehicleext::getStoragevehicle_code, rows.getJSONObject(0).getString("vehicle_code")));
|
storagevehicleextService.updateBatchById(nonZeroQtyVehicles);
|
||||||
vehicleObj.setCanuse_qty(vehicleObj.getCanuse_qty().subtract(whileSub));
|
}
|
||||||
vehicleObj.setUpdate_optid(SecurityUtils.getCurrentUserId());
|
if (zeroQtyVehicles.size() > 0) {
|
||||||
vehicleObj.setUpdate_optname(SecurityUtils.getCurrentNickName());
|
storagevehicleextService.removeByIds(zeroQtyVehicles.stream().map(MdPbStoragevehicleext::getStoragevehicleext_id).collect(Collectors.toList()));
|
||||||
vehicleObj.setUpdate_time(DateUtil.now());
|
}
|
||||||
storagevehicleextService.updateById(vehicleObj);
|
|
||||||
return PdaResponse.requestOk("取料成功!");
|
return PdaResponse.requestOk("取料成功!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public class PdaWarehouseServiceImpl implements PdaWarehouseService {
|
|||||||
Structattr startStruct = structattrService.getByCode(search);
|
Structattr startStruct = structattrService.getByCode(search);
|
||||||
if (ObjectUtil.isEmpty(startStruct)) {
|
if (ObjectUtil.isEmpty(startStruct)) {
|
||||||
vehicleCode = search;
|
vehicleCode = search;
|
||||||
List<Structattr> points = structattrService.getByVehicleCode(search, true);
|
List<Structattr> points = structattrService.getByVehicleCode(search, IOSEnum.LOCK_TYPE.code("未锁定"), true);
|
||||||
if (points.size() != 1) {
|
if (points.size() != 1) {
|
||||||
throw new BadRequestException(points.size() > 1
|
throw new BadRequestException(points.size() > 1
|
||||||
? "该托盘号绑定在多个点位" + points.stream().map(Structattr::getStruct_code).collect(Collectors.toList()) + ",请检查!"
|
? "该托盘号绑定在多个点位" + points.stream().map(Structattr::getStruct_code).collect(Collectors.toList()) + ",请检查!"
|
||||||
|
|||||||
@@ -0,0 +1,235 @@
|
|||||||
|
package org.nl.wms.sch_manage.service.util.tasks;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||||
|
import org.nl.common.exception.BadRequestException;
|
||||||
|
import org.nl.common.utils.CodeUtil;
|
||||||
|
import org.nl.common.utils.SecurityUtils;
|
||||||
|
import org.nl.config.IdUtil;
|
||||||
|
import org.nl.wms.basedata_manage.enums.BaseDataEnum;
|
||||||
|
import org.nl.wms.basedata_manage.service.IStructattrService;
|
||||||
|
import org.nl.wms.basedata_manage.service.dao.Structattr;
|
||||||
|
import org.nl.wms.sch_manage.enums.TaskEnum;
|
||||||
|
import org.nl.wms.sch_manage.enums.TaskStatus;
|
||||||
|
import org.nl.wms.sch_manage.service.ISchBasePointService;
|
||||||
|
import org.nl.wms.sch_manage.service.ISchBaseTaskService;
|
||||||
|
import org.nl.wms.sch_manage.service.dao.SchBasePoint;
|
||||||
|
import org.nl.wms.sch_manage.service.dao.SchBaseTask;
|
||||||
|
import org.nl.wms.sch_manage.service.util.ACSTaskTypeEnum;
|
||||||
|
import org.nl.wms.sch_manage.service.util.AbstractTask;
|
||||||
|
import org.nl.wms.sch_manage.service.util.AcsTaskDto;
|
||||||
|
import org.nl.wms.sch_manage.service.util.TaskType;
|
||||||
|
import org.nl.wms.warehouse_management.enums.IOSConstant;
|
||||||
|
import org.nl.wms.warehouse_management.enums.IOSEnum;
|
||||||
|
import org.nl.wms.warehouse_management.service.IOutBillService;
|
||||||
|
import org.nl.wms.warehouse_management.service.dao.GroupPlate;
|
||||||
|
import org.nl.wms.warehouse_management.service.dao.IOStorInvDis;
|
||||||
|
import org.nl.wms.warehouse_management.service.dao.mapper.GroupPlateMapper;
|
||||||
|
import org.nl.wms.warehouse_management.service.dao.mapper.IOStorInvDisMapper;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 托盘出库任务
|
||||||
|
* @Author: lyd
|
||||||
|
* @Date: 2025/12/10
|
||||||
|
*/
|
||||||
|
@Component(value = "PalletOutTask")
|
||||||
|
@TaskType("PalletOutTask")
|
||||||
|
public class PalletOutTask extends AbstractTask {
|
||||||
|
/**
|
||||||
|
* 任务服务
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
private ISchBaseTaskService taskService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 出库服务
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private IOutBillService outBillService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分配明细mapper
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private IOStorInvDisMapper ioStorInvDisMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点位服务
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private ISchBasePointService iSchBasePointService;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 组盘记录服务
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private GroupPlateMapper groupPlateMapper;
|
||||||
|
@Resource
|
||||||
|
private IStructattrService structattrService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String create(JSONObject json) {
|
||||||
|
SchBaseTask task = new SchBaseTask();
|
||||||
|
task.setTask_id(IdUtil.getStringId());
|
||||||
|
task.setTask_code(CodeUtil.getNewCode("TASK_CODE"));
|
||||||
|
task.setTask_status(TaskStatus.CREATED.getCode());
|
||||||
|
task.setConfig_code(PalletOutTask.class.getSimpleName());
|
||||||
|
task.setPoint_code1(json.getString("point_code1"));
|
||||||
|
task.setPoint_code2(json.getString("point_code2"));
|
||||||
|
task.setVehicle_code(json.getString("vehicle_code"));
|
||||||
|
task.setMaterial_id(json.getString("material_id"));
|
||||||
|
task.setMaterial_qty(json.getBigDecimal("material_qty"));
|
||||||
|
task.setGroup_id(json.getString("group_id"));
|
||||||
|
task.setRequest_param(json.toString());
|
||||||
|
task.setPriority(json.getString("Priority"));
|
||||||
|
task.setTask_type(TaskEnum.TASK_TYPE.code("料箱"));
|
||||||
|
task.setIs_wait(json.getString("is_wait"));
|
||||||
|
task.setCreate_id(SecurityUtils.getCurrentUserId());
|
||||||
|
task.setCreate_name(SecurityUtils.getCurrentNickName());
|
||||||
|
task.setCreate_time(DateUtil.now());
|
||||||
|
taskService.save(task);
|
||||||
|
|
||||||
|
// 点位上锁
|
||||||
|
structattrService.update(new LambdaUpdateWrapper<Structattr>()
|
||||||
|
.set(Structattr::getLock_type, IOSEnum.LOCK_TYPE.code("其他锁"))
|
||||||
|
.eq(Structattr::getStruct_code, task.getPoint_code1()));
|
||||||
|
|
||||||
|
// 下发任务
|
||||||
|
this.sendTaskOne(task.getTask_id());
|
||||||
|
return task.getTask_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AcsTaskDto sendAcsParam(String taskId) {
|
||||||
|
SchBaseTask taskDao = taskService.getById(taskId);
|
||||||
|
|
||||||
|
// 组织下发给acs的数据
|
||||||
|
AcsTaskDto acsTaskDto = new AcsTaskDto();
|
||||||
|
acsTaskDto.setExt_task_id(taskDao.getTask_id());
|
||||||
|
acsTaskDto.setTask_code(taskDao.getTask_code());
|
||||||
|
acsTaskDto.setStart_device_code(taskDao.getPoint_code1());
|
||||||
|
acsTaskDto.setNext_device_code(taskDao.getPoint_code2());
|
||||||
|
acsTaskDto.setPriority(taskDao.getPriority());
|
||||||
|
acsTaskDto.setVehicle_code(taskDao.getVehicle_code());
|
||||||
|
|
||||||
|
acsTaskDto.setVehicle_type(IOSConstant.ONE);
|
||||||
|
acsTaskDto.setIs_wait(taskDao.getIs_wait());
|
||||||
|
acsTaskDto.setTask_type(ACSTaskTypeEnum.CTU_TASK.getCode());
|
||||||
|
|
||||||
|
acsTaskDto.setPriority(IOSConstant.ONE);
|
||||||
|
acsTaskDto.setAgv_system_type(IOSConstant.THREE);
|
||||||
|
acsTaskDto.setIs_get_pause(IOSConstant.ZERO);
|
||||||
|
acsTaskDto.setIs_put_pause(IOSConstant.ZERO);
|
||||||
|
|
||||||
|
return acsTaskDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
protected void updateStatus(String task_code, TaskStatus status) {
|
||||||
|
// 校验任务
|
||||||
|
SchBaseTask taskObj = taskService.getByCode(task_code);
|
||||||
|
if (taskObj.getTask_status().equals(TaskStatus.FINISHED.getCode())) {
|
||||||
|
throw new BadRequestException("该任务已完成!");
|
||||||
|
}
|
||||||
|
if (taskObj.getTask_status().equals(TaskStatus.CANCELED.getCode())) {
|
||||||
|
throw new BadRequestException("该任务已取消!");
|
||||||
|
}
|
||||||
|
// 根据传来的类型去对任务进行操作
|
||||||
|
if (status.equals(TaskStatus.EXECUTING)) {
|
||||||
|
this.executingTask(taskObj);
|
||||||
|
taskObj.setTask_status(TaskStatus.EXECUTING.getCode());
|
||||||
|
taskObj.setRemark("执行中");
|
||||||
|
taskService.updateById(taskObj);
|
||||||
|
}
|
||||||
|
if (status.equals(TaskStatus.FINISHED)) {
|
||||||
|
this.finishTask(taskObj);
|
||||||
|
}
|
||||||
|
if (status.equals(TaskStatus.CANCELED)) {
|
||||||
|
this.cancelTask(taskObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void forceFinish(String task_code) {
|
||||||
|
SchBaseTask taskObj = taskService.getByCode(task_code);
|
||||||
|
if (ObjectUtil.isEmpty(taskObj)) {
|
||||||
|
throw new BadRequestException("该任务不存在");
|
||||||
|
}
|
||||||
|
this.finishTask(taskObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void cancel(String task_code) {
|
||||||
|
SchBaseTask taskObj = taskService.getByCode(task_code);
|
||||||
|
if (ObjectUtil.isEmpty(taskObj)) {
|
||||||
|
throw new BadRequestException("该任务不存在");
|
||||||
|
}
|
||||||
|
if (!TaskStatus.CREATE.getCode().equals(taskObj.getTask_status())) {
|
||||||
|
throw new BadRequestException("任务状态必须为生成才能取消任务");
|
||||||
|
}
|
||||||
|
this.cancelTask(taskObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void finishTask(SchBaseTask taskObj) {
|
||||||
|
// 更新终点
|
||||||
|
iSchBasePointService.update(
|
||||||
|
new UpdateWrapper<SchBasePoint>().lambda()
|
||||||
|
.eq(SchBasePoint::getPoint_code, taskObj.getPoint_code2())
|
||||||
|
.set(SchBasePoint::getVehicle_code, taskObj.getVehicle_code())
|
||||||
|
.set(SchBasePoint::getPoint_status, IOSEnum.POINT_STATUS.code("有箱有料"))
|
||||||
|
.set(SchBasePoint::getIng_task_code, taskObj.getTask_id())
|
||||||
|
);
|
||||||
|
// 任务完成
|
||||||
|
taskObj.setTask_status(TaskStatus.FINISHED.getCode());
|
||||||
|
taskObj.setRemark("已完成");
|
||||||
|
taskService.updateById(taskObj);
|
||||||
|
this.taskConfirm(taskObj.getTask_code());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void cancelTask(SchBaseTask taskObj) {
|
||||||
|
|
||||||
|
// 取消任务
|
||||||
|
taskService.update(new LambdaUpdateWrapper<SchBaseTask>()
|
||||||
|
.set(SchBaseTask::getIs_delete, BaseDataEnum.IS_YES_NOT.code("是"))
|
||||||
|
.set(SchBaseTask::getTask_status, TaskStatus.CANCELED.getCode())
|
||||||
|
.set(SchBaseTask::getRemark, "已取消")
|
||||||
|
.eq(SchBaseTask::getTask_id, taskObj.getTask_id())
|
||||||
|
);
|
||||||
|
|
||||||
|
// 点位上锁
|
||||||
|
structattrService.update(new LambdaUpdateWrapper<Structattr>()
|
||||||
|
.set(Structattr::getLock_type, IOSEnum.LOCK_TYPE.code("未锁定"))
|
||||||
|
.eq(Structattr::getStruct_code, taskObj.getPoint_code1()));
|
||||||
|
|
||||||
|
// 更新任务状态
|
||||||
|
taskObj.setTask_status(TaskStatus.CANCELED.getCode());
|
||||||
|
taskObj.setRemark("已取消");
|
||||||
|
taskService.updateById(taskObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void taskConfirm(String task_code) {
|
||||||
|
SchBaseTask taskObj = taskService.getByCode(task_code);
|
||||||
|
|
||||||
|
// 删除组盘信息
|
||||||
|
groupPlateMapper.delete(
|
||||||
|
new QueryWrapper<GroupPlate>().lambda()
|
||||||
|
.eq(GroupPlate::getVehicle_code, taskObj.getVehicle_code())
|
||||||
|
.eq(GroupPlate::getStatus, IOSEnum.GROUP_PLATE_STATUS.code("出库"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -182,7 +182,7 @@ public interface IOutBillService extends IService<IOStorInv> {
|
|||||||
*/
|
*/
|
||||||
void createTask(IOStorInvDis ioStorInvDis, String point_code, IOStorInv ioStorInv);
|
void createTask(IOStorInvDis ioStorInvDis, String point_code, IOStorInv ioStorInv);
|
||||||
|
|
||||||
List<TurnoverDetailDto> getCanuseSpecifiedIvt(Map param);
|
List<JSONObject> getCanuseSpecifiedIvt(Map param);
|
||||||
|
|
||||||
List<MdPbStoragevehicleextDto> queryAvailableSpecifiedInv(Map param);
|
List<MdPbStoragevehicleextDto> queryAvailableSpecifiedInv(Map param);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public interface IOStorInvMapper extends BaseMapper<IOStorInv> {
|
|||||||
|
|
||||||
List<JSONObject> getVehicleGroup ( List<String> collect);
|
List<JSONObject> getVehicleGroup ( List<String> collect);
|
||||||
|
|
||||||
List<TurnoverDetailDto> getCanuseSpecifiedIvt(@Param("param")Map param);
|
List<JSONObject> getCanuseSpecifiedIvt(@Param("param")Map param);
|
||||||
|
|
||||||
List<MdPbStoragevehicleextDto> queryAvailableSpecifiedInv(@Param("param")Map param);
|
List<MdPbStoragevehicleextDto> queryAvailableSpecifiedInv(@Param("param")Map param);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -214,7 +214,7 @@
|
|||||||
ORDER BY gp.create_time DESC
|
ORDER BY gp.create_time DESC
|
||||||
</select>
|
</select>
|
||||||
<select id="getCanuseSpecifiedIvt"
|
<select id="getCanuseSpecifiedIvt"
|
||||||
resultType="org.nl.wms.pda.general_management.service.dto.TurnoverDetailDto">
|
resultType="com.alibaba.fastjson.JSONObject">
|
||||||
SELECT
|
SELECT
|
||||||
ext.storagevehicleext_id,
|
ext.storagevehicleext_id,
|
||||||
ext.storagevehicle_code,
|
ext.storagevehicle_code,
|
||||||
|
|||||||
@@ -1123,7 +1123,7 @@ public class OutBillServiceImpl extends ServiceImpl<IOStorInvMapper, IOStorInv>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TurnoverDetailDto> getCanuseSpecifiedIvt(Map param) {
|
public List<JSONObject> getCanuseSpecifiedIvt(Map param) {
|
||||||
return this.baseMapper.getCanuseSpecifiedIvt(param);
|
return this.baseMapper.getCanuseSpecifiedIvt(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user