Commit 6c7cc056 authored by zhengyi's avatar zhengyi

Merge branch 'release' into dev

parents 8368c6f4 503e4c12
-- 更新订单添加预装但未提交审核的出货状态值
update ecw_order o set o.shipment_state = 304 WHERE o.`status` = 5 AND o.shipment_state = 0 AND (select COUNT(1) from ecw_box_preload_goods pg WHERE pg.order_id = o.order_id AND pg.deleted = 0) > 0;
......@@ -158,7 +158,7 @@ public class PhoneUtil {
}
// 字典中获取验证规则
String rule = null;
String rule = "";
try {
List<DictDataRespDTO> dtos = DictFrameworkUtils.listDictDatasFromCache("phone_number_rule");
if (CollUtil.isNotEmpty(dtos)) {
......@@ -178,6 +178,8 @@ public class PhoneUtil {
}
if (StrUtil.isNotBlank(rule)) {
// 这里的正则前面包含了区号做唯一识别,需要先替换掉
rule = rule.replaceFirst(code, "");
log.info(String.format("获取手机号规则成功, code: %s, mobile: %s, rule: %s", code, mobile, rule));
return mobile.matches(rule);
}
......
......@@ -122,7 +122,7 @@ public interface CustomerComplaintMapper extends BaseMapperX<CustomerComplaintDO
"</script>"
})
List<CustomerComplaintExcelVO> selectList(@Param("query") CustomerComplaintExportReqVO query);
List<CustomerComplaintExcelVO> selectExcelList(@Param("query") CustomerComplaintExportReqVO query);
}
......@@ -25,13 +25,13 @@ import java.util.List;
public interface CustomerMapper extends BaseMapperX<CustomerDO> {
//合并操作日志
void doMergeCustomerOperateLog(long customer_id1,long customer_id2);
void doMergeCustomerOperateLog(@Param("customer_id1") Long customer_id1, @Param("customer_id2") Long customer_id2);
//合并客户信用日志
void doMergeCustomerCreditLog(long customer_id1,long customer_id2);
void doMergeCustomerCreditLog(@Param("customer_id1") Long customer_id1, @Param("customer_id2") Long customer_id2);
//合并客户登记日志
void doMergeCustomerLevelLog(long customer_id1,long customer_id2);
void doMergeCustomerLevelLog(@Param("customer_id1") Long customer_id1, @Param("customer_id2") Long customer_id2);
IPage<CustomerDO> getPage(IPage<CustomerDO> page,
@Param(Constants.WRAPPER) Wrapper<CustomerDO> queryWrapper);
......
......@@ -131,7 +131,7 @@ public class CustomerComplaintServiceImpl extends AbstractService<CustomerCompla
@Override
public List<CustomerComplaintExcelVO> getCustomerComplaintList(CustomerComplaintExportReqVO exportReqVO) {
return customerComplaintMapper.selectList(exportReqVO);
return customerComplaintMapper.selectExcelList(exportReqVO);
}
}
......@@ -215,4 +215,19 @@ public class CustomerRespVO extends CustomerBaseVO {
*/
@ApiModelProperty(value = "客户角色(逗号分隔的) customer_role 字典")
private String roles;
/**
* 客户类别
* <p>
* 枚举 {@link TODO customer_type 字典}
*/
@ApiModelProperty(value = "客户类型(逗号分隔的) customer_type 字典")
private String type;
/**
* 产品类型 即主营类别
*/
@ApiModelProperty(value = "主营类别")
private Long productType;
}
......@@ -29,6 +29,10 @@
<artifactId>yudao-module-sale-core</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-order-api</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</project>
......@@ -15,7 +15,7 @@ Content-Type: application/json
### 合并客户
GET {{baseUrl}}/ecw/customer/mergeCus?customerIdSaved=52009&customerIdDeleted=51966
GET {{baseUrl}}/ecw/customer/mergeCus?customerIdSaved=52043&customerIdDeleted=52042
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
Content-Type: application/json
......
package cn.iocoder.yudao.module.customer.controller.admin.customer;
import cn.iocoder.yudao.module.customer.dal.dataobject.customer.CustomerDO;
public interface CustomerMergeService {
boolean doMergeCus(CustomerDO customerDOSaved,
CustomerDO customerDODeleted,
long loginUserId);
}
......@@ -188,6 +188,8 @@ public interface ErrorCodeConstants {
ErrorCode CUSTOMER_APPROVAL_IN_PROCESSING = new ErrorCode(1004006043, "customer.approval.in.processing");
ErrorCode AREA_CODE_NOT_NULL = new ErrorCode(1004006044, "area.code.not.null");
ErrorCode CURRENCY_ID_NOT_NULL = new ErrorCode(1004006045, "currency.id.not.null");
}
......
......@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.ecw.controller.admin.region;
import cn.iocoder.yudao.framework.apollo.core.event.ChannelDataEvent;
import cn.iocoder.yudao.framework.apollo.core.event.QueryChannelInfoEvent;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
......@@ -26,6 +27,7 @@ import cn.iocoder.yudao.framework.excel.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
import static cn.iocoder.yudao.module.ecw.enums.ErrorCodeConstants.*;
import cn.iocoder.yudao.module.ecw.controller.admin.region.vo.*;
import cn.iocoder.yudao.module.ecw.dal.dataobject.region.RegionDO;
......@@ -217,4 +219,22 @@ public class RegionController {
List<RegionDO> cityList = regionService.getCityListByParentId(parentId);
return success(RegionConvert.INSTANCE.convertList(cityList));
}
@GetMapping("/check/dest-currency/area-code/")
@ApiOperation("检查国家区域是否与手机号国家区号一致")
@ApiImplicitParams({
@ApiImplicitParam(name = "currencyId", value = "国家ID", required = true, example = "1024", dataTypeClass = Long.class),
@ApiImplicitParam(name = "areaCode", value = "手机国家区号", required = true, example = "86", dataTypeClass = String.class)
})
public CommonResult<Boolean> checkDestCurrencyAndAreaCode(@RequestParam("currencyId") Long currencyId,
@RequestParam("areaCode") String areaCode) {
if (currencyId == null) {
return CommonResult.error(CURRENCY_ID_NOT_NULL);
}
if (StringUtils.isBlank(areaCode)) {
return CommonResult.error(AREA_CODE_NOT_NULL);
}
return success(regionService.countByIdAndAreaCode(currencyId, areaCode));
}
}
......@@ -10,7 +10,9 @@ import cn.iocoder.yudao.module.ecw.dal.dataobject.region.RegionDO;
import cn.iocoder.yudao.module.ecw.service.region.RegionService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.access.prepost.PreAuthorize;
......@@ -25,6 +27,8 @@ import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.module.ecw.enums.ErrorCodeConstants.AREA_CODE_NOT_NULL;
import static cn.iocoder.yudao.module.ecw.enums.ErrorCodeConstants.CURRENCY_ID_NOT_NULL;
@Api(tags = "app-web - 国家城市管理")
@RestController
......@@ -130,6 +134,24 @@ public class AppRegionController {
return success(RegionConvert.INSTANCE.convertList(cityList));
}
@GetMapping("/check/dest-currency/area-code/")
@ApiOperation("检查国家区域是否与手机号国家区号一致")
@ApiImplicitParams({
@ApiImplicitParam(name = "currencyId", value = "国家ID", required = true, example = "1024", dataTypeClass = Long.class),
@ApiImplicitParam(name = "areaCode", value = "手机国家区号", required = true, example = "86", dataTypeClass = String.class)
})
public CommonResult<Boolean> checkDestCurrencyAndAreaCode(@RequestParam("currencyId") Long currencyId,
@RequestParam("areaCode") String areaCode) {
if (currencyId == null) {
return CommonResult.error(CURRENCY_ID_NOT_NULL);
}
if (StringUtils.isBlank(areaCode)) {
return CommonResult.error(AREA_CODE_NOT_NULL);
}
return success(regionService.countByIdAndAreaCode(currencyId, areaCode));
}
private RegionRespVO buildChildTree(RegionRespVO pNode, List<RegionRespVO> allDatas){
List<RegionRespVO> childs = new ArrayList<>();
for(RegionRespVO itemNode : allDatas) {
......
......@@ -44,6 +44,14 @@ public interface RegionService {
*/
RegionDO getRegion(Long id);
/**
* 根据国家id和手机国家区号统计数值,判断区号是否与国家一致
* @param id
* @param areaCode
* @return
*/
Boolean countByIdAndAreaCode(Long id, String areaCode);
/**
* 获得区域设置列表
*
......
package cn.iocoder.yudao.module.ecw.service.region;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import java.util.*;
import cn.iocoder.yudao.module.ecw.controller.admin.region.vo.*;
import cn.iocoder.yudao.module.ecw.dal.dataobject.region.RegionDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
......@@ -31,12 +35,12 @@ public class RegionServiceImpl implements RegionService {
@Override
public Long createRegion(RegionCreateReqVO createReqVO) {
if (Objects.equals(createReqVO.getType(), "1") || Objects.equals(createReqVO.getType(), "3")){
if (StringUtils.isBlank(createReqVO.getLabelCode())){
if (Objects.equals(createReqVO.getType(), "1") || Objects.equals(createReqVO.getType(), "3")) {
if (StringUtils.isBlank(createReqVO.getLabelCode())) {
throw exception(REGION_LABEL_CODE_NOT_NULL);
}
String[] codes = createReqVO.getLabelCode().split(StrUtil.DASHED);
if (codes.length < 2){
if (codes.length < 2) {
throw exception(REGION_LABEL_CODE_COUNTRY_AND_CITY_AND_AIR_COUNTRY);
}
}
......@@ -49,12 +53,12 @@ public class RegionServiceImpl implements RegionService {
@Override
public void updateRegion(RegionUpdateReqVO updateReqVO) {
if (Objects.equals(updateReqVO.getType(), "1") || Objects.equals(updateReqVO.getType(), "3")){
if (StringUtils.isBlank(updateReqVO.getLabelCode())){
if (Objects.equals(updateReqVO.getType(), "1") || Objects.equals(updateReqVO.getType(), "3")) {
if (StringUtils.isBlank(updateReqVO.getLabelCode())) {
throw exception(REGION_LABEL_CODE_NOT_NULL);
}
String[] codes = updateReqVO.getLabelCode().split(StrUtil.DASHED);
if (codes.length < 2){
if (codes.length < 2) {
throw exception(REGION_LABEL_CODE_COUNTRY_AND_CITY_AND_AIR_COUNTRY);
}
}
......@@ -94,6 +98,13 @@ public class RegionServiceImpl implements RegionService {
return regionMapper.selectById(id);
}
@Override
public Boolean countByIdAndAreaCode(Long id, String areaCode) {
Long count = regionMapper.selectCount(new LambdaQueryWrapper<RegionDO>().eq(RegionDO::getId, id).eq(RegionDO::getAreaCode, areaCode));
return Objects.nonNull(count) && count > 0L;
}
@Override
public List<RegionDO> getRegionList(Collection<Long> ids) {
return regionMapper.selectBatchIds(ids);
......
......@@ -11,6 +11,7 @@ import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
......@@ -86,6 +87,7 @@ public class UserBackVO {
* 生日
*/
@ExcelProperty("生日")
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY)
@ApiModelProperty(value = "生日")
private Date birthday;
/**
......
......@@ -28,14 +28,19 @@ public enum OrderStatusMsgEnum {
adjust_applying(5, 10112, 212, 0, "调仓中", "order.status.adjust", "order.status.adjust"),
ADJUST_WAREHOUSE(5, 10113, 215, 0, "调仓已到仓", "order.status.adjust.arrived.warehouse", "order.status.adjust.arrived.warehouse"),
ADJUST_WAREHOUSE_PRE_INSTALLED(5, 10113, 215, 304, "调仓已到仓", "order.status.adjust.arrived.warehouse", "order.status.adjust.arrived.warehouse"),
EXIT_WAREHOUSE(5, 10114, 216, 0, "报关退场已入仓", "order.status.adjust.demobilized.warehoused", "order.status.warehousing"),
PREINSTALL_EXAMINE(5, 10115, 0, 305, "预装审核中", "order.status.pre.install.review", "order.status.pre.install.review"),
PRE_INSTALLED_PROGRESS(5, 10115, 202, 304, "已入仓", "order.status.warehousing", "order.status.warehousing"),
// PRE_INSTALLED_PROGRESS(5, 10115, 202, 304, "预装中", "order.status.pre.install", "order.status.pre.install"),
PREINSTALL_EXAMINE(5, 10116, 0, 305, "预装审核中", "order.status.pre.install.review", "order.status.pre.install.review"),
WAREHOUSE_ADJUSTMENT_PRE_INSTALLED(8, 10203, 214, 304, "调仓待入仓", "order.status.adjust.wait.in.warehouse", "order.status.adjust"),
WITHDRAWN(7, 0, 0, 0, "已退仓", "Withdrawn", "order.status.draft"),
adjust_wait_out(8, 10202, 213, 0, "调仓待出仓", "order.status.adjust.wait.out.warehouse", "order.status.adjust"),
WAREHOUSE_ADJUSTMENT(8, 10203, 214, 0, "调仓待入仓", "order.status.adjust.wait.in.warehouse", "order.status.adjust"),
MERGED_ORDER(9, 10204, 210, 0, "已合单", "order.status.closed", "order.status.closed"),
MERGED_ORDER_PRE_INSTALLED(9, 10204, 210, 304, "已合单", "order.status.closed", "order.status.closed"),
MERGED_ORDER_FINISH(9, 10205, 211, 0, "已合单归档", "order.status.closed", "order.status.closed"),
SPLIT_ORDER(10, 10206, 208, 0, "已拆单", "order.status.split.succeeded", "order.status.warehousing"),
......@@ -106,6 +111,7 @@ public enum OrderStatusMsgEnum {
AIR_TO_BE_PREPARED(502, 10105, 202, 0, "仓库待备货", "air.to.be.prepared", "air.to.be.prepared"),
AIR_IN_STOCK(503, 10105, 202, 0, "仓库备货中", "air.in.stock", "air.in.stock"),
AIR_READY_STOCK_AND_WAITING_TO_BE_ARRANGED(504, 10105, 202, 0, "待排单", "air.ready.stock.and.waiting.to.be.arranged", "air.ready.stock.and.waiting.to.be.arranged"),
AIR_READY_STOCK_AND_WAITING_TO_BE_ARRANGED_SORTING(504, 10105, 202, 304, "待排单", "air.ready.stock.and.waiting.to.be.arranged", "air.ready.stock.and.waiting.to.be.arranged"),
;
......
......@@ -390,7 +390,7 @@ public interface OrderBusinessService extends IService<OrderDO> {
* @param orderItemDOList 订单商品项列表
* @param type 类型 : 1 新增 2 修改 3 实测入仓信息 4 合单 5 拆单 6 处理未报价异常 7 特价申请 8 订单货值修改
* 9 处理重泡货异常 10 已入仓订单修改重订价 11 处理渠道异常 12 处理单询异常 13 处理超重异常 14 批量加价 15 完成入仓
* 16 分拣完成锁定价格 20 强制重订价格 30 空运订单每日定时更新价格 40 订单异常处理完成更新计价 50 更新订单优惠信息
* 16 分拣完成锁定价格 17 分拣反审解除锁定价格 18 出货入仓修改 20 强制重订价格 30 空运订单每日定时更新价格 40 订单异常处理完成更新计价 50 更新订单优惠信息
**/
void costCalculation(String userId, OrderDO orderDO, Long consignorCustomerId, Long consigneeCustomerId,
Long consignorCustomerContactsId, Long consigneeCustomerContactsId,
......
......@@ -70,6 +70,14 @@ public interface OrderService extends IService<OrderDO> {
*/
OrderDO orderInWarehouse(@Valid OrderWarehouseInVO orderWarehouseInVO);
/**
* 出货订单入仓
*
* @param orderWarehouseInVO 入仓信息
*/
OrderDO shipmentOrderInWarehouse(@Valid OrderWarehouseInVO orderWarehouseInVO);
/**
* 合单-创建合并订单
*
......
......@@ -615,6 +615,7 @@ public class OrderCargoControlServiceImpl extends AbstractService<OrderCargoCont
orderCargoControlApplyVO.setApplyStatus(0);
orderCargoControlApplyVO.setOrderType(releaseInfoDto.getType());
orderCargoControlApplyVO.setOrgIsOverseasWarehouse(StringUtils.isNotBlank(releaseInfoDto.getType()) && releaseInfoDto.getType().contains("2"));
orderCargoControlApplyVO.setNewIsOverseasWarehouse(!orderCargoControlApplyVO.getOrgIsOverseasWarehouse());
return orderCargoControlApplyVO;
} else {
OrderCargoControlApplyVO applyVO = JSONObject.parseObject(orderApprovalDO.getDetails(), OrderCargoControlApplyVO.class);
......@@ -707,6 +708,7 @@ public class OrderCargoControlServiceImpl extends AbstractService<OrderCargoCont
if ((StringUtils.isBlank(orderDO.getType()) || !orderDO.getType().contains("2")) && !orderCargoControlApplyVO.getNewIsOverseasWarehouse()) {
throw exception(ORDER_NOT_IS_OVERSEAS_WAREHOUSE_ORDER);
}
orderCargoControlApplyVO.setOrgIsOverseasWarehouse(StringUtils.isNotBlank(orderDO.getType()) && orderDO.getType().contains("2"));
orderApprovalDO.setOrderId(orderCargoControlApplyVO.getOrderId());
orderApprovalDO.setType(62);
orderApprovalDO.setDetails(JSONObject.toJSONString(orderCargoControlApplyVO));
......
......@@ -197,7 +197,13 @@ public class OrderExceptionServiceImpl extends AbstractService<OrderExceptionMap
Long resultId = null;
boolean mustToInsert = true;
List<String> exceptionUniqueKeyList = Arrays.asList(OrderExceptionEnum.ORDER_SUPERFLUOUS_BOX_EXCEPTION.getKey(), OrderExceptionEnum.ORDER_LACK_BOX_EXCEPTION.getKey(), OrderExceptionEnum.ORDER_PAY_EXCEPTION.getKey(), OrderExceptionEnum.ORDER_HEAVY_CARGO_EXCEPTION.getKey(), OrderExceptionEnum.ORDER_BULKY_CARGO_EXCEPTION.getKey(), OrderExceptionEnum.ORDER_DOC_EXCEPTION.getKey(), OrderExceptionEnum.ORDER_CONSIGNOR_EXCEPTION.getKey(), OrderExceptionEnum.NOT_CUSTOMER_SERVICE_EXCEPTION.getKey(), OrderExceptionEnum.GOODS_ADD_EXCEPTION.getKey(), OrderExceptionEnum.GOODS_OVERWEIGHT_EXCEPTION.getKey(), OrderExceptionEnum.LINE_WEIGHT_EXCEPTION.getKey(), OrderExceptionEnum.STOCK_UP_EXCEPTION.getKey(), OrderExceptionEnum.NOT_SHIPPING_CHANNEL_EXCEPTION.getKey());
List<String> exceptionUniqueKeyList = Arrays.asList(OrderExceptionEnum.ORDER_SUPERFLUOUS_BOX_EXCEPTION.getKey(),
OrderExceptionEnum.ORDER_LACK_BOX_EXCEPTION.getKey(), OrderExceptionEnum.ORDER_PAY_EXCEPTION.getKey(),
OrderExceptionEnum.ORDER_HEAVY_CARGO_EXCEPTION.getKey(), OrderExceptionEnum.ORDER_BULKY_CARGO_EXCEPTION.getKey(),
OrderExceptionEnum.ORDER_DOC_EXCEPTION.getKey(), OrderExceptionEnum.ORDER_CONSIGNOR_EXCEPTION.getKey(),
OrderExceptionEnum.NOT_CUSTOMER_SERVICE_EXCEPTION.getKey(), OrderExceptionEnum.GOODS_ADD_EXCEPTION.getKey(),
OrderExceptionEnum.GOODS_OVERWEIGHT_EXCEPTION.getKey(), OrderExceptionEnum.LINE_WEIGHT_EXCEPTION.getKey(),
OrderExceptionEnum.STOCK_UP_EXCEPTION.getKey(), OrderExceptionEnum.NOT_SHIPPING_CHANNEL_EXCEPTION.getKey());
if (exceptionUniqueKeyList.contains(createReqVO.getOrderExceptionType())) {
List<OrderExceptionDO> pnedingOrderExceptionList = this.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(createReqVO.getOrderId(), createReqVO.getOrderItemId(), createReqVO.getOrderExceptionType());
......@@ -1350,22 +1356,23 @@ public class OrderExceptionServiceImpl extends AbstractService<OrderExceptionMap
}
List<OrderChangePriceParam> channelPriceParams = new ArrayList<>();
if (null != vo.getChannelPriceList() && vo.getChannelPriceList().size() > 0) {
for (OrderExceptionChannelPriceCreateReqVO channelPrice : vo.getChannelPriceList()) {
channelPrice.setExceptionId(vo.getOrderExceptionId());
channelPrice.setExceptionResultId(orderExceptionResult.getId());
orderExceptionChannelPriceService.createExceptionChannelPrice(channelPrice);
OrderChangePriceParam priceParam = new OrderChangePriceParam();
BeanUtil.copyProperties(channelPrice, priceParam);
channelPriceParams.add(priceParam);
}
}
// List<OrderChangePriceParam> channelPriceParams = new ArrayList<>();
// if (null != vo.getChannelPriceList() && vo.getChannelPriceList().size() > 0) {
// for (OrderExceptionChannelPriceCreateReqVO channelPrice : vo.getChannelPriceList()) {
// channelPrice.setExceptionId(vo.getOrderExceptionId());
// channelPrice.setExceptionResultId(orderExceptionResult.getId());
// orderExceptionChannelPriceService.createExceptionChannelPrice(channelPrice);
//
// OrderChangePriceParam priceParam = new OrderChangePriceParam();
// BeanUtil.copyProperties(channelPrice, priceParam);
// channelPriceParams.add(priceParam);
// }
// }
this.updateById(orderExceptionDO);
//回调之前保存一下异常状态,防止删除
orderBusinessService.handleOrderChannelException(orderExceptionDO.getOrderId(), vo.getChannelId(), vo.getLineId(), channelPriceParams);
// orderBusinessService.handleOrderChannelException(orderExceptionDO.getOrderId(), vo.getChannelId(), vo.getLineId(), channelPriceParams);
orderBusinessService.handleOrderChannelException(orderExceptionDO.getOrderId(), vo.getChannelId(), vo.getLineId(), null);
} else {
throw exception(ORDER_HANDLER_EXCEPTION_NOT_EXISTS);
}
......
......@@ -6,7 +6,6 @@ import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.apollo.core.event.BoxCheckOrderSchedulingEvent;
import cn.iocoder.yudao.framework.apollo.core.event.Order.CalculateOrderVValueEvent;
import cn.iocoder.yudao.framework.apollo.core.event.QueryChannelInfoEvent;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
......@@ -1220,7 +1219,7 @@ public class OrderWarehouseInServiceImpl extends AbstractService<OrderWarehouseI
orderItemDOList,
isNotRollbackIn, orderWarehouseInDOList,
zhongPaoBest,
channelPackagingOverWeightAdditionalBoList);
channelPackagingOverWeightAdditionalBoList, false);
if (CollectionUtil.isNotEmpty(channelPackagingOverWeightAdditionalBoList)) {
channelPackagingOverWeightAdditionalBoList =
......@@ -1903,7 +1902,7 @@ public class OrderWarehouseInServiceImpl extends AbstractService<OrderWarehouseI
private void processOrderItemException(Long orderId, OrderDO orderDO, List<OrderItemDO> orderItemDOList,
boolean isNotRollbackIn, List<OrderWarehouseInDO> orderWarehouseInDOList, ZhongPaoBestVO zhongPaoBest,
List<ChannelPackagingOverWeightAdditionalBo> channelPackagingOverWeightAdditionalBoList) {
List<ChannelPackagingOverWeightAdditionalBo> channelPackagingOverWeightAdditionalBoList, boolean isFinishStocked) {
// 处理异常
for (OrderItemDO orderItemDO : orderItemDOList) {
......@@ -1934,8 +1933,10 @@ public class OrderWarehouseInServiceImpl extends AbstractService<OrderWarehouseI
// orderItem 设置warehouseInInfoVo
WarehouseInInfoVO warehouseInInfoVO = this.orderItemSetWarehouseInInfoVO(orderItemDO, orderWarehouseInDOListFilter);
// 处理空运订单 商品重量超限异常 和 商品路线重量超限异常
// 处理空运订单 商品重量超限异常 和 商品路线重量超限异常 (完成入仓时才需要,备货完成时不需要处理)
if (!isFinishStocked) {
this.processAirOrderOverWeightException(orderId, orderDO, orderItemDO, warehouseInInfoVO, channelPackagingOverWeightAdditionalBoList);
}
this.setOrderItemZhongPao(zhongPaoBest, orderItemDO, warehouseInInfoVO.getWeight(), warehouseInInfoVO.getVolume());
......@@ -2061,6 +2062,7 @@ public class OrderWarehouseInServiceImpl extends AbstractService<OrderWarehouseI
// 自动处理清关费未报价异常
orderExceptionService.autoProcessException(orderId, orderItemId, OrderExceptionEnum.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION, "因处理商品路线重量超限异常,自动取消。", OrderExceptionResult.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION_RESULT.PROCESSED);
orderExceptionService.autoProcessException(orderId, orderItemId, OrderExceptionEnum.ORDER_NO_QUOTE_EXCEPTION, "因处理商品路线重量超限异常,自动取消。", OrderExceptionResult.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION_RESULT.PROCESSED);
}
}
}
......@@ -4726,7 +4728,7 @@ public class OrderWarehouseInServiceImpl extends AbstractService<OrderWarehouseI
ZhongPaoBestVO zhongPaoBest = getZhongPaoBest(orderDO);
// 根据订单项产生异常,多箱,少箱,新增商品异常,入仓特性不符异常
processOrderItemException(orderId, orderDO, orderItemDOList, isNotRollbackIn, orderWarehouseInDOList, zhongPaoBest, channelPackagingOverWeightAdditionalBoList);
processOrderItemException(orderId, orderDO, orderItemDOList, isNotRollbackIn, orderWarehouseInDOList, zhongPaoBest, channelPackagingOverWeightAdditionalBoList, true);
if (CollectionUtil.isNotEmpty(channelPackagingOverWeightAdditionalBoList)) {
channelPackagingOverWeightAdditionalBoList = channelPackagingOverWeightAdditionalBoList.stream().filter(t -> !t.isMerged()).collect(Collectors.toList());
......
......@@ -537,6 +537,12 @@ public class OrderBackPageVO {
@ApiModelProperty(value = "业绩归属客户名称")
private String customerName;
@ApiModelProperty(value = "业绩归属客户的客户经理ID")
private Long customerService;
@ApiModelProperty(value = "业绩归属客户的客户经理名称")
private String customerServiceName;
// -----------end -----------
......
......@@ -386,6 +386,9 @@ public class OrderBaseVO {
@ApiModelProperty(value = "放货箱数")
private Integer releaseNum;
@ApiModelProperty(value = "是否有收货人,1-是,0-否")
private Boolean hasConsignee = true;
public void setExceptionReason(String exceptionReason) {
this.exceptionReason = StringUtils.isNotBlank(exceptionReason) ? I18nMessage.getMessage(exceptionReason) : exceptionReason;
}
......
......@@ -1675,6 +1675,8 @@
o.is_exception,
o.create_time,
o.load_time,
o.unload_time,
o.customer_id,
(select su.nickname from system_user su where su.deleted = 0 and su.id = o.salesman_id) as salesman_name,
(select min(wi.`in_time`) from ecw_order_warehouse_in wi where wi.deleted = 0 and wi.order_id = o.order_id ) as
in_time,
......@@ -1699,8 +1701,13 @@
nee.country_code as consignee_country_code,
if(#{query.lang} = 0, channel.name_zh, channel.name_en) as channel_name,
o.update_time,
c.name as customer_name,
c.customer_service,
su.nickname as customer_service_name,
#{query.lang} as lang
from ecw_order o
left join ecw_customer c on o.customer_id = c.id
left join system_user su on su.id = c.customer_service
left join (
SELECT
ewl.id AS line_id,
......
......@@ -74,7 +74,7 @@ tenant-id: {{adminTenentId}}
### 查询前20条
GET {{baseUrl}}/ecw/order/customer-order-page?customerDetailId=5008
GET {{baseUrl}}/ecw/order/customer-order-page?customerDetailId=51969
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
......
......@@ -2663,7 +2663,7 @@ public class ProductPriceServiceImpl extends AbstractService<ProductPriceMapper,
if (yfPriceUnit.equals(addYfPriceUnit) && yfVolumeUnit.equals(addYfVolumeUnit)) {
update = true;
yf = yf.add(addYf);
dbItem.setTransportPrice(yf);
dbItem.setTransportPrice(yf.compareTo(BigDecimal.ZERO) < 0? BigDecimal.ZERO: yf);
}
}
......@@ -2678,7 +2678,7 @@ public class ProductPriceServiceImpl extends AbstractService<ProductPriceMapper,
if (qgfPriceUnit.equals(addQgfPriceUnit) && qgfVolumeUnit.equals(addQgfVolumeUnit)) {
update = true;
qgf = qgf.add(addQgf);
dbItem.setClearancePrice(qgf);
dbItem.setClearancePrice(qgf.compareTo(BigDecimal.ZERO) < 0? BigDecimal.ZERO: qgf);
}
}
}
......@@ -2694,7 +2694,7 @@ public class ProductPriceServiceImpl extends AbstractService<ProductPriceMapper,
if (qbjPriceUnit.equals(addQbjPriceUnit) && qbjVolumeUnit.equals(addQbjVolumeUnit)) {
update = true;
qbj = qbj.add(addQbj);
dbItem.setAllPrice(qbj);
dbItem.setAllPrice(qbj.compareTo(BigDecimal.ZERO) < 0? BigDecimal.ZERO: qbj);
}
}
}
......@@ -2710,7 +2710,7 @@ public class ProductPriceServiceImpl extends AbstractService<ProductPriceMapper,
if (qgfPriceUnit.equals(addQgfPriceUnit) && qgfVolumeUnit.equals(addQgfVolumeUnit)) {
update = true;
qgf = qgf.add(addQgf);
dbItem.setClearancePrice(qgf);
dbItem.setClearancePrice(qgf.compareTo(BigDecimal.ZERO) < 0? BigDecimal.ZERO: qgf);
}
}
}
......
......@@ -91,7 +91,7 @@ public class RewardController {
rewardBackVOPageResult.getList().forEach(rewardBackVO -> {
List<Integer> nodeId = new ArrayList<>();
nodeId.add(rewardBackVO.getNodeId());
rewardBackVO.getNodeIds().add(new RewardBackVO.NodeAndPoints(nodeId, rewardBackVO.getPointsRequire(), rewardBackVO.getQuantityRemain()));
rewardBackVO.getNodeIds().add(new RewardBackVO.NodeAndPoints(nodeId, rewardBackVO.getQuantityRemain(), rewardBackVO.getPointsRequire()));
});
return success(rewardBackVOPageResult);
}
......
......@@ -121,9 +121,7 @@ public interface OfferMapper extends BaseMapperX<OfferDO> {
"from ecw_offer o ",
"left join ecw_customer_contacts cc on (o.relation = 1 and cc.id = o.consignor_id) or (o.relation = 2 and cc.id = o.consignee_id) ",
"<when test = 'pageVO.sourceIds != null and pageVO.sourceIds.size() > 0'>",
"left join ecw_customer user on user.id = o.relation_id ",
"</when>",
"left join system_user u on u.id = o.follow_up_salesman_id ",
"left join ecw_region s on o.objective_id = s.id ",
"left join ecw_warehouse_line line on o.line_id = line.id ",
......
......@@ -34,6 +34,7 @@ import cn.iocoder.yudao.module.shipment.vo.boxPreloadSection.BoxLoadSectionBackV
import cn.iocoder.yudao.module.shipment.vo.boxTally.BoxOrderLocationUpdateReq;
import cn.iocoder.yudao.module.shipment.vo.boxTally.BoxTallyBackVO;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import org.springframework.context.annotation.Description;
import javax.validation.Valid;
import java.math.BigDecimal;
......@@ -161,6 +162,8 @@ public interface BoxService extends IService<BoxDO> {
* @param auditType 审核类型
* @param auditResult 审核结果
*/
@Deprecated
@Description(value = "当前方法已废弃")
void updateOrderStatusByShipmentId(Long shipmentId, Integer orderStatus, Integer inWarehouseState, Integer shipmentState, Integer auditType, String auditResult);
void updateOrderStatusByShipmentIdAndTransportType(Long shipmentId, Integer orderStatus, Integer inWarehouseState, Integer shipmentState, Integer auditType, String auditResult, Integer transportType);
......@@ -171,6 +174,8 @@ public interface BoxService extends IService<BoxDO> {
void updateOrderStatusByOrderIdAndTransportType(Collection<Long> orderIdList, Integer orderStatus, Integer inWarehouseState, Integer shipmentState, Integer auditType, String auditResult, Date businessTime, Date estTime, Integer transportType);
@Deprecated
@Description(value = "当前方法已废弃")
void updateOrderStatusByShipmentId(Long shipmentId, Integer orderStatus, Integer inWarehouseState, Integer shipmentState, Integer auditType, String auditResult, Date date);
void updateOrderStatus(Long orderId, Integer orderStatus, Integer inWarehouseState, Integer shipmentState, Integer auditType, String auditResult, Boolean is, Integer hasExit);
......@@ -752,7 +757,7 @@ public interface BoxService extends IService<BoxDO> {
*
* @param orderIdList 订单列表
*/
void checkOrderPayStatus(Collection<Long> orderIdList);
void checkOrderPayStatus(BoxOrderMarkUpVO vo);
void updateUlBoxTime(Long shipmentId, Date ulBoxTime);
......
......@@ -1865,11 +1865,14 @@ public class BoxServiceImpl extends AbstractService<BoxMapper, BoxDO> implements
for (Long orderId : orderIdList) {
orderService.updateStatus(orderId, null, orderStatus, null, inWarehouseState, shipmentState, auditType, auditResult, businessTime, "出货操作", null);
}
if (transportType == 3) {
if (Objects.nonNull(shipmentState)) {
if (transportType == 1) {
this.shipmentSeaOrderTimeLog(orderIdList, null, businessTime, shipmentState);
} else if (transportType == 3) {
if (shipmentState == BoxStatusEnum.CLEARANCE_WAIT_UNLOAD.getStatus()) {
// 空运清关
addOrderAirTimeLog(orderIdList, OrderAirTimeEnum.AIR_CLEARED, null, null, null, businessTime, null);
} else if (shipmentState == BoxStatusEnum.ARRIVAL_WAIT_DISCHARGE.getStatus()) {
} else if (shipmentState == BoxStatusEnum.ARRIVAL_WAIT_DISCHARGE.getStatus() || shipmentState == BoxStatusEnum.DISCHARGE_WAIT_CLEARANCE.getStatus()) {
// 空运到港
addOrderAirTimeLog(orderIdList, OrderAirTimeEnum.AIR_ARRIVED, null, null, null, businessTime, null);
} else {
......@@ -1877,6 +1880,7 @@ public class BoxServiceImpl extends AbstractService<BoxMapper, BoxDO> implements
}
}
}
}
/**
......@@ -1902,6 +1906,7 @@ public class BoxServiceImpl extends AbstractService<BoxMapper, BoxDO> implements
for (Long orderId : orderIdList) {
orderService.updateStatus(orderId, null, orderStatus, null, inWarehouseState, shipmentState, auditType, auditResult, businessTime, "出货操作", null);
}
if (Objects.nonNull(shipmentState)) {
if (transportType == 1) {
this.shipmentSeaOrderTimeLog(orderIdList, estTime, businessTime, shipmentState);
} else if (transportType == 3) {
......@@ -1916,6 +1921,7 @@ public class BoxServiceImpl extends AbstractService<BoxMapper, BoxDO> implements
}
}
}
}
/**
* 更新出货单下的订单状态
......@@ -3090,7 +3096,8 @@ public class BoxServiceImpl extends AbstractService<BoxMapper, BoxDO> implements
if (boxDO.getTransportType().equals(TransportTypeEnum.AIR.getType())) {
checkOrderTagNum(shipmentId, 0);
//空运,修改订单状态
updateOrderStatusByShipmentId(shipmentId, OrderStatusEnum.SHIPMENT.getValue(), null, BoxAirStatusEnum.TALLY_COMPLETE.getStatus(), null, null);
updateOrderStatusByShipmentIdAndTransportType(shipmentId, OrderStatusEnum.SHIPMENT.getValue(), null,
BoxAirStatusEnum.TALLY_COMPLETE.getStatus(), null, null, Integer.parseInt(boxDO.getTransportType()));
}
}
......@@ -5041,7 +5048,8 @@ public class BoxServiceImpl extends AbstractService<BoxMapper, BoxDO> implements
@Override
public void checkOrderPayStatus(Collection<Long> orderIds) {
public void checkOrderPayStatus(BoxOrderMarkUpVO vo) {
Collection<Long> orderIds = vo.getOrderIds();
if (CollectionUtil.isEmpty(orderIds)) return;
List<ReceivableDO> receivableList =
receivableService.getOrderPayList(orderIds);
......@@ -5049,13 +5057,18 @@ public class BoxServiceImpl extends AbstractService<BoxMapper, BoxDO> implements
orderQueryService.getOrderList(orderIds);
Map<Long, OrderDO> orderMap = orderList.stream()
.collect(Collectors.toMap(OrderDO::getOrderId, v -> v));
Boolean freightMarkUp = Objects.nonNull(vo.getFreightFee()) && vo.getFreightFee().compareTo(BigDecimal.ZERO) > 0;
Boolean clearanceMarkUp = Objects.nonNull(vo.getClearanceFee()) && vo.getClearanceFee().compareTo(BigDecimal.ZERO) > 0;
List<String> payOrderNoList = new ArrayList<>();
List<ReceivableDO> newReceivableList = new ArrayList<>();
if (CollectionUtil.isNotEmpty(receivableList)) {
Map<Long, List<ReceivableDO>> receivableMap = receivableList.stream()
newReceivableList = receivableList.stream().filter(r -> r.getFeeSource() == 1
&& ((freightMarkUp && r.getFeeType() == 1) || (clearanceMarkUp && r.getFeeType() == 2))).collect(Collectors.toList());
}
if (CollectionUtil.isNotEmpty(newReceivableList)) {
// 只判断订单自动计算的运费与清关费应收单, 且运费加价,只判断运费应收单,清关费加价,只判断清关费应收单
Map<Long, List<ReceivableDO>> receivableMap = newReceivableList.stream()
.collect(Collectors.groupingBy(ReceivableDO::getOrderId));
for (Map.Entry<Long,
List<ReceivableDO>> entry : receivableMap.entrySet()) {
......
......@@ -355,7 +355,6 @@ public class BoxPreloadGoodsServiceImpl extends AbstractService<BoxPreloadGoodsM
}
preloadGoodsDOList.add(boxPreloadGoods);
}
// 插入
boxPreloadGoodsMapper.insertBatch(preloadGoodsDOList);
......@@ -363,6 +362,10 @@ public class BoxPreloadGoodsServiceImpl extends AbstractService<BoxPreloadGoodsM
//修改为预装中
boxDO.setPrStatus(PrStatusEnum.PRELOAD_ING.getPrStatus());
boxService.updateById(boxDO);
for (Long oId : orderIdList) {
boxService.updateOrderStatus(oId, null, null,
BoxStatusEnum.PREINSTALLING.getStatus(), null, null, Boolean.FALSE);
}
boxService.addOrderLog(orderIdList, OrderShipmentLog.PRELOAD_ADD, "");
} else if (boxDO.getPrStatus() == PrStatusEnum.PRELOAD_APPROVAL_SUCCESS.getPrStatus()) {
//补单。修改订单状态
......@@ -370,12 +373,14 @@ public class BoxPreloadGoodsServiceImpl extends AbstractService<BoxPreloadGoodsM
boxService.updateOrderStatus(oId, OrderStatusEnum.PRE_INSTALLED.getValue(), 0,
BoxStatusEnum.PREINSTALL_EXAMINE_SUCCESS.getStatus(), null, null, Boolean.FALSE);
}
//生成提单号
boxService.generateBillLadingNo(shipmentId, false, false);
boxService.addOrderLog(orderIdList, OrderShipmentLog.CABINET_PATCH, "");
} else {
for (Long oId : orderIdList) {
boxService.updateOrderStatus(oId, null, null,
BoxStatusEnum.PREINSTALLING.getStatus(), null, null, Boolean.FALSE);
}
boxService.addOrderLog(orderIdList, OrderShipmentLog.PRELOAD_ADD, "");
}
......@@ -449,6 +454,8 @@ public class BoxPreloadGoodsServiceImpl extends AbstractService<BoxPreloadGoodsM
//修改为预装中
boxDO.setPrStatus(PrStatusEnum.PRELOAD_ING.getPrStatus());
boxService.updateById(boxDO);
boxService.updateOrderStatus(orderId, null, null,
BoxStatusEnum.PREINSTALLING.getStatus(), null, null, Boolean.FALSE);
boxService.addOrderLog(Collections.singletonList(orderId), OrderShipmentLog.PRELOAD_ADD, "");
} else if (boxDO.getPrStatus() == PrStatusEnum.PRELOAD_APPROVAL_SUCCESS.getPrStatus()) {
//补单。修改订单状态
......@@ -2410,6 +2417,10 @@ public class BoxPreloadGoodsServiceImpl extends AbstractService<BoxPreloadGoodsM
//修改为分拣中
boxDO.setPrStatus(StStatusEnum.SORTING.getStStatus());
boxService.updateById(boxDO);
for (Long oId : orderIdList) {
boxService.updateOrderStatus(oId, null, null,
BoxStatusEnum.PREINSTALLING.getStatus(), null, null, Boolean.FALSE);
}
boxService.addOrderLog(orderIdList, OrderShipmentLog.SORTING_ADD, "");
} else if (boxDO.getPrStatus() == StStatusEnum.SORTING_APPROVAL_SUCCESS.getStStatus()) {
//补单。修改订单状态
......@@ -2429,6 +2440,10 @@ public class BoxPreloadGoodsServiceImpl extends AbstractService<BoxPreloadGoodsM
boxService.addOrderLog(orderIdList, OrderShipmentLog.MERGE_PATCH, "");
} else {
for (Long oId : orderIdList) {
boxService.updateOrderStatus(oId, null, null,
BoxStatusEnum.PREINSTALLING.getStatus(), null, null, Boolean.FALSE);
}
boxService.addOrderLog(orderIdList, OrderShipmentLog.SORTING_ADD, "");
}
......
......@@ -85,8 +85,8 @@ public class BoxTrailerServiceImpl extends AbstractService<BoxTrailerMapper, Box
//如果是已经派车,则不用再次更新订单状态
if(tlStatus != TlStatueEnum.HAS_SEND_CAR.getTlStatus()) {
boxService.updateOrderStatusByShipmentId(shipmentId, null, null,
boxDO.getShipmentStatus(), null, null);
boxService.updateOrderStatusByShipmentIdAndTransportType(shipmentId, null, null,
boxDO.getShipmentStatus(), null, null, Integer.parseInt(boxDO.getTransportType()));
}
}
boxService.updateById(boxDO);
......
......@@ -301,3 +301,7 @@ customer.approval.in.processing=
order.overseas.warehouse.update.is.or.no=
order.is.overseas.warehouse.order=
order.not.is.overseas.warehouse.order=
area.code.not.null=
currency.id.not.null=
\ No newline at end of file
......@@ -353,6 +353,7 @@ order.status.adjust.wait.out.warehouse=Transfer warehouse to be out of warehouse
order.status.adjust.wait.in.warehouse=Transferred warehouse to be warehoused
order.status.adjust.arrived.warehouse=Warehouse transfer has arrived
order.status.adjust.demobilized.warehoused=Demobilized and warehoused
order.status.pre.install=Pre installed
order.status.pre.install.review=Pre installation under review
order.status.preinstalled=Preinstalled
order.status.dispatched.car.wait.pick.counter=The car has been dispatched, waiting to pick up the counter
......@@ -1108,3 +1109,7 @@ customer.approval.in.processing=Non-main customer approval is in progress and ca
order.overseas.warehouse.update.is.or.no=Please select order overseas warehouse modification Yes or No
order.is.overseas.warehouse.order=This order is already an overseas warehouse order
order.not.is.overseas.warehouse.order=This order is already a non overseas warehouse order
area.code.not.null=The national mobile phone area code cannot be empty
currency.id.not.null=The country ID cannot be empty
\ No newline at end of file
......@@ -354,6 +354,7 @@ order.status.adjust.wait.out.warehouse=\u8C03\u4ED3\u5F85\u51FA\u4ED3
order.status.adjust.wait.in.warehouse=\u8C03\u4ED3\u5F85\u5165\u4ED3
order.status.adjust.arrived.warehouse=\u8C03\u4ED3\u5DF2\u5230\u4ED3
order.status.adjust.demobilized.warehoused=\u9000\u573A\u5DF2\u5165\u4ED3
order.status.pre.install=\u9884\u88C5\u4E2D
order.status.pre.install.review=\u9884\u88C5\u5BA1\u6838\u4E2D
order.status.preinstalled=\u5DF2\u9884\u88C5
order.status.dispatched.car.wait.pick.counter=\u5DF2\u6D3E\u8F66\uFF0C\u5F85\u63D0\u67DC
......@@ -1108,3 +1109,7 @@ customer.approval.in.processing=\u975E\u4E3B\u5BA2\u6237\u5BA1\u6279\u6B63\u5728
order.overseas.warehouse.update.is.or.no=\u8bf7\u9009\u62e9\u8ba2\u5355\u6d77\u5916\u4ed3\u4fee\u6539\u662f\u6216\u5426
order.is.overseas.warehouse.order=\u8be5\u8ba2\u5355\u5df2\u7ecf\u662f\u6d77\u5916\u4ed3\u8ba2\u5355
order.not.is.overseas.warehouse.order=\u8be5\u8ba2\u5355\u5df2\u7ecf\u662f\u975e\u6d77\u5916\u4ed3\u8ba2\u5355
area.code.not.null=\u56fd\u5bb6\u624b\u673a\u533a\u53f7\u4e0d\u80fd\u4e3a\u7a7a
currency.id.not.null=\u56fd\u5bb6id\u4e0d\u80fd\u4e3a\u7a7a
\ No newline at end of file
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