Commit c37edf85 by 杨浩

配送员端接口

parent e0e76314
......@@ -23,7 +23,7 @@ public enum UserSystemEnum implements ArrayValuable<String> {
// 客户
CUSTOMER("客户", "CUSTOMER"),
// 运营人员
OPER("运营人员", "OPER");
OPER("运营", "OPER");
private final String label;
private final String key;
......
......@@ -29,4 +29,10 @@ public class ErpSupplierPageReqVO extends PageParam {
@Schema(description = "联系电话", example = "18818288888")
private String telephone;
@Schema(description = "联系人")
private String contact;
@Schema(description = "统一社会信用代码")
private String unifiedSocialCreditCode;
}
\ No newline at end of file
......@@ -18,6 +18,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Size;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
......@@ -68,7 +69,10 @@ public class ErpCustomerController {
@Operation(summary = "客户绑定仓库")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@Parameter(name = "warehouseAreaIds", description = "库区id集合", required = true, example = "1024")
public CommonResult<Boolean> bindWarehouse(@RequestParam("id") Long id, @RequestParam("warehouseAreaIds") List<Long> warehouseAreaIds) {
public CommonResult<Boolean> bindWarehouse(@RequestParam("id") Long id,
@RequestParam("warehouseAreaIds")
@Size(max = 1, min = 1, message = "只能绑定一个库区")
List<Long> warehouseAreaIds) {
customerService.bindWarehouse(id, warehouseAreaIds);
return success(Boolean.TRUE);
}
......
......@@ -9,6 +9,7 @@ import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import java.util.List;
import static cn.iocoder.foodnexus.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
......@@ -50,6 +51,12 @@ public class ErpSaleOrderPageReqVO extends PageParam {
@Schema(description = "客户编号", example = "1724")
private Long customerId;
@Schema(description = "灶点id")
private Long customerDeptId;
@Schema(description = "灶点id集合")
private List<Long> customerDeptIds;
@Schema(description = "下单时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] orderTime;
......
......@@ -2,6 +2,7 @@ package cn.iocoder.foodnexus.module.erp.controller.admin.sale.vo.order;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import cn.iocoder.foodnexus.module.erp.api.vo.warehouse.WarehouseInfo;
import cn.iocoder.foodnexus.module.erp.enums.SaleOrderPickUpStatus;
import cn.iocoder.foodnexus.module.order.dto.CustomerAddressInfo;
import cn.iocoder.foodnexus.module.order.enums.DeliveryMode;
......@@ -111,9 +112,18 @@ public class ErpSaleOrderRespVO {
@Schema(description = "配送模式")
private DeliveryMode deliveryMode;
@Schema(description = "配送时间")
@Schema(description = "配送时间(取货时间)")
private LocalDateTime deliveryTime;
@Schema(description = "接单时间")
private LocalDateTime acceptTime;
@Schema(description = "送达时间")
private LocalDateTime arrivalTime;
@Schema(description = "客户签收时间")
private LocalDateTime signTime;
@Schema(description = "配送人员")
private Long deliveryStaffId;
......@@ -127,6 +137,23 @@ public class ErpSaleOrderRespVO {
@Schema(description = "拣货状态")
private SaleOrderPickUpStatus pickUpStatus;
@Schema(description = "收获仓库id", requiredMode = Schema.RequiredMode.REQUIRED, example = "27065")
private Long warehouseId;
@Schema(description = "收获库区id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26507")
private Long warehouseAreaId;
@Schema(description = "仓库信息")
private WarehouseInfo warehouseInfo;
@Schema(description = "预计配送开始时间")
private LocalDateTime planDeliveryStartTime;
@Schema(description = "预计配送结束时间")
private LocalDateTime planDeliveryEndTime;
@Data
public static class Item {
......
package cn.iocoder.foodnexus.module.erp.controller.admin.sale.vo.order;
import cn.idev.excel.annotation.ExcelProperty;
import cn.iocoder.foodnexus.module.erp.api.vo.warehouse.WarehouseInfo;
import cn.iocoder.foodnexus.module.erp.enums.SaleOrderPickUpStatus;
import cn.iocoder.foodnexus.module.order.dto.CustomerAddressInfo;
import cn.iocoder.foodnexus.module.order.enums.DeliveryMode;
......@@ -24,6 +26,9 @@ public class ErpSaleOrderSaveReqVO {
@NotNull(message = "客户编号不能为空")
private Long customerId;
@Schema(description = "灶点id")
private Long customerDeptId;
@Schema(description = "下单时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "下单时间不能为空")
private LocalDateTime orderTime;
......@@ -53,7 +58,7 @@ public class ErpSaleOrderSaveReqVO {
@Schema(description = "配送模式")
private DeliveryMode deliveryMode;
@Schema(description = "配送时间")
@Schema(description = "配送时间(取货时间)")
private LocalDateTime deliveryTime;
@Schema(description = "配送人员")
......@@ -66,6 +71,24 @@ public class ErpSaleOrderSaveReqVO {
@TableField(typeHandler = JacksonTypeHandler.class)
private CustomerAddressInfo addressInfo;
@Schema(description = "收获仓库id", requiredMode = Schema.RequiredMode.REQUIRED, example = "27065")
private Long warehouseId;
@Schema(description = "收获库区id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26507")
private Long warehouseAreaId;
@Schema(description = "仓库信息")
private WarehouseInfo warehouseInfo;
@Schema(description = "预计配送开始时间")
private LocalDateTime planDeliveryStartTime;
@Schema(description = "预计配送结束时间")
private LocalDateTime planDeliveryEndTime;
@Schema(description = "拣货状态")
private SaleOrderPickUpStatus pickUpStatus;
@Schema(description = "订单清单列表")
private List<Item> items;
......
......@@ -2,6 +2,8 @@ package cn.iocoder.foodnexus.module.erp.controller.admin.sale.vo.out;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import cn.iocoder.foodnexus.module.erp.api.vo.warehouse.WarehouseInfo;
import cn.iocoder.foodnexus.module.erp.enums.SaleOrderPickUpStatus;
import cn.iocoder.foodnexus.module.order.dto.CustomerAddressInfo;
import cn.iocoder.foodnexus.module.order.enums.DeliveryMode;
import com.baomidou.mybatisplus.annotation.TableField;
......@@ -107,7 +109,7 @@ public class ErpSaleOutRespVO {
@Schema(description = "配送模式")
private DeliveryMode deliveryMode;
@Schema(description = "配送时间")
@Schema(description = "配送时间(取货时间)")
private LocalDateTime deliveryTime;
@Schema(description = "配送人员")
......@@ -120,6 +122,24 @@ public class ErpSaleOutRespVO {
@TableField(typeHandler = JacksonTypeHandler.class)
private CustomerAddressInfo addressInfo;
@Schema(description = "收获仓库id", requiredMode = Schema.RequiredMode.REQUIRED, example = "27065")
private Long warehouseId;
@Schema(description = "收获库区id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26507")
private Long warehouseAreaId;
@Schema(description = "仓库信息")
private WarehouseInfo warehouseInfo;
@Schema(description = "预计配送开始时间")
private LocalDateTime planDeliveryStartTime;
@Schema(description = "预计配送结束时间")
private LocalDateTime planDeliveryEndTime;
@Schema(description = "拣货状态")
private SaleOrderPickUpStatus pickUpStatus;
@Data
public static class Item {
......@@ -154,6 +174,12 @@ public class ErpSaleOutRespVO {
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "客户订单子项id")
private Long customerOrderItemId;
@Schema(description = "拣货状态")
private SaleOrderPickUpStatus pickUpStatus;
// ========== 关联字段 ==========
@Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力")
......
package cn.iocoder.foodnexus.module.erp.controller.admin.sale.vo.out;
import cn.iocoder.foodnexus.module.erp.api.vo.warehouse.WarehouseInfo;
import cn.iocoder.foodnexus.module.erp.enums.SaleOrderPickUpStatus;
import cn.iocoder.foodnexus.module.order.dto.CustomerAddressInfo;
import cn.iocoder.foodnexus.module.order.enums.DeliveryMode;
import com.baomidou.mybatisplus.annotation.TableField;
......@@ -54,9 +56,18 @@ public class ErpSaleOutSaveReqVO {
@Schema(description = "配送模式")
private DeliveryMode deliveryMode;
@Schema(description = "配送时间")
@Schema(description = "配送时间(取货时间)")
private LocalDateTime deliveryTime;
@Schema(description = "接单时间")
private LocalDateTime acceptTime;
@Schema(description = "送达时间")
private LocalDateTime arrivalTime;
@Schema(description = "客户签收时间")
private LocalDateTime signTime;
@Schema(description = "配送人员")
private Long deliveryStaffId;
......@@ -67,6 +78,24 @@ public class ErpSaleOutSaveReqVO {
@TableField(typeHandler = JacksonTypeHandler.class)
private CustomerAddressInfo addressInfo;
@Schema(description = "收获仓库id", requiredMode = Schema.RequiredMode.REQUIRED, example = "27065")
private Long warehouseId;
@Schema(description = "收获库区id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26507")
private Long warehouseAreaId;
@Schema(description = "仓库信息")
private WarehouseInfo warehouseInfo;
@Schema(description = "预计配送开始时间")
private LocalDateTime planDeliveryStartTime;
@Schema(description = "预计配送结束时间")
private LocalDateTime planDeliveryEndTime;
@Schema(description = "拣货状态")
private SaleOrderPickUpStatus pickUpStatus;
@Data
public static class Item {
......@@ -102,6 +131,12 @@ public class ErpSaleOutSaveReqVO {
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "客户订单子项id")
private Long customerOrderItemId;
@Schema(description = "拣货状态")
private SaleOrderPickUpStatus pickUpStatus;
}
}
\ No newline at end of file
......@@ -2,6 +2,7 @@ package cn.iocoder.foodnexus.module.erp.dal.dataobject.sale;
import cn.iocoder.foodnexus.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpAuditStatus;
import cn.iocoder.foodnexus.module.erp.api.vo.warehouse.WarehouseInfo;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.finance.ErpAccountDO;
import cn.iocoder.foodnexus.module.erp.enums.SaleOrderPickUpStatus;
import cn.iocoder.foodnexus.module.order.dto.CustomerAddressInfo;
......@@ -53,6 +54,10 @@ public class ErpSaleOrderDO extends BaseDO {
*/
private Long customerId;
/**
* 灶点id
*/
private Long customerDeptId;
/**
* 结算账户编号
*
* 关联 {@link ErpAccountDO#getId()}
......@@ -137,11 +142,26 @@ public class ErpSaleOrderDO extends BaseDO {
private DeliveryMode deliveryMode;
/**
* 配送时间
* 配送时间(取货时间)
*/
private LocalDateTime deliveryTime;
/**
* 接单时间
*/
private LocalDateTime acceptTime;
/**
* 送达时间
*/
private LocalDateTime arrivalTime;
/**
* 客户签收时间
*/
private LocalDateTime signTime;
/**
* 配送人员
*
* DeliveryStaffDO
......@@ -163,4 +183,27 @@ public class ErpSaleOrderDO extends BaseDO {
* 拣货状态
*/
private SaleOrderPickUpStatus pickUpStatus;
/**
* 收获仓库id
*/
private Long warehouseId;
/**
* 收获库区id
*/
private Long warehouseAreaId;
/**
* 仓库信息
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private WarehouseInfo warehouseInfo;
/**
* 预计配送开始时间
*/
private LocalDateTime planDeliveryStartTime;
/**
* 预计配送结束时间
*/
private LocalDateTime planDeliveryEndTime;
}
\ No newline at end of file
......@@ -2,7 +2,9 @@ package cn.iocoder.foodnexus.module.erp.dal.dataobject.sale;
import cn.iocoder.foodnexus.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpAuditStatus;
import cn.iocoder.foodnexus.module.erp.api.vo.warehouse.WarehouseInfo;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.finance.ErpAccountDO;
import cn.iocoder.foodnexus.module.erp.enums.SaleOrderPickUpStatus;
import cn.iocoder.foodnexus.module.order.dto.CustomerAddressInfo;
import cn.iocoder.foodnexus.module.order.enums.DeliveryMode;
import com.baomidou.mybatisplus.annotation.KeySequence;
......@@ -143,11 +145,26 @@ public class ErpSaleOutDO extends BaseDO {
private DeliveryMode deliveryMode;
/**
* 配送时间
* 配送时间(取货时间)
*/
private LocalDateTime deliveryTime;
/**
* 接单时间
*/
private LocalDateTime acceptTime;
/**
* 送达时间
*/
private LocalDateTime arrivalTime;
/**
* 客户签收时间
*/
private LocalDateTime signTime;
/**
* 配送人员
*
* DeliveryStaffDO
......@@ -164,4 +181,32 @@ public class ErpSaleOutDO extends BaseDO {
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private CustomerAddressInfo addressInfo;
/**
* 收获仓库id
*/
private Long warehouseId;
/**
* 收获库区id
*/
private Long warehouseAreaId;
/**
* 仓库信息
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private WarehouseInfo warehouseInfo;
/**
* 预计配送开始时间
*/
private LocalDateTime planDeliveryStartTime;
/**
* 预计配送结束时间
*/
private LocalDateTime planDeliveryEndTime;
/**
* 拣货状态
*/
private SaleOrderPickUpStatus pickUpStatus;
}
\ No newline at end of file
......@@ -4,6 +4,7 @@ import cn.iocoder.foodnexus.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.stock.ErpStockOutDO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.stock.ErpWarehouseDO;
import cn.iocoder.foodnexus.module.erp.enums.SaleOrderPickUpStatus;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
......@@ -100,4 +101,16 @@ public class ErpSaleOutItemDO extends BaseDO {
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> remarkFiles;
/**
* 客户订单子项id
* @link // CustomerOrderItemDO#getId()
*/
private Long customerOrderItemId;
/**
* 拣货状态
*
* {@link SaleOrderPickUpStatus}
*/
private SaleOrderPickUpStatus pickUpStatus;
}
\ No newline at end of file
......@@ -25,6 +25,8 @@ public interface ErpSupplierMapper extends BaseMapperX<ErpSupplierDO> {
.inIfPresent(ErpSupplierDO::getId, reqVO.getIdList())
.likeIfPresent(ErpSupplierDO::getMobile, reqVO.getMobile())
.likeIfPresent(ErpSupplierDO::getTelephone, reqVO.getTelephone())
.eqIfPresent(ErpSupplierDO::getUnifiedSocialCreditCode, reqVO.getUnifiedSocialCreditCode())
.likeIfPresent(ErpSupplierDO::getContact, reqVO.getContact())
.orderByDesc(ErpSupplierDO::getId));
}
......
......@@ -31,6 +31,8 @@ public interface ErpSaleOrderMapper extends BaseMapperX<ErpSaleOrderDO> {
.eqIfPresent(ErpSaleOrderDO::getCreator, reqVO.getCreator())
.eqIfPresent(ErpSaleOrderDO::getDeliveryStaffId, reqVO.getDeliveryStaffId())
.eqIfPresent(ErpSaleOrderDO::getPickUpStatus, reqVO.getPickUpStatus())
.eqIfPresent(ErpSaleOrderDO::getCustomerDeptId, reqVO.getCustomerDeptId())
.inIfPresent(ErpSaleOrderDO::getCustomerDeptId, reqVO.getCustomerDeptIds())
.orderByDesc(ErpSaleOrderDO::getId);
// 入库状态。为什么需要 t. 的原因,是因为联表查询时,需要指定表名,不然会报 out_count 错误
if (Objects.equals(reqVO.getOutStatus(), ErpSaleOrderPageReqVO.OUT_STATUS_NONE)) {
......
......@@ -9,6 +9,7 @@ import org.springframework.stereotype.Repository;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.ThreadLocalRandom;
/**
......@@ -90,7 +91,10 @@ public class ErpNoRedisDAO {
Long no = stringRedisTemplate.opsForValue().increment(key);
// 设置过期时间
stringRedisTemplate.expire(key, Duration.ofDays(1L));
return noPrefix + String.format("%06d", no);
return noPrefix + random() + String.format("%06d", no);
}
private int random() {
return ThreadLocalRandom.current().nextInt(100, 1000);
}
}
package cn.iocoder.foodnexus.module.erp.enums;
import cn.iocoder.foodnexus.framework.common.core.ArrayValuable;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.module.erp.enums.stock.ErpStockRecordBizTypeEnum;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
......@@ -18,12 +19,16 @@ public enum SaleOrderPickUpStatus implements ArrayValuable<String> {
TO_BE("TO_BE", "待拣"),
PICK_UP("PICK_UP", "已拣"),
PICK_UP("PICK_UP", "待接单"),
ALREADY("ALREADY", "已发货"),
ACCEPT("ACCEPT", "待配送"),
ALREADY("ALREADY", "配送中"),
ARRIVAL("ARRIVAL", "已到货"),
SIGN("SIGN", "已签收"),
;
public static final String[] ARRAYS = Arrays.stream(values()).map(SaleOrderPickUpStatus::getType).toArray(String[]::new);
......@@ -37,6 +42,18 @@ public enum SaleOrderPickUpStatus implements ArrayValuable<String> {
*/
private final String name;
public static SaleOrderPickUpStatus getByType(String pickUpStatus) {
if (CommonUtil.isBlank(pickUpStatus)) {
return null;
}
for (SaleOrderPickUpStatus em : values()) {
if (em.getType().equals(pickUpStatus)) {
return em;
}
}
return null;
}
@Override
public String[] array() {
return ARRAYS;
......
package cn.iocoder.foodnexus.module.erp.service.customerwarehouse;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
......@@ -92,7 +93,7 @@ public class CustomerWarehouseServiceImpl implements CustomerWarehouseService {
public void deleteByCustomerId(Long customerId, List<Long> warehouseAreaIds) {
customerWarehouseMapper.delete(Wrappers.<CustomerWarehouseDO>lambdaQuery()
.eq(CustomerWarehouseDO::getCustomerId, customerId)
.in(CustomerWarehouseDO::getWarehouseAreaId, warehouseAreaIds));
.in(CommonUtil.isNotEmpty(warehouseAreaIds), CustomerWarehouseDO::getWarehouseAreaId, warehouseAreaIds));
}
@Override
......
......@@ -110,4 +110,6 @@ public interface ErpCustomerService {
* @return
*/
List<Long> queryWarehouseAreaIdByCustomerId(Long id);
ErpCustomerDO getCustomerByUserId(Long loginUserId);
}
\ No newline at end of file
......@@ -147,7 +147,7 @@ public class ErpCustomerServiceImpl implements ErpCustomerService, ErpCustomerAp
ErpWarehouseDO warehouse = warehouseService.getWarehouse(warehouseArea.getParentId());
Optional.ofNullable(warehouse).orElseThrow(() -> new ServiceException(WAREHOUSE_NOT_EXISTS));
customerWarehouseService.deleteByCustomerId(id, CommonUtil.asList(warehouseAreaId));
customerWarehouseService.deleteByCustomerId(id, null);
CustomerWarehouseSaveReqVO saveReqVO = new CustomerWarehouseSaveReqVO();
saveReqVO.setCustomerId(id);
......@@ -179,6 +179,23 @@ public class ErpCustomerServiceImpl implements ErpCustomerService, ErpCustomerAp
return CommonUtil.listConvert(customerWarehouseService.getCustomerWarehouseByCustomerId(id), CustomerWarehouseDO::getWarehouseAreaId);
}
@Override
public ErpCustomerDO getCustomerByUserId(Long userId) {
AdminUserDO user = userService.getUser(userId);
if (!UserSystemEnum.CUSTOMER.getKey().equals(user.getUserSystem())) {
throw exception(ERROR_CUSTOMER_USER);
}
DeptDO topDept = deptService.getTopDept(user.getDeptId());
ErpCustomerDO customer = customerMapper.selectOne(ErpCustomerDO::getSystemDeptId, topDept.getId());
if (CommonUtil.isEmpty(customer)) {
throw exception(CUSTOMER_NOT_EXISTS);
}
if (CommonStatusEnum.isDisable(customer.getStatus())) {
throw exception(CUSTOMER_NOT_ENABLE, customer.getName());
}
return customer;
}
/* --------------- api --------------- */
@Override
......
......@@ -20,6 +20,8 @@ import java.util.Map;
*/
public interface ErpSaleOrderService {
String SALE_ORDER_LOCK = "saleOrderLock:%s";
/**
* 创建销售订单
*
......@@ -123,15 +125,20 @@ public interface ErpSaleOrderService {
void updatePickUp(Long id, Long itemId);
/**
* 配送
* 取货,生成销售出库单
*/
void delivery(Long id, Long deliveryStaffId);
/**
* 到货
* 接单
* @param id
* @param deliveryStaffId
*/
void accept(Long id, Long deliveryStaffId);
/**
* 到货
*/
void arrival(DeliveryOrderUpdateReqVO reqVO, Long deliveryStaffId);
/**
......@@ -143,4 +150,6 @@ public interface ErpSaleOrderService {
ErpSaleOrderDO queryByCustomerOrderId(Long customerOrderId);
ErpSaleOrderItemDO queryItemByCustomerOrderItemId(Long customerOrderItemId);
void receiptByCustomerOrderId(Long id, List<Long> customerOrderItemId);
}
\ No newline at end of file
......@@ -100,4 +100,6 @@ public interface ErpSaleOutService {
ErpSaleOutDO getSaleOutByCustomerOrderId(Long customerOrderId);
void receiptByCustomerOrderId(Long customerOrderId, List<Long> customerOrderItemId);
}
\ No newline at end of file
......@@ -3,6 +3,7 @@ package cn.iocoder.foodnexus.module.erp.service.sale;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.framework.common.util.number.MoneyUtils;
import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;
import cn.iocoder.foodnexus.module.erp.controller.admin.sale.vo.out.ErpSaleOutPageReqVO;
......@@ -15,6 +16,7 @@ import cn.iocoder.foodnexus.module.erp.dal.mysql.sale.ErpSaleOutItemMapper;
import cn.iocoder.foodnexus.module.erp.dal.mysql.sale.ErpSaleOutMapper;
import cn.iocoder.foodnexus.module.erp.dal.redis.no.ErpNoRedisDAO;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpAuditStatus;
import cn.iocoder.foodnexus.module.erp.enums.SaleOrderPickUpStatus;
import cn.iocoder.foodnexus.module.erp.enums.stock.ErpStockRecordBizTypeEnum;
import cn.iocoder.foodnexus.module.erp.service.finance.ErpAccountService;
import cn.iocoder.foodnexus.module.erp.service.product.ErpProductService;
......@@ -23,6 +25,7 @@ import cn.iocoder.foodnexus.module.erp.service.stock.bo.ErpStockRecordCreateReqB
import cn.iocoder.foodnexus.module.product.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.foodnexus.module.product.service.spu.ProductSpuService;
import cn.iocoder.foodnexus.module.system.api.user.AdminUserApi;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
......@@ -30,6 +33,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
......@@ -315,4 +319,20 @@ public class ErpSaleOutServiceImpl implements ErpSaleOutService {
return saleOutMapper.selectOne(ErpSaleOutDO::getCustomerOrderId, customerOrderId);
}
@Override
public void receiptByCustomerOrderId(Long customerOrderId, List<Long> customerOrderItemId) {
LocalDateTime receiptTime = LocalDateTime.now();
saleOutMapper.update(Wrappers.<ErpSaleOutDO>lambdaUpdate()
.set(ErpSaleOutDO::getPickUpStatus, SaleOrderPickUpStatus.SIGN.getType())
.set(ErpSaleOutDO::getSignTime, receiptTime)
.eq(ErpSaleOutDO::getCustomerOrderId, customerOrderId)
.eq(ErpSaleOutDO::getPickUpStatus, SaleOrderPickUpStatus.ARRIVAL.getType()));
if (CommonUtil.isNotEmpty(customerOrderItemId)) {
saleOutItemMapper.update(Wrappers.<ErpSaleOutItemDO>lambdaUpdate()
.set(ErpSaleOutItemDO::getPickUpStatus, SaleOrderPickUpStatus.SIGN.getType())
.in(ErpSaleOutItemDO::getCustomerOrderItemId, customerOrderItemId));
}
}
}
......@@ -31,7 +31,7 @@ import cn.iocoder.foodnexus.module.operations.controller.admin.deliverystaff.vo.
import cn.iocoder.foodnexus.module.operations.dal.dataobject.deliverystaff.DeliveryStaffDO;
import cn.iocoder.foodnexus.module.operations.service.deliverystaff.DeliveryStaffService;
@Tag(name = "APP - 配送员信息")
@Tag(name = "管理后台 - 配送员信息")
@RestController
@RequestMapping("/operation/delivery-staff")
@Validated
......@@ -77,6 +77,22 @@ public class DeliveryStaffController {
return success(true);
}
@PutMapping("/bind-dept")
@Operation(summary = "配送员绑定灶点")
@PreAuthorize("@ss.hasPermission('operation:delivery-staff:update')")
public CommonResult<Boolean> bindDept(@Valid @RequestBody DeliveryStaffBindDeptReqVO updateReqVO) {
deliveryStaffService.bindDept(updateReqVO);
return success(true);
}
@PutMapping("bind-dept-release")
@Operation(summary = "配送员解绑灶点")
@PreAuthorize("@ss.hasPermission('operation:delivery-staff:update')")
public CommonResult<Boolean> bindDeptRelease(@Valid @RequestBody DeliveryStaffBindDeptReqVO updateReqVO) {
deliveryStaffService.bindDeptRelease(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除配送员信息")
......
package cn.iocoder.foodnexus.module.operations.controller.admin.deliverystaff.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
/**
* @author : yanghao
* create at: 2025/8/28 16:57
* @description: 配送员绑定客户
*/
@Data
public class DeliveryStaffBindDeptReqVO {
@Schema(description = "配送员id")
@NotNull(message = "配送员不能为空")
private Long staffId;
@Schema(description = "灶点id集合")
@NotNull(message = "灶点id不能为空")
private List<Long> deptIdList;
}
......@@ -20,9 +20,11 @@ public class DeliveryStaffCustomerRespVO {
@ExcelProperty("配送员id")
private Long deliveryStaffId;
@Schema(description = "客户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "24925")
@ExcelProperty("客户id")
private Long customerId;
@Schema(description = "客户id/灶点id", requiredMode = Schema.RequiredMode.REQUIRED, example = "24925")
@ExcelProperty("客户id/灶点id")
private Long targetId;
private Boolean isDept;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
......
......@@ -16,12 +16,12 @@ public class DeliveryStaffCustomerSaveReqVO {
@NotNull(message = "配送员id不能为空")
private Long deliveryStaffId;
@Schema(description = "客户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "24925")
@NotNull(message = "客户id不能为空")
private Long customerId;
@Schema(description = "客户id/灶点id", requiredMode = Schema.RequiredMode.REQUIRED, example = "24925")
@NotNull(message = "目标id不能为空")
private Long targetId;
@Schema(description = "客户灶点id")
@NotNull(message = "客户灶点id不能可空")
private Long customerDeptId;
@Schema(description = "true-灶点 / false-客户")
@NotNull(message = "isDept不能可空")
private Boolean isDept;
}
\ No newline at end of file
......@@ -95,6 +95,12 @@ public class ScoringWeightController {
return success(BeanUtils.toBean(pageResult, ScoringWeightRespVO.class));
}
@GetMapping("/list")
@Operation(summary = "获取全部评分权重")
public CommonResult<List<ScoringWeightRespVO>> getScoringWeightList() {
return success(BeanUtils.toBean(scoringWeightService.listAll(), ScoringWeightRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出评分权重 Excel")
@PreAuthorize("@ss.hasPermission('operations:scoring-weight:export')")
......
package cn.iocoder.foodnexus.module.operations.controller.app.customer;
import cn.iocoder.foodnexus.framework.common.enums.UserSystemEnum;
import cn.iocoder.foodnexus.framework.common.pojo.CommonResult;
import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;
import cn.iocoder.foodnexus.module.erp.controller.admin.sale.vo.customer.ErpCustomerRespVO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.sale.ErpCustomerDO;
import cn.iocoder.foodnexus.module.erp.service.sale.ErpCustomerService;
import cn.iocoder.foodnexus.module.system.annotations.AppSystemAuth;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import static cn.iocoder.foodnexus.framework.common.pojo.CommonResult.success;
import static cn.iocoder.foodnexus.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
/**
* @author : yanghao
* create at: 2025/10/14 17:08
* @description: APP - 客户信息
*/
@Tag(name = "管理后台 - ERP 客户")
@RestController
@RequestMapping("/erp/customer")
@Validated
@AppSystemAuth(UserSystemEnum.CUSTOMER)
public class AppCustomerController {
@Resource
private ErpCustomerService customerService;
@GetMapping("/get")
@Operation(summary = "获得客户")
public CommonResult<ErpCustomerRespVO> getCustomer() {
ErpCustomerDO customer = customerService.getCustomerByUserId(getLoginUserId());
return success(BeanUtils.toBean(customer, ErpCustomerRespVO.class, item -> {
item.setWarehouseAreaIds(customerService.queryWarehouseAreaIdByCustomerId(item.getId()));
}));
}
}
package cn.iocoder.foodnexus.module.operations.controller.app.customerrequire;
import cn.iocoder.foodnexus.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.foodnexus.framework.common.enums.UserSystemEnum;
import cn.iocoder.foodnexus.framework.common.pojo.CommonResult;
import cn.iocoder.foodnexus.framework.common.pojo.PageParam;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
......@@ -15,6 +16,7 @@ import cn.iocoder.foodnexus.module.operations.controller.admin.customerrequire.v
import cn.iocoder.foodnexus.module.operations.controller.admin.customerrequire.vo.CustomerRequireSaveReqVO;
import cn.iocoder.foodnexus.module.operations.dal.dataobject.customerrequire.CustomerRequireDO;
import cn.iocoder.foodnexus.module.operations.service.customerrequire.CustomerRequireService;
import cn.iocoder.foodnexus.module.system.annotations.AppSystemAuth;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
......@@ -36,6 +38,7 @@ import static cn.iocoder.foodnexus.framework.common.pojo.CommonResult.success;
@RestController
@RequestMapping("/oper/customer-require")
@Validated
@AppSystemAuth(UserSystemEnum.CUSTOMER)
public class AppCustomerRequireController {
@Resource
......
package cn.iocoder.foodnexus.module.operations.controller.app.delivery;
import cn.iocoder.foodnexus.framework.common.enums.UserSystemEnum;
import cn.iocoder.foodnexus.framework.common.pojo.CommonResult;
import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;
import cn.iocoder.foodnexus.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.foodnexus.module.operations.controller.admin.deliverystaff.vo.DeliveryStaffRespVO;
import cn.iocoder.foodnexus.module.operations.controller.admin.deliverystaff.vo.DeliveryStaffSaveReqVO;
import cn.iocoder.foodnexus.module.operations.dal.dataobject.deliverystaff.DeliveryStaffDO;
import cn.iocoder.foodnexus.module.operations.service.deliverystaff.DeliveryStaffService;
import cn.iocoder.foodnexus.module.operations.service.deliverystaffcustomer.DeliveryStaffCustomerService;
import cn.iocoder.foodnexus.module.operations.service.vehicleinfo.VehicleInfoService;
import cn.iocoder.foodnexus.module.system.annotations.AppSystemAuth;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import static cn.iocoder.foodnexus.framework.common.pojo.CommonResult.success;
/**
* @author : yanghao
* create at: 2025/10/14 16:14
* @description: 配送员 - 个人信息
*/
@Tag(name = "配送员 - 个人信息")
@RestController
@RequestMapping("/delivery/oper")
@Validated
@AppSystemAuth(UserSystemEnum.DELIVERY)
public class AppDeliveryStaffController {
@Autowired
private DeliveryStaffService deliveryStaffService;
@Resource
private DeliveryStaffCustomerService deliveryStaffCustomerService;
@Resource
private VehicleInfoService vehicleInfoService;
@GetMapping("/get")
@Operation(summary = "获得配送员信息")
public CommonResult<DeliveryStaffRespVO> getDeliveryStaff() {
DeliveryStaffDO deliveryStaff = deliveryStaffService.getDeliveryStaffByUserId(SecurityFrameworkUtils.getLoginUserId());
return success(BeanUtils.toBean(deliveryStaff, DeliveryStaffRespVO.class, item -> {
// item.setCustomerList(deliveryStaffCustomerService.queryCustomerListByDeliveryStaffId(item.getId()));
item.setVehicleInfo(vehicleInfoService.queryByStaffId(item.getId()));
// item.setCustomerDeptList(deliveryStaffCustomerService.queryDeptListByStaffId(item.getId()));
}));
}
}
......@@ -32,13 +32,13 @@ public class DeliveryStaffCustomerDO extends BaseDO {
*/
private Long deliveryStaffId;
/**
* 客户id
* 客户id/灶点id
*/
private Long customerId;
private Long targetId;
/**
* 客户灶点id
* false-客户/true-灶点
*/
private Long customerDeptId;
private Boolean isDept;
}
\ No newline at end of file
......@@ -5,7 +5,6 @@ import jakarta.validation.*;
import cn.iocoder.foodnexus.module.operations.controller.admin.deliverystaff.vo.*;
import cn.iocoder.foodnexus.module.operations.dal.dataobject.deliverystaff.DeliveryStaffDO;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.pojo.PageParam;
/**
* 配送员信息 Service 接口
......@@ -14,6 +13,8 @@ import cn.iocoder.foodnexus.framework.common.pojo.PageParam;
*/
public interface DeliveryStaffService {
String USER_INIT_PASSWORD_KEY = "system.user.init-password";
/**
* 创建配送员信息
*
......@@ -62,4 +63,10 @@ public interface DeliveryStaffService {
void bindCustomer(DeliveryStaffBindCustomerReqVO updateReqVO);
void bindCustomerRelease(DeliveryStaffBindCustomerReqVO updateReqVO);
DeliveryStaffDO getDeliveryStaffByUserId(Long loginUserId);
void bindDept(@Valid DeliveryStaffBindDeptReqVO updateReqVO);
void bindDeptRelease(@Valid DeliveryStaffBindDeptReqVO updateReqVO);
}
\ No newline at end of file
package cn.iocoder.foodnexus.module.operations.service.deliverystaff;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.stream.StreamUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.foodnexus.framework.common.enums.UserSystemEnum;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.module.infra.api.config.ConfigApi;
import cn.iocoder.foodnexus.module.operations.dal.dataobject.deliverystaffcustomer.DeliveryStaffCustomerDO;
import cn.iocoder.foodnexus.module.operations.dal.mysql.deliverystaffcustomer.DeliveryStaffCustomerMapper;
import cn.iocoder.foodnexus.module.order.api.DeliveryStaffApi;
import cn.iocoder.foodnexus.module.order.dto.DeliveryStaffSimpleInfo;
import cn.iocoder.foodnexus.module.system.controller.admin.user.vo.user.UserSaveReqVO;
import cn.iocoder.foodnexus.module.system.service.dept.DeptService;
import cn.iocoder.foodnexus.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.foodnexus.module.system.service.user.AdminUserService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -22,15 +22,13 @@ import java.util.*;
import cn.iocoder.foodnexus.module.operations.controller.admin.deliverystaff.vo.*;
import cn.iocoder.foodnexus.module.operations.dal.dataobject.deliverystaff.DeliveryStaffDO;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.pojo.PageParam;
import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;
import cn.iocoder.foodnexus.module.operations.dal.mysql.deliverystaff.DeliveryStaffMapper;
import static cn.iocoder.foodnexus.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.foodnexus.module.operations.enums.ErrorCodeConstants.*;
import static cn.iocoder.foodnexus.module.system.enums.ErrorCodeConstants.USER_IMPORT_INIT_PASSWORD;
/**
* 配送员信息 Service 实现类
......@@ -50,31 +48,46 @@ public class DeliveryStaffServiceImpl implements DeliveryStaffService, DeliveryS
@Autowired
private AdminUserService userService;
@Autowired
private ConfigApi configApi;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createDeliveryStaff(DeliveryStaffSaveReqVO createReqVO) {
// 插入
DeliveryStaffDO deliveryStaff = BeanUtils.toBean(createReqVO, DeliveryStaffDO.class);
String userName = validStaffName(createReqVO.getName(), 1);
// 新建一个账号
UserSaveReqVO userSaveReqVO = new UserSaveReqVO();
userSaveReqVO.setUsername(createReqVO.getName());
userSaveReqVO.setNickname(createReqVO.getName());
userSaveReqVO.setUsername(userName);
userSaveReqVO.setNickname(userName);
userSaveReqVO.setRemark(createReqVO.getRemark());
// TODO 待定
userSaveReqVO.setDeptId(100L);
userSaveReqVO.setMobile(createReqVO.getContact());
userSaveReqVO.setUserSystem(UserSystemEnum.DELIVERY.getKey());
userSaveReqVO.setPassword("123456");
String initPassword = configApi.getConfigValueByKey(USER_INIT_PASSWORD_KEY);
if (StrUtil.isEmpty(initPassword)) {
throw exception(USER_IMPORT_INIT_PASSWORD);
}
userSaveReqVO.setPassword(initPassword);
Long userId = userService.createUser(userSaveReqVO);
deliveryStaff.setUserId(userId);
deliveryStaffMapper.insert(deliveryStaff);
// 返回
return deliveryStaff.getId();
}
private String validStaffName(String name, int suffix) {
AdminUserDO user = userService.getUserByUsername(name);
if (CommonUtil.isNotEmpty(user)) {
return validStaffName(name + suffix, suffix + 1);
}
return name;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateDeliveryStaff(DeliveryStaffSaveReqVO updateReqVO) {
......@@ -86,7 +99,7 @@ public class DeliveryStaffServiceImpl implements DeliveryStaffService, DeliveryS
UserSaveReqVO updateUser = new UserSaveReqVO();
updateUser.setId(deliveryStaffDO.getUserId());
updateUser.setUsername(updateReqVO.getName());
// updateUser.setUsername(updateReqVO.getName());
updateUser.setNickname(updateReqVO.getName());
updateUser.setRemark(updateReqVO.getRemark());
updateUser.setMobile(updateReqVO.getContact());
......@@ -133,7 +146,8 @@ public class DeliveryStaffServiceImpl implements DeliveryStaffService, DeliveryS
if (CommonUtil.isNotEmpty(updateReqVO.getCustomerIdList())) {
List<DeliveryStaffCustomerDO> deliveryStaffCustomerDOS = CommonUtil.listConvert(updateReqVO.getCustomerIdList(), customer -> {
DeliveryStaffCustomerDO deliveryStaffCustomerDO = new DeliveryStaffCustomerDO();
deliveryStaffCustomerDO.setCustomerId(customer);
deliveryStaffCustomerDO.setTargetId(customer);
deliveryStaffCustomerDO.setIsDept(Boolean.FALSE);
deliveryStaffCustomerDO.setDeliveryStaffId(updateReqVO.getStaffId());
return deliveryStaffCustomerDO;
});
......@@ -146,7 +160,38 @@ public class DeliveryStaffServiceImpl implements DeliveryStaffService, DeliveryS
validateDeliveryStaffExists(updateReqVO.getStaffId());
deliveryStaffCustomerMapper.delete(Wrappers.<DeliveryStaffCustomerDO>lambdaQuery()
.eq(DeliveryStaffCustomerDO::getDeliveryStaffId, updateReqVO.getStaffId())
.in(DeliveryStaffCustomerDO::getCustomerId, updateReqVO.getCustomerIdList()));
.eq(DeliveryStaffCustomerDO::getIsDept, Boolean.FALSE)
.in(DeliveryStaffCustomerDO::getTargetId, updateReqVO.getCustomerIdList()));
}
@Override
public DeliveryStaffDO getDeliveryStaffByUserId(Long loginUserId) {
return deliveryStaffMapper.selectOne(DeliveryStaffDO::getUserId, loginUserId);
}
@Override
public void bindDept(DeliveryStaffBindDeptReqVO updateReqVO) {
validateDeliveryStaffExists(updateReqVO.getStaffId());
deliveryStaffCustomerMapper.delete(DeliveryStaffCustomerDO::getDeliveryStaffId, updateReqVO.getStaffId());
if (CommonUtil.isNotEmpty(updateReqVO.getDeptIdList())) {
List<DeliveryStaffCustomerDO> deliveryStaffCustomerDOS = CommonUtil.listConvert(updateReqVO.getDeptIdList(), deptId -> {
DeliveryStaffCustomerDO deliveryStaffCustomerDO = new DeliveryStaffCustomerDO();
deliveryStaffCustomerDO.setTargetId(deptId);
deliveryStaffCustomerDO.setIsDept(Boolean.TRUE);
deliveryStaffCustomerDO.setDeliveryStaffId(updateReqVO.getStaffId());
return deliveryStaffCustomerDO;
});
deliveryStaffCustomerMapper.insertBatch(deliveryStaffCustomerDOS);
}
}
@Override
public void bindDeptRelease(DeliveryStaffBindDeptReqVO updateReqVO) {
validateDeliveryStaffExists(updateReqVO.getStaffId());
deliveryStaffCustomerMapper.delete(Wrappers.<DeliveryStaffCustomerDO>lambdaQuery()
.eq(DeliveryStaffCustomerDO::getDeliveryStaffId, updateReqVO.getStaffId())
.eq(DeliveryStaffCustomerDO::getIsDept, Boolean.TRUE)
.in(DeliveryStaffCustomerDO::getTargetId, updateReqVO.getDeptIdList()));
}
@Override
......
......@@ -92,14 +92,19 @@ public class DeliveryStaffCustomerServiceImpl implements DeliveryStaffCustomerSe
public List<ErpCustomerRespVO> queryCustomerListByDeliveryStaffId(Long staffId) {
List<DeliveryStaffCustomerDO> list = deliveryStaffCustomerMapper.selectList(Wrappers.<DeliveryStaffCustomerDO>lambdaQuery()
.eq(DeliveryStaffCustomerDO::getDeliveryStaffId, staffId)
.groupBy(DeliveryStaffCustomerDO::getCustomerId));
return BeanUtils.toBean(customerService.getCustomerList(list.stream().map(DeliveryStaffCustomerDO::getCustomerId).toList()), ErpCustomerRespVO.class);
.eq(DeliveryStaffCustomerDO::getIsDept, Boolean.FALSE)
.groupBy(DeliveryStaffCustomerDO::getTargetId));
return BeanUtils.toBean(customerService.getCustomerList(list.stream().map(DeliveryStaffCustomerDO::getTargetId).toList()),
ErpCustomerRespVO.class);
}
@Override
public List<DeptSimpleRespVO> queryDeptListByStaffId(Long staffId) {
List<DeliveryStaffCustomerDO> deliveryStaffCustomerDOS = deliveryStaffCustomerMapper.selectList(DeliveryStaffCustomerDO::getDeliveryStaffId, staffId);
return BeanUtils.toBean(deptService.getDeptList(CommonUtil.listConvertSet(deliveryStaffCustomerDOS, DeliveryStaffCustomerDO::getCustomerDeptId)),
List<DeliveryStaffCustomerDO> deliveryStaffCustomerDOS = deliveryStaffCustomerMapper.selectList(Wrappers.<DeliveryStaffCustomerDO>lambdaQuery()
.eq(DeliveryStaffCustomerDO::getDeliveryStaffId, staffId)
.eq(DeliveryStaffCustomerDO::getIsDept, Boolean.TRUE)
.groupBy(DeliveryStaffCustomerDO::getTargetId));
return BeanUtils.toBean(deptService.getDeptList(CommonUtil.listConvertSet(deliveryStaffCustomerDOS, DeliveryStaffCustomerDO::getTargetId)),
DeptSimpleRespVO.class);
}
......
......@@ -3,6 +3,7 @@ package cn.iocoder.foodnexus.module.order.dto;
import cn.iocoder.foodnexus.module.erp.api.vo.warehouse.WarehouseInfo;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import cn.iocoder.foodnexus.module.order.enums.DeliveryMode;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
......@@ -34,6 +35,10 @@ public class CustomerOrderDTO {
*/
private Long customerId;
/**
* 灶点id
*/
private Long customerDeptId;
/**
* 收获仓库id
*/
private Long warehouseId;
......@@ -100,4 +105,9 @@ public class CustomerOrderDTO {
*/
private CustomerOrderRemark orderRemark;
/**
* 是否已评论
*/
private Boolean hasScore;
}
package cn.iocoder.foodnexus.module.order.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.util.List;
......@@ -15,43 +17,32 @@ import java.util.List;
@Data
public class DeliveryOrderUpdateReqVO {
/**
* 销售出库单id
*/
@NotNull(message = "销售出库单id不能为空")
private Long saleOutId;
@Schema(description = "客户订单id(customerOrderInfo.id)")
@NotNull(message = "客户订单id(customerOrderInfo.id)")
private Long id;
/**
* 销售出库子项
*/
@NotNull(message = "销售出库子项不能为空")
@Schema(description = "子项")
@NotNull(message = "子项不能为空")
@Valid
private List<Item> items;
@Size(min = 1, message = "子项不能为空")
private List<DeliveryOrderUpdateItems> orderItems;
@Data
public static class Item {
public static class DeliveryOrderUpdateItems {
/**
* 销售出库子id
*/
@NotNull(message = "销售出库子id不能为空")
private Long saleOutItemid;
@Schema(description = "客户子订单id")
@NotNull(message = "客户子订单id不能为空")
private Long id;
/**
* 实际签收数量
*/
@Schema(description = "实际签收数量")
@NotNull(message = "实际签收数量不能为空")
@Min(value = 0, message = "实际签收数量最小为0")
private Integer signedQuantity;
/**
* 说明
*/
@Schema(description = "说明")
private String remark;
/**
* 相关文件
*/
@Schema(description = "相关文件")
private List<String> remarkFiles;
}
......
......@@ -62,7 +62,7 @@ public enum CustomerOrderStatus implements ArrayValuable<String> {
SORTING("商品分拣", "SORTING", 6) {
@Override
public String getText() {
return "您的商品在【%s】分仓已完成分拣,【%s】正在进行配送";
return "您的商品在【%s】分仓已完成分拣";
}
},
// 商品配送
......
......@@ -30,4 +30,10 @@ public class OrderScoreSupplierPageReqVO extends PageParam {
@Schema(description = "联系电话", example = "18818288888")
private String telephone;
@Schema(description = "联系人")
private String contact;
@Schema(description = "统一社会信用代码")
private String unifiedSocialCreditCode;
}
\ No newline at end of file
......@@ -23,10 +23,10 @@ public class AppCustomerOrderItemSaveReqVO {
@Schema(description = "订单商品总价,单位:分", hidden = true)
private Integer orderItemTotal;
@Schema(description = "市场价,单位使用:分")
@Schema(description = "市场价,单位使用:分", hidden = true)
private Integer marketPrice;
@Schema(description = "下浮率(%)")
@Schema(description = "下浮率(%)", hidden = true)
private BigDecimal discount;
@Schema(description = "订单商品数量", requiredMode = Schema.RequiredMode.REQUIRED)
......
......@@ -19,12 +19,10 @@ public class AppCustomerOrderSaveReqVO {
@Schema(description = "订单id,新增为空")
private Long id;
@Schema(description = "收获仓库id", requiredMode = Schema.RequiredMode.REQUIRED, example = "27065")
@NotNull(message = "收获仓库id不能为空")
@Schema(description = "收获仓库id", hidden = true)
private Long warehouseId;
@Schema(description = "收获库区id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26507")
@NotNull(message = "收获库区id不能为空")
@Schema(description = "收获库区id", hidden = true)
private Long warehouseAreaId;
@Schema(description = "客户收货地址id")
......
package cn.iocoder.foodnexus.module.order.controller.app.delivery;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.foodnexus.framework.common.enums.UserSystemEnum;
import cn.iocoder.foodnexus.framework.common.pojo.CommonResult;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.util.collection.MapUtils;
import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;
import cn.iocoder.foodnexus.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.foodnexus.module.erp.controller.admin.product.vo.product.ErpProductRespVO;
import cn.iocoder.foodnexus.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO;
import cn.iocoder.foodnexus.module.erp.controller.admin.sale.vo.order.ErpSaleOrderRespVO;
import cn.iocoder.foodnexus.module.erp.controller.admin.sale.vo.out.ErpSaleOutPageReqVO;
import cn.iocoder.foodnexus.module.erp.controller.admin.sale.vo.out.ErpSaleOutRespVO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.sale.ErpCustomerDO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.sale.ErpSaleOrderDO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.sale.ErpSaleOrderItemDO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.sale.ErpSaleOutDO;
import cn.iocoder.foodnexus.module.erp.service.product.ErpProductService;
import cn.iocoder.foodnexus.module.erp.service.sale.ErpCustomerService;
import cn.iocoder.foodnexus.module.erp.service.sale.ErpSaleOrderService;
import cn.iocoder.foodnexus.module.erp.service.sale.ErpSaleOutService;
import cn.iocoder.foodnexus.module.order.api.DeliveryStaffApi;
import cn.iocoder.foodnexus.module.order.dto.DeliveryOrderUpdateReqVO;
import cn.iocoder.foodnexus.module.system.annotations.AppSystemAuth;
import cn.iocoder.foodnexus.module.system.api.user.AdminUserApi;
import cn.iocoder.foodnexus.module.system.api.user.dto.AdminUserRespDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import static cn.iocoder.foodnexus.framework.common.pojo.CommonResult.success;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.convertMultiMap;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.convertSet;
/**
* @author : yanghao
* create at: 2025/9/26 09:49
* @description: 订单 - 配送
*/
@Tag(name = "配送员 - 订单 - 配送")
@RestController
@RequestMapping("/delivery/order")
@Validated
@AppSystemAuth(UserSystemEnum.DELIVERY)
public class DeliveryOrderController {
@Autowired
private DeliveryStaffApi deliveryStaffApi;
@Autowired
private ErpSaleOrderService saleOrderService;
@Resource
private ErpProductService productService;
@Resource
private ErpCustomerService customerService;
@Autowired
private ErpSaleOutService saleOutService;
@Resource
private AdminUserApi adminUserApi;
// 查询所有已拣销售订单
@GetMapping("/page")
@Operation(summary = "获得销售订单分页")
public CommonResult<PageResult<ErpSaleOrderRespVO>> getSaleOrderPage(@Valid ErpSaleOrderPageReqVO pageReqVO) {
pageReqVO.setDeliveryStaffId(deliveryStaffApi.queryStaffIdByUserId(SecurityFrameworkUtils.getLoginUserId()));
// pageReqVO.setPickUpStatus(SaleOrderPickUpStatus.PICK_UP);
PageResult<ErpSaleOrderDO> pageResult = saleOrderService.getSaleOrderPage(pageReqVO);
return success(buildSaleOrderVOPageResult(pageResult));
}
// TODO 配送单修改实际配送数量在哪一步?
// 配送订单,生成销售出库单
@PostMapping("/delivery")
@Operation(summary = "配送订单")
@Parameter(name = "id", description = "销售订单id", required = true)
public CommonResult<Boolean> delivery(@RequestParam("id") Long id) {
saleOrderService.delivery(id, deliveryStaffApi.queryStaffIdByUserId(SecurityFrameworkUtils.getLoginUserId()));
return success(Boolean.TRUE);
}
@GetMapping("/sale-out/page")
@Operation(summary = "获得销售出库分页")
public CommonResult<PageResult<ErpSaleOutRespVO>> getSaleOutPage(@Valid ErpSaleOutPageReqVO pageReqVO) {
PageResult<ErpSaleOutDO> pageResult = saleOutService.getSaleOutPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, ErpSaleOutRespVO.class));
}
// 订单到货
@PostMapping("/arrival")
@Operation(summary = "订单到货")
@Parameter(name = "id", description = "销售订单id", required = true)
public CommonResult<Boolean> arrival(@RequestBody @Valid DeliveryOrderUpdateReqVO reqVO) {
saleOrderService.arrival(reqVO, deliveryStaffApi.queryStaffIdByUserId(SecurityFrameworkUtils.getLoginUserId()));
return success(Boolean.TRUE);
}
private PageResult<ErpSaleOrderRespVO> buildSaleOrderVOPageResult(PageResult<ErpSaleOrderDO> pageResult) {
if (CollUtil.isEmpty(pageResult.getList())) {
return PageResult.empty(pageResult.getTotal());
}
// 1.1 订单项
List<ErpSaleOrderItemDO> saleOrderItemList = saleOrderService.getSaleOrderItemListByOrderIds(
convertSet(pageResult.getList(), ErpSaleOrderDO::getId));
Map<Long, List<ErpSaleOrderItemDO>> saleOrderItemMap = convertMultiMap(saleOrderItemList, ErpSaleOrderItemDO::getOrderId);
// 1.2 产品信息
Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap(
convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductId));
// 1.3 客户信息
Map<Long, ErpCustomerDO> customerMap = customerService.getCustomerMap(
convertSet(pageResult.getList(), ErpSaleOrderDO::getCustomerId));
// 1.4 管理员信息
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
convertSet(pageResult.getList(), saleOrder -> Long.parseLong(saleOrder.getCreator())));
// 2. 开始拼接
return BeanUtils.toBean(pageResult, ErpSaleOrderRespVO.class, saleOrder -> {
saleOrder.setItems(BeanUtils.toBean(saleOrderItemMap.get(saleOrder.getId()), ErpSaleOrderRespVO.Item.class,
item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName())
.setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName()))));
saleOrder.setProductNames(CollUtil.join(saleOrder.getItems(), ",", ErpSaleOrderRespVO.Item::getProductName));
MapUtils.findAndThen(customerMap, saleOrder.getCustomerId(), supplier -> saleOrder.setCustomerName(supplier.getName()));
MapUtils.findAndThen(userMap, Long.parseLong(saleOrder.getCreator()), user -> saleOrder.setCreatorName(user.getNickname()));
});
}
}
package cn.iocoder.foodnexus.module.order.controller.app.delivery;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.foodnexus.framework.common.enums.UserSystemEnum;
import cn.iocoder.foodnexus.framework.common.pojo.CommonResult;
import cn.iocoder.foodnexus.framework.common.pojo.PageParam;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.framework.common.util.collection.MapUtils;
import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;
import cn.iocoder.foodnexus.framework.common.validation.InEnum;
import cn.iocoder.foodnexus.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.foodnexus.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO;
import cn.iocoder.foodnexus.module.erp.controller.admin.sale.vo.order.ErpSaleOrderRespVO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.sale.ErpCustomerDO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.sale.ErpSaleOrderDO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.sale.ErpSaleOrderItemDO;
import cn.iocoder.foodnexus.module.erp.enums.SaleOrderPickUpStatus;
import cn.iocoder.foodnexus.module.erp.service.sale.ErpCustomerService;
import cn.iocoder.foodnexus.module.erp.service.sale.ErpSaleOrderService;
import cn.iocoder.foodnexus.module.erp.service.sale.ErpSaleOutService;
import cn.iocoder.foodnexus.module.erp.service.stock.ErpStockService;
import cn.iocoder.foodnexus.module.operations.dal.dataobject.deliverystaff.DeliveryStaffDO;
import cn.iocoder.foodnexus.module.operations.service.deliverystaff.DeliveryStaffService;
import cn.iocoder.foodnexus.module.operations.service.deliverystaffcustomer.DeliveryStaffCustomerService;
import cn.iocoder.foodnexus.module.order.api.DeliveryStaffApi;
import cn.iocoder.foodnexus.module.order.controller.admin.customerorder.vo.CustomerOrderRespVO;
import cn.iocoder.foodnexus.module.order.controller.admin.customerorderitem.vo.CustomerOrderItemRespVO;
import cn.iocoder.foodnexus.module.order.controller.app.delivery.vo.DeliveryOrderDetails;
import cn.iocoder.foodnexus.module.order.controller.app.delivery.vo.DeliverySaleOrderRespVO;
import cn.iocoder.foodnexus.module.order.dal.dataobject.customerorder.CustomerOrderDO;
import cn.iocoder.foodnexus.module.order.dto.DeliveryOrderUpdateReqVO;
import cn.iocoder.foodnexus.module.order.service.customerorder.CustomerOrderService;
import cn.iocoder.foodnexus.module.order.service.customerorderitem.CustomerOrderItemService;
import cn.iocoder.foodnexus.module.product.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.foodnexus.module.product.service.spu.ProductSpuService;
import cn.iocoder.foodnexus.module.system.annotations.AppSystemAuth;
import cn.iocoder.foodnexus.module.system.api.user.AdminUserApi;
import cn.iocoder.foodnexus.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.foodnexus.module.system.controller.admin.dept.vo.dept.DeptSimpleRespVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import static cn.iocoder.foodnexus.framework.common.pojo.CommonResult.success;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.convertMultiMap;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.convertSet;
/**
* @author : yanghao
* create at: 2025/10/14 17:56
* @description: 配送员 - 订单 - 接单
*/
@Tag(name = "配送员 - 订单 - 接单")
@RestController
@RequestMapping("/delivery/sale-order")
@Validated
@AppSystemAuth(UserSystemEnum.DELIVERY)
public class DeliverySaleOrderController {
@Autowired
private DeliveryStaffApi deliveryStaffApi;
@Autowired
private DeliveryStaffCustomerService deliveryStaffCustomerService;
@Autowired
private ErpSaleOrderService saleOrderService;
@Autowired
private CustomerOrderService customerOrderService;
@Autowired
private CustomerOrderItemService customerOrderItemService;
@GetMapping("/page")
@Operation(summary = "查询配送单")
@Parameter(name = "pickUpStatus", description = "拣货状态(字典类型:sale_order_pick_up_status)", required = true, example = "1024")
public CommonResult<PageResult<DeliverySaleOrderRespVO>> getSaleOrderPage(@Valid PageParam pageReq,
@InEnum(value = SaleOrderPickUpStatus.class)
@RequestParam("pickUpStatus")
String pickUpStatus) {
ErpSaleOrderPageReqVO pageReqVO = new ErpSaleOrderPageReqVO();
pageReqVO.setPageNo(pageReq.getPageNo());
pageReqVO.setPageSize(pageReq.getPageSize());
if (SaleOrderPickUpStatus.PICK_UP.getType().equals(pickUpStatus) || SaleOrderPickUpStatus.TO_BE.getType().equals(pickUpStatus) ) {
List<DeptSimpleRespVO> deptSimpleRespVOS = deliveryStaffCustomerService.queryDeptListByStaffId(deliveryStaffApi.queryStaffIdByUserId(SecurityFrameworkUtils.getLoginUserId()));
pageReqVO.setCustomerDeptIds(CommonUtil.listConvert(deptSimpleRespVOS, DeptSimpleRespVO::getId));
} else {
pageReqVO.setDeliveryStaffId(deliveryStaffApi.queryStaffIdByUserId(SecurityFrameworkUtils.getLoginUserId()));
}
pageReqVO.setPickUpStatus(SaleOrderPickUpStatus.getByType(pickUpStatus));
return success(BeanUtils.toBean(saleOrderService.getSaleOrderPage(pageReqVO), DeliverySaleOrderRespVO.class));
}
@GetMapping("/get")
@Operation(summary = "获得销售订单")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
public CommonResult<DeliveryOrderDetails<DeliverySaleOrderRespVO>> getSaleOrder(@RequestParam("id") Long id) {
ErpSaleOrderDO saleOrder = saleOrderService.getSaleOrder(id);
if (saleOrder == null) {
return success(null);
}
DeliveryOrderDetails<DeliverySaleOrderRespVO> result = new DeliveryOrderDetails<>();
result.setDeliveryInfo(BeanUtils.toBean(saleOrder, DeliverySaleOrderRespVO.class));
result.setCustomerOrderInfo(BeanUtils.toBean(customerOrderService.getCustomerOrder(saleOrder.getCustomerOrderId()),
CustomerOrderRespVO.class, item ->
item.setOrderItems(BeanUtils.toBean(customerOrderItemService.queryByOrderId(item.getId()), CustomerOrderItemRespVO.class))));
return success(result);
}
@PostMapping("/accept")
@Operation(summary = "确认接单")
@Parameter(name = "id", description = "配送单id(deliveryInfo.id)", required = true)
public CommonResult<Boolean> accept(@RequestParam("id") Long id) {
saleOrderService.accept(id, deliveryStaffApi.queryStaffIdByUserId(SecurityFrameworkUtils.getLoginUserId()));
return success(Boolean.TRUE);
}
// 配送订单,生成销售出库单
@PostMapping("/delivery")
@Operation(summary = "确认取货")
@Parameter(name = "id", description = "配送单id(deliveryInfo.id)", required = true)
public CommonResult<Boolean> delivery(@RequestParam("id") Long id) {
saleOrderService.delivery(id, deliveryStaffApi.queryStaffIdByUserId(SecurityFrameworkUtils.getLoginUserId()));
return success(Boolean.TRUE);
}
// 订单到货
@PostMapping("/arrival")
@Operation(summary = "订单到货")
public CommonResult<Boolean> arrival(@RequestBody @Valid DeliveryOrderUpdateReqVO reqVO) {
saleOrderService.arrival(reqVO, deliveryStaffApi.queryStaffIdByUserId(SecurityFrameworkUtils.getLoginUserId()));
return success(Boolean.TRUE);
}
}
package cn.iocoder.foodnexus.module.order.controller.app.delivery.vo;
import cn.iocoder.foodnexus.module.order.controller.admin.customerorder.vo.CustomerOrderRespVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* @author : yanghao
* create at: 2025/10/15 10:18
* @description: 配送员 - 订单详情
*/
@Data
public class DeliveryOrderDetails<T> {
@Schema(description = "配送信息")
private T deliveryInfo;
@Schema(description = "客户订单信息")
private CustomerOrderRespVO customerOrderInfo;
}
package cn.iocoder.foodnexus.module.order.controller.app.delivery.vo;
import cn.idev.excel.annotation.ExcelProperty;
import cn.iocoder.foodnexus.module.erp.api.vo.warehouse.WarehouseInfo;
import cn.iocoder.foodnexus.module.erp.enums.SaleOrderPickUpStatus;
import cn.iocoder.foodnexus.module.order.dto.CustomerAddressInfo;
import cn.iocoder.foodnexus.module.order.enums.DeliveryMode;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* @author : yanghao
* create at: 2025/10/14 18:16
* @description: 配送员 - 销售订单
*/
@Data
public class DeliverySaleOrderRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386")
@ExcelProperty("编号")
private Long id;
@Schema(description = "销售单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "XS001")
@ExcelProperty("销售单编号")
private String no;
@Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1724")
private Long customerId;
@Schema(description = "客户名称", example = "芋道")
@ExcelProperty("客户名称")
private String customerName;
@Schema(description = "下单时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("下单时间")
private LocalDateTime orderTime;
@Schema(description = "客户订单id")
private Long customerOrderId;
@Schema(description = "配送模式")
private DeliveryMode deliveryMode;
@Schema(description = "配送时间(取货时间)")
private LocalDateTime deliveryTime;
@Schema(description = "接单时间")
private LocalDateTime acceptTime;
@Schema(description = "送达时间")
private LocalDateTime arrivalTime;
@Schema(description = "客户签收时间")
private LocalDateTime signTime;
@Schema(description = "客户收货地址id")
private Long addressId;
@Schema(description = "客户收货地址info")
@TableField(typeHandler = JacksonTypeHandler.class)
private CustomerAddressInfo addressInfo;
@Schema(description = "拣货状态")
private SaleOrderPickUpStatus pickUpStatus;
@Schema(description = "收获仓库id", requiredMode = Schema.RequiredMode.REQUIRED, example = "27065")
private Long warehouseId;
@Schema(description = "收获库区id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26507")
private Long warehouseAreaId;
@Schema(description = "仓库信息")
private WarehouseInfo warehouseInfo;
@Schema(description = "预计配送开始时间")
private LocalDateTime planDeliveryStartTime;
@Schema(description = "预计配送结束时间")
private LocalDateTime planDeliveryEndTime;
}
package cn.iocoder.foodnexus.module.order.controller.app.shoppingcart;
import cn.iocoder.foodnexus.framework.common.enums.UserSystemEnum;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.framework.common.util.collection.MapUtils;
import cn.iocoder.foodnexus.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.foodnexus.module.order.controller.app.shoppingcart.vo.ShoppingCartPageReqVO;
import cn.iocoder.foodnexus.module.order.controller.app.shoppingcart.vo.ShoppingCartRespVO;
import cn.iocoder.foodnexus.module.order.controller.app.shoppingcart.vo.ShoppingCartSaveReqVO;
import cn.iocoder.foodnexus.module.product.api.ProductSpuApi;
import cn.iocoder.foodnexus.module.product.api.dto.ProductInfo;
import cn.iocoder.foodnexus.module.product.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.foodnexus.module.product.service.spu.ProductSpuService;
import cn.iocoder.foodnexus.module.system.annotations.AppSystemAuth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
......@@ -36,6 +43,9 @@ public class ShoppingCartController {
@Resource
private ShoppingCartService shoppingCartService;
@Autowired
private ProductSpuService productService;
@PostMapping("/create")
@Operation(summary = "创建购物车")
public CommonResult<Long> createShoppingCart(@Valid @RequestBody ShoppingCartSaveReqVO createReqVO) {
......@@ -70,7 +80,8 @@ public class ShoppingCartController {
@Parameter(name = "id", description = "编号", required = true, example = "1024")
public CommonResult<ShoppingCartRespVO> getShoppingCart(@RequestParam("id") Long id) {
ShoppingCartDO shoppingCart = shoppingCartService.getShoppingCart(id);
return success(BeanUtils.toBean(shoppingCart, ShoppingCartRespVO.class));
return success(BeanUtils.toBean(shoppingCart, ShoppingCartRespVO.class, cart ->
cart.setProductInfo(BeanUtils.toBean(productService.getSpu(cart.getProductId()), ProductInfo.class))));
}
@GetMapping("/page")
......@@ -78,7 +89,10 @@ public class ShoppingCartController {
public CommonResult<PageResult<ShoppingCartRespVO>> getShoppingCartPage(@Valid ShoppingCartPageReqVO pageReqVO) {
pageReqVO.setCreator(SecurityFrameworkUtils.getLoginUserId());
PageResult<ShoppingCartDO> pageResult = shoppingCartService.getShoppingCartPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, ShoppingCartRespVO.class));
Map<Long, ProductSpuDO> productMap = productService.getSpuMap(CommonUtil.listConvertSet(pageResult.getList(), ShoppingCartDO::getProductId));
return success(BeanUtils.toBean(pageResult, ShoppingCartRespVO.class, item -> {
MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductInfo(BeanUtils.toBean(product, ProductInfo.class)));
}));
}
}
\ No newline at end of file
package cn.iocoder.foodnexus.module.order.controller.app.shoppingcart.vo;
import cn.iocoder.foodnexus.module.product.api.dto.ProductInfo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
......@@ -24,6 +25,9 @@ public class ShoppingCartRespVO {
@ExcelProperty("商品名称")
private String productName;
@Schema(description = "商品信息")
private ProductInfo productInfo;
@Schema(description = "单价(分)", requiredMode = Schema.RequiredMode.REQUIRED, example = "6013")
@ExcelProperty("单价(分)")
private Integer unitPrice;
......
......@@ -18,6 +18,8 @@ import cn.iocoder.foodnexus.framework.common.pojo.PageParam;
*/
public interface CustomerOrderService {
String ORDER_LOCK = "orderLock:%s";
/**
* 创建客户总订单
*
......
......@@ -3,6 +3,7 @@ package cn.iocoder.foodnexus.module.order.service.customerorder;
import cn.iocoder.foodnexus.framework.common.enums.UserSystemEnum;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.framework.common.util.spring.SpringUtils;
import cn.iocoder.foodnexus.framework.redis.utils.RedisUtils;
import cn.iocoder.foodnexus.framework.security.core.LoginUser;
import cn.iocoder.foodnexus.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.foodnexus.module.customerpermission.core.annotation.CustomerVisible;
......@@ -11,6 +12,7 @@ import cn.iocoder.foodnexus.module.erp.api.service.ErpCustomerApi;
import cn.iocoder.foodnexus.module.erp.api.service.ErpSupplierApi;
import cn.iocoder.foodnexus.module.erp.api.service.ErpWarehouseApi;
import cn.iocoder.foodnexus.module.erp.controller.admin.sale.vo.returns.ErpSaleReturnSaveReqVO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.customerwarehouse.CustomerWarehouseDO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.sale.*;
import cn.iocoder.foodnexus.module.erp.service.customerwarehouse.CustomerWarehouseService;
import cn.iocoder.foodnexus.module.erp.service.purchase.ErpPurchaseOrderServiceImpl;
......@@ -197,7 +199,20 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
public Long appCreateCustomerOrder(AppCustomerOrderSaveReqVO createReqVO) {
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
Long customerId = customerApi.queryCustomerIdByUserId(loginUser.getId());
List<CustomerWarehouseDO> customerWarehouse = customerWarehouseService.getCustomerWarehouseByCustomerId(customerId);
if (CommonUtil.isEmpty(customerWarehouse) || CommonUtil.isEmpty(customerWarehouse.get(0))) {
throw exception(CUSTOMER_ORDER_ADDRESS_NOEXISTS);
} else {
// TODO 理论上客户只对应一个库区
createReqVO.setWarehouseId(customerWarehouse.get(0).getWarehouseId());
createReqVO.setWarehouseAreaId(customerWarehouse.get(0).getWarehouseAreaId());
}
this.validCustomerOrder(createReqVO, customerId);
Long customerOrderId;
String lock = String.format(ORDER_LOCK, loginUser.getId());
RedisUtils.tryLockRds(lock);
try {
CustomerVisibleProductRespDTO dto = inquireCustomerApi.queryCustomerIdByCustomerId(customerId);
Map<Long, CustomerVisibleProductRespDTO.CustomerProduct> customerProductMap = CommonUtil.listConvertMap(dto.getItems(), CustomerVisibleProductRespDTO.CustomerProduct::getProductId);
Set<Long> supplierSet = new HashSet<>();
......@@ -245,7 +260,7 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
createOrder.setOrderAmount(orderAmount.get());
Long customerOrderId = this.createCustomerOrder(createOrder);
customerOrderId = this.createCustomerOrder(createOrder);
customerOrderItemService.createBatch(collect, customerOrderId);
// 拆分采购订单
......@@ -258,6 +273,9 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
event.setCopyWriter(CommonUtil.asList(String.valueOf(createOrder.getOrderAmount()),
String.valueOf(createOrder.getProductCount())));
orderRecordApi.recordEvent(event);
} finally {
RedisUtils.unLockRds(lock);
}
return customerOrderId;
}
......@@ -276,8 +294,6 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
if (CommonUtil.isEmpty(customerOrder)) {
throw exception(CUSTOMER_ORDER_NOT_EXISTS);
}
Long customerId = customerApi.queryCustomerIdByUserId(loginUser.getId());
this.validCustomerOrder(updateReqVO, customerId);
// TODO 具体修改什么待定
// TODO 采购订单拆分更新
......@@ -295,7 +311,9 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
if (CommonUtil.isEmpty(customerOrder)) {
throw exception(CUSTOMER_ORDER_NOT_EXISTS);
}
// TODO ... 取消订单校验待定(订单状态)
String lock = String.format(ORDER_LOCK, reqVO.getId());
RedisUtils.tryLockRds(lock);
try {
CustomerOrderStatus orderStatus = customerOrder.getOrderStatus();
if (orderStatus.equals(CustomerOrderStatus.ORDER_SUCCESS) ||
orderStatus.equals(CustomerOrderStatus.ORDER_MATCH)) {
......@@ -317,6 +335,9 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
} else {
throw exception(CUSTOMER_ORDER_STATUS_ERROR);
}
} finally {
RedisUtils.unLockRds(lock);
}
}
/**
......@@ -339,6 +360,9 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
if (CommonUtil.isEmpty(saleOut)) {
throw exception(CUSTOMER_ORDER_OUT_ERROR);
}
String lock = String.format(ORDER_LOCK, reqVO.getId());
RedisUtils.tryLockRds(lock);
try {
List<ErpSaleOutItemDO> saleOutItems = saleOutService.getSaleOutItemListByOutId(saleOut.getId());
Map<Long, ErpSaleOutItemDO> productMap = CommonUtil.listConvertMap(saleOutItems, ErpSaleOutItemDO::getProductId);
......@@ -353,7 +377,7 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
CustomerOrderRemark remark = new CustomerOrderRemark();
remark.setOperTime(Date.from(saleOutItem.getCreateTime()
.atZone(ZoneId.systemDefault()) // 绑定系统默认时区
.toInstant() ));
.toInstant()));
remark.setRemarkFiles(saleOutItem.getRemarkFiles());
remark.setRemark(saleOutItem.getRemark());
updateItem.setOrderRemark(remark);
......@@ -372,6 +396,10 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
updateOrder.setActualAmount(actualAmount.get());
customerOrderMapper.updateById(updateOrder);
// 更新销售单和销售出库单的状态
saleOrderService.receiptByCustomerOrderId(reqVO.getId(), CommonUtil.listConvert(customerOrderItems, CustomerOrderItemDO::getId));
saleOutService.receiptByCustomerOrderId(reqVO.getId(), CommonUtil.listConvert(customerOrderItems, CustomerOrderItemDO::getId));
// 订单记录
CustomerOrderRecordEvent event = new CustomerOrderRecordEvent();
event.setOrderStatus(CustomerOrderStatus.SIGN_RECEIPT);
......@@ -379,6 +407,9 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
// TODO 签收单链接
event.setCopyWriter(CommonUtil.asList("TODO 签收单链接"));
orderRecordApi.recordEvent(event);
} finally {
RedisUtils.unLockRds(lock);
}
}
@Override
......@@ -430,6 +461,10 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
throw exception(CUSTOMER_ORDER_STATUS_ERROR);
}
String lock = String.format(ORDER_LOCK, reqVO.getCustomerOrderId());
RedisUtils.tryLockRds(lock);
try {
// 修改客户订单状态
CustomerOrderRecordEvent event = new CustomerOrderRecordEvent();
event.setOrderStatus(CustomerOrderStatus.RETURN);
......@@ -475,6 +510,9 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
}
returnSaveReqVO.setItems(items);
saleReturnService.createSaleReturn(returnSaveReqVO);
} finally {
RedisUtils.unLockRds(lock);
}
}
/**
......@@ -518,6 +556,9 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
if (CommonUtil.isNotEmpty(customerOrder.getHasScore()) && customerOrder.getHasScore()) {
throw exception(CUSTOMER_ORDER_HAS_RECEIPT);
}
String lock = String.format(ORDER_LOCK, reqVO.getOrderId());
RedisUtils.tryLockRds(lock);
try {
if (CommonUtil.isNotEmpty(reqVO.getItems())) {
reqVO.getItems().forEach(item -> {
if (!orderScoreService.exists(id, item.getScoreId())) {
......@@ -550,6 +591,9 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
updateScore.setId(id);
updateScore.setHasScore(Boolean.TRUE);
customerOrderMapper.updateById(updateScore);
} finally {
RedisUtils.unLockRds(lock);
}
}
@Override
......@@ -561,6 +605,11 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
for (CustomerOrderStatus em : CustomerOrderStatus.values()) {
result.put(em.getKey(), statusMap.getOrDefault(em.getKey(), 0L));
}
// TODO 待评价
result.put("TO_BE_SCORE", customerOrderMapper.selectCount(Wrappers.<CustomerOrderDO>lambdaQuery()
.eq(CustomerOrderDO::getHasScore, Boolean.FALSE)
.in(CustomerOrderDO::getOrderStatus, CommonUtil.asList(CustomerOrderStatus.SIGN_RECEIPT.getLabel(),
CustomerOrderStatus.FINISH.getLabel()))));
return result;
}
......
......@@ -23,8 +23,8 @@ public class AuthLoginReqVO extends CaptchaVerificationReqVO {
@Schema(description = "账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "foodnexusyuanma")
@NotEmpty(message = "登录账号不能为空")
@Length(min = 4, max = 16, message = "账号长度为 4-16 位")
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
/*@Length(min = 4, max = 16, message = "账号长度为 4-16 位")
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")*/
private String username;
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "buzhidao")
......
......@@ -7,6 +7,7 @@ import cn.iocoder.foodnexus.framework.common.enums.UserTypeEnum;
import cn.iocoder.foodnexus.framework.common.pojo.CommonResult;
import cn.iocoder.foodnexus.framework.security.config.SecurityProperties;
import cn.iocoder.foodnexus.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.foodnexus.module.erp.api.service.ErpCustomerApi;
import cn.iocoder.foodnexus.module.system.controller.admin.auth.vo.*;
import cn.iocoder.foodnexus.module.system.convert.auth.AuthConvert;
import cn.iocoder.foodnexus.module.system.dal.dataobject.permission.MenuDO;
......@@ -28,6 +29,7 @@ import jakarta.annotation.security.PermitAll;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
......
......@@ -7,6 +7,7 @@ import org.springframework.stereotype.Component;
import java.time.Duration;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ThreadLocalRandom;
/**
......@@ -35,9 +36,13 @@ public class GenCodeUtils {
private String getCode(String type, String monthDay, Long increment) {
if (increment < MAX) {
return String.format("%s%s0%s", type, monthDay, String.valueOf(increment + MAX).substring(1));
return String.format("%s%s%s0%s", type, monthDay, random(), String.valueOf(increment + MAX).substring(1));
}
return String.format("%s%s%s", type, monthDay, increment);
return String.format("%s%s%s%s", type, monthDay, random(), increment);
}
private int random() {
return ThreadLocalRandom.current().nextInt(100, 1000);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment