From d7daf871cac2fbed536a81d9afc60895c6562635 Mon Sep 17 00:00:00 2001 From: dengjun Date: Tue, 23 Jul 2024 15:36:01 +0800 Subject: [PATCH] =?UTF-8?q?BUG=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rtosc/dto/BatchCheckShipVo.java | 31 + .../rtosc/dto/BillNumValidVo.java | 28 + .../rtosc/dto/DepartureCargoVo.java | 54 +- .../rtosc/dto/DepartureValidVo.java | 47 + .../haitonggauto/rtosc/dto/DepartureVo.java | 22 +- .../rtosc/dto/ExportInAuditVo.java | 51 + .../rtosc/dto/ExportInBatchCheckVo.java | 44 + .../rtosc/dto/ExportInCargoVo.java | 1 - .../rtosc/dto/ExportInQueryVo.java | 30 + .../haitonggauto/rtosc/dto/ExportInVo.java | 9 +- .../rtosc/dto/ExportInspectCargoVo.java | 1 - .../rtosc/dto/ExportInspectVo.java | 8 +- .../rtosc/dto/ExportLoadCargoVo.java | 1 - .../rtosc/dto/ExportLoadCheckVo.java | 6 + .../rtosc/dto/InspectValidVo.java | 25 + .../rtosc/dto/UpdatePlanArrivePortVo.java | 33 + .../rtosc/dto/UpdatePreArrivalTimeVo.java | 44 + .../rtosc/dto/UpdateVoyageVo.java | 11 +- .../rtosc/dto/ValidVinActivateVo.java | 31 + .../rtosc/excel/DepartureImportExcel.java | 59 + .../rtosc/excel/ExportInBillSpareExcel.java | 10 +- .../rtosc/excel/ExportInCargoExportExcel.java | 18 +- .../rtosc/excel/ExportInExcel.java | 13 +- .../rtosc/excel/ExportInPlanExcel.java | 73 +- .../rtosc/excel/ExportInSpareExcel.java | 2 +- .../rtosc/excel/ExportLoadExcel.java | 11 +- .../rtosc/excel/ExportLoadExportExcel.java | 60 + .../rtosc/excel/ExportLoadInsideExcel.java | 31 +- .../rtosc/excel/ExportLoadSpareExcel.java | 10 +- .../rtosc/excel/ExportVinExcel.java | 5 +- .../rtosc/excel/FreeTradeExcel.java | 59 +- .../rtosc/excel/ImportUnloadExcel.java | 1 - .../rtosc/excel/InspectExcel.java | 58 + .../haitonggauto/rtosc/query/CargoQuery.java | 7 + .../rtosc/query/CargoVinQuery.java | 16 + .../rtosc/query/DepartureQuery.java | 16 + .../rtosc/query/ExportInBathCheckQuery.java | 28 + .../rtosc/query/ExportInCheckQuery.java | 21 +- .../rtosc/query/ExportInQuery.java | 14 +- .../rtosc/query/ExportInspectCheckQuery.java | 38 + .../rtosc/query/ExportInspectQuery.java | 35 + .../rtosc/query/ExportLoadCheckQuery.java | 7 + .../rtosc/query/ExportLoadQuery.java | 4 + .../rtosc/common/dto/LoginUser.java | 11 + .../rtosc/common/utils/WrapperKit.java | 18 +- .../common/validate/DependsOnValidator.java | 2 +- .../haitonggauto/rtosc/api/NuzarOpenApi.java | 24 + .../haitonggauto/rtosc/api/NuzarShpApi.java | 16 +- .../rtosc/api/dto/BatchConfirmReviewReq.java | 27 + .../rtosc/api/dto/CheckShipPlanReq.java | 16 + .../rtosc/api/dto/CheckVinReq.java | 3 + .../rtosc/api/dto/ImportInspectReq.java | 31 + .../rtosc/api/dto/ImportInspectResp.java | 55 + .../api/dto/ShipmentBerthsStatusRespDTO.java | 23 + .../rtosc/api/dto/TrendShipResp.java | 26 + .../rtosc/api/dto/UserInfoDto.java | 94 + .../rtosc/api/dto/VinCheckReq.java | 27 + .../rtosc/api/dto/VinCheckResp.java | 20 + .../rtosc/api/dto/VoyageResp.java | 3 + .../config/InterceptorConfiguration.java | 12 +- .../rtosc/config/PermInterceptor.java | 56 +- .../rtosc/handler/DepartureHandler.java | 381 +++- .../rtosc/handler/ExportInHandler.java | 1398 +++++++++++--- .../rtosc/handler/ExportInspectHandler.java | 443 ++++- .../rtosc/handler/ExportLoadHandler.java | 1635 +++++++++++++++-- .../rtosc/handler/FreeTradeHandler.java | 92 +- .../rtosc/handler/HeathCheckHandler.java | 14 + .../rtosc/handler/ImportInspectHandler.java | 393 +++- .../rtosc/handler/ImportUnloadHandler.java | 10 + .../rtosc/handler/excel/ExcelMergeUtil.java | 2 +- .../handler/excel/ReadExcelListener.java | 15 + .../rtosc/handler/mapper/PoMapper.java | 4 + .../rtosc/job/SyncToOldHandler.java | 7 - .../rtosc/service/CustomerService.java | 2 +- .../service/impl/CustomerServiceImpl.java | 27 +- .../src/main/resources/application-pre.yml | 4 +- .../src/main/resources/logback-spring.xml | 4 +- .../resources/templates/departure_temp.xlsx | Bin 0 -> 8766 bytes .../templates/export_inspect_temp.xlsx | Bin 0 -> 10336 bytes .../templates/import_inspect_temp.xlsx | Bin 0 -> 8109 bytes .../src/main/resources/templates/in_temp.xlsx | Bin 20109 -> 21154 bytes .../src/main/resources/templates/template.pdf | Bin 21985 -> 24103 bytes .../main/resources/templates/template.xlsx | Bin 15028 -> 14986 bytes .../com/haitonggauto/rtosc/BJNumTest.java | 78 +- .../repository/entity/CustomerDeparture.java | 34 +- .../entity/CustomerDepartureCargo.java | 88 +- .../repository/entity/CustomerExportIn.java | 12 + .../entity/CustomerExportInCargo.java | 37 + .../entity/CustomerExportInspect.java | 1 - .../repository/entity/CustomerFreeTrade.java | 37 + .../mapper/CustomerExportInMapper.java | 2 +- .../mapper/CustomerExportLoadMapper.java | 2 +- .../rtosc/repository/query/PrintQuery.java | 6 + .../service/CustomerExportInService.java | 2 +- .../service/CustomerExportLoadService.java | 2 +- .../impl/CustomerExportInServiceImpl.java | 4 +- .../impl/CustomerExportLoadServiceImpl.java | 4 +- .../mapper/CustomerDepartureCargoMapper.xml | 52 +- .../mapper/CustomerExportInCargoMapper.xml | 3 + .../mapper/CustomerExportInMapper.xml | 8 +- .../mapper/CustomerExportLoadMapper.xml | 9 +- 101 files changed, 5548 insertions(+), 801 deletions(-) create mode 100644 nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/BatchCheckShipVo.java create mode 100644 nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/BillNumValidVo.java create mode 100644 nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/DepartureValidVo.java create mode 100644 nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInAuditVo.java create mode 100644 nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInBatchCheckVo.java create mode 100644 nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInQueryVo.java create mode 100644 nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/InspectValidVo.java create mode 100644 nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/UpdatePlanArrivePortVo.java create mode 100644 nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/UpdatePreArrivalTimeVo.java create mode 100644 nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ValidVinActivateVo.java create mode 100644 nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/DepartureImportExcel.java create mode 100644 nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportLoadExportExcel.java create mode 100644 nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/InspectExcel.java create mode 100644 nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/CargoVinQuery.java create mode 100644 nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInBathCheckQuery.java create mode 100644 nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/BatchConfirmReviewReq.java create mode 100644 nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/CheckShipPlanReq.java create mode 100644 nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/ImportInspectReq.java create mode 100644 nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/ImportInspectResp.java create mode 100644 nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/ShipmentBerthsStatusRespDTO.java create mode 100644 nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/TrendShipResp.java create mode 100644 nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/UserInfoDto.java create mode 100644 nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/VinCheckReq.java create mode 100644 nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/VinCheckResp.java create mode 100644 nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/HeathCheckHandler.java create mode 100644 nuzar-customer-controller/src/main/resources/templates/departure_temp.xlsx create mode 100644 nuzar-customer-controller/src/main/resources/templates/export_inspect_temp.xlsx create mode 100644 nuzar-customer-controller/src/main/resources/templates/import_inspect_temp.xlsx diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/BatchCheckShipVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/BatchCheckShipVo.java new file mode 100644 index 0000000..7ab312d --- /dev/null +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/BatchCheckShipVo.java @@ -0,0 +1,31 @@ +package com.haitonggauto.rtosc.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; +import java.util.Date; + +@Data +@ApiModel(value = "多船批量审核") +public class BatchCheckShipVo implements Serializable { + + @ApiModelProperty(value = "船ID") + @NotBlank(message = "船ID不能为空") + private String shipId; + + @ApiModelProperty(value = "航次ID") + @NotBlank(message = "航次ID不能为空") + private String voyageId; + + @ApiModelProperty(value = "港区ID") + @NotBlank(message = "港区ID不能为空") + private String portAreaId; + + @ApiModelProperty(value = "预进港时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date preArrivalTime; +} diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/BillNumValidVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/BillNumValidVo.java new file mode 100644 index 0000000..1ae3522 --- /dev/null +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/BillNumValidVo.java @@ -0,0 +1,28 @@ +package com.haitonggauto.rtosc.dto; + +import com.haitonggauto.rtosc.common.utils.ValidationGroup; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Data +@ApiModel("提单号验证") +public class BillNumValidVo { + @ApiModelProperty(value = "船ID") + @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "船ID不能为空") + private String shipId; + + @ApiModelProperty(value = "航次ID") + @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "航次ID不能为空") + private String voyageId; + + @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "货代ID不能为空") + @ApiModelProperty(value = "货代ID", required = true) + private String freightId; + + @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "提单号不能为空") + @ApiModelProperty(value = "提单号", required = true) + private String billNum; +} diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/DepartureCargoVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/DepartureCargoVo.java index a7916d1..59fe6f0 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/DepartureCargoVo.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/DepartureCargoVo.java @@ -1,5 +1,6 @@ package com.haitonggauto.rtosc.dto; +import com.baomidou.mybatisplus.annotation.TableField; import com.haitonggauto.rtosc.common.utils.ValidationGroup; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -9,6 +10,7 @@ import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import java.io.Serializable; +import java.math.BigDecimal; @Data @ApiModel(value = "提离港区货物表",description = "") @@ -46,14 +48,13 @@ public class DepartureCargoVo implements Serializable { * 货物类型 */ // @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "车型不能为空") - @ApiModelProperty(value = "车型", required = true) - private String cargoType; +// @ApiModelProperty(value = "车型", required = true) +// private String cargoType; /** * 车架号/条码 */ @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "车架号/条码不能为空") - @Size(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, min = 17, max = 17, message = "车架号长度为17位") @ApiModelProperty(value = "车架号/条码", required = true) private String vin; @@ -71,6 +72,53 @@ public class DepartureCargoVo implements Serializable { @ApiModelProperty(value = "是否退关", required = true) private Integer isShutout; + /** + * 车型ID + */ + @ApiModelProperty(value = "车型ID") + private String cartTypeId; + + /** + * 车型 + */ + @ApiModelProperty(value = "车型") + private String cartType; + // 型号 + + @ApiModelProperty(value = "型号") + private String models; + /** + * 长 + */ + @ApiModelProperty(value = "长") + private BigDecimal length; + + /** + * 宽 + */ + @ApiModelProperty(value = "宽") + private BigDecimal width; + + /** + * 高 + */ + @ApiModelProperty(value = "高") + private BigDecimal height; + + /** + * 重量(吨) + */ + @TableField(value = "weight") + @ApiModelProperty(value = "重量") + private BigDecimal weight; + + // 是否报关 + @ApiModelProperty(value = "是否报关") + private Integer isCustoms; + + @ApiModelProperty(value = "是否随车备件") + private Integer isSpare; + @ApiModelProperty(value = "车辆状态") private String vinStatus; diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/DepartureValidVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/DepartureValidVo.java new file mode 100644 index 0000000..15398c1 --- /dev/null +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/DepartureValidVo.java @@ -0,0 +1,47 @@ +package com.haitonggauto.rtosc.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.List; + +@Data +@ApiModel("提离港区验证") +public class DepartureValidVo { + @ApiModelProperty(value = "船ID") + @NotBlank(message = "船ID不能为空") + private String shipId; + + @ApiModelProperty(value = "航次ID") + @NotBlank(message = "航次ID不能为空") + private String voyageId; + + @NotBlank(message = "港区ID不能为空") + @ApiModelProperty(value = "港区ID", required = true) + private String portAreaId; + + @ApiModelProperty(value = "品牌ID", required = true) + @NotBlank(message = "品牌ID不能为空") + private String brandId; + + @Valid + @NotNull(message = "车架号不能为空") + @Size(min = 1, message = "车架号不能为空") + private List vins; + + @Data + public static class BillVin { + @ApiModelProperty(value = "提单号", required = true) + @NotBlank(message = "提单号不能为空") + private String billNo; + + @ApiModelProperty(value = "车架号", required = true) + @NotBlank(message = "车架号不能为空") + private String vin; + } +} diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/DepartureVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/DepartureVo.java index 6a5ca8e..bb02140 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/DepartureVo.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/DepartureVo.java @@ -56,30 +56,44 @@ public class DepartureVo implements Serializable { * 航次ID */ @ApiModelProperty(value = "航次ID") - @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "航次ID不能为空") +// @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "航次ID不能为空") private String voyageId; /** * 航次 */ @ApiModelProperty(value = "航次", required = true) - @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "航次不能为空") +// @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "航次不能为空") private String voyage; /** * 港区ID */ @ApiModelProperty(value = "港区ID") - @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "港区ID不能为空") +// @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "港区ID不能为空") private String portAreaId; /** * 港区 */ @ApiModelProperty(value = "港区", required = true) - @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "港区不能为空") +// @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "港区不能为空") private String portArea; + /** + * 品牌ID + */ + @ApiModelProperty(value = "品牌ID") + @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "品牌ID不能为空") + private String brandId; + + /** + * 品牌 + */ + @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "品牌不能为空") + @ApiModelProperty(value = "品牌") + private String brand; + /** * 贸易类型 */ diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInAuditVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInAuditVo.java new file mode 100644 index 0000000..818730f --- /dev/null +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInAuditVo.java @@ -0,0 +1,51 @@ +package com.haitonggauto.rtosc.dto; + +import com.haitonggauto.rtosc.common.utils.ValidationGroup; +import com.haitonggauto.rtosc.repository.enums.AuditEnum; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.List; + +/** + * 出口进场基本表 + * + * @TableName customer_export_in + */ +@Data +@ApiModel(value = "进港审核", description = "") +public class ExportInAuditVo implements Serializable { + + @ApiModelProperty(value = "船ID") + @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "船ID不能为空") + private String shipId; + + /** + * 航次ID + */ + @ApiModelProperty(value = "航次ID") + @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "航次ID不能为空") + private String voyageId; + + /** + * 审核状态 + */ + @ApiModelProperty(value = "审核状态") + @NotNull(groups = {ValidationGroup.insert.class}, message = "审核状态不能为空") + private AuditEnum checkStatus; + + @ApiModelProperty(value = "提单号列表") + @NotNull(groups = {ValidationGroup.insert.class}, message = "提单号列表不能为空") + @Size(min = 1, message = "提单号列表不能为空") + private List billNums; + /** + * 审核原因 + */ + @ApiModelProperty(value = "审核原因") + private String checkResult; +} \ No newline at end of file diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInBatchCheckVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInBatchCheckVo.java new file mode 100644 index 0000000..1091234 --- /dev/null +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInBatchCheckVo.java @@ -0,0 +1,44 @@ +package com.haitonggauto.rtosc.dto; + +import com.haitonggauto.rtosc.common.utils.ValidationGroup; +import com.haitonggauto.rtosc.repository.enums.AuditEnum; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.List; + +/** + * 出口进场货物表 + * @TableName customer_export_in_cargo + */ +@Data +@ApiModel(value = "多船审核信息",description = "") +public class ExportInBatchCheckVo implements Serializable { + + @ApiModelProperty(value = "原始审核状态") + @NotNull(message = "原始审核状态不能为空") + private AuditEnum originalCheckStatus; + + @ApiModelProperty(value = "审核状态") + @NotNull(message = "审核状态不能为空") + private AuditEnum checkStatus; + + /** + * 审核原因 + */ + @ApiModelProperty(value = "审核原因") + private String checkResult; + + @ApiModelProperty(value = "审核类型, 0-全部,1-车辆,2-备件") + private String type; + + @Valid + @NotNull(message = "审核船名列表为空") + @Size(min = 1, message = "审核船名列表不能为空") + private List ships; +} \ No newline at end of file diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInCargoVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInCargoVo.java index 0408af6..88d8905 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInCargoVo.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInCargoVo.java @@ -32,7 +32,6 @@ public class ExportInCargoVo implements Serializable { * 车架号 */ @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "车架号不能为空") - @Size(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, min = 17, max = 17, message = "车架号长度为17位") @ApiModelProperty(value = "车架号", required = true) private String vin; diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInQueryVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInQueryVo.java new file mode 100644 index 0000000..9db249e --- /dev/null +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInQueryVo.java @@ -0,0 +1,30 @@ +package com.haitonggauto.rtosc.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.List; + +@Data +@ApiModel(value = "进港计划查询",description = "") +public class ExportInQueryVo implements Serializable { + + @ApiModelProperty(value = "船ID") + private String shipId; + + /** + * 受理号 + */ + @ApiModelProperty(value = "航次ID") + private String voyageId; + + @ApiModelProperty(value = "车架号列表") + @NotNull(message = "请传入车架号列表") + @Size(min = 1, message = "车架号列表不能为空") + private List billNums; + +} diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInVo.java index 39303f7..9e4bb97 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInVo.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInVo.java @@ -1,6 +1,5 @@ package com.haitonggauto.rtosc.dto; -import com.baomidou.mybatisplus.annotation.TableField; import com.fasterxml.jackson.annotation.JsonFormat; import com.haitonggauto.rtosc.common.utils.ValidationGroup; import com.haitonggauto.rtosc.common.validate.DependsOn; @@ -182,6 +181,14 @@ public class ExportInVo implements Serializable { @ApiModelProperty(value = "运输方式", required = true) private String transportWay; + @ApiModelProperty(value = "预进港时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date preArrivalTime; + + @ApiModelProperty(value = "预靠泊时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date planArrivePortTime; + @ApiModelProperty(value = "进场开始时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date beginEnterTime; diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInspectCargoVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInspectCargoVo.java index ae06434..e6ca4cc 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInspectCargoVo.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInspectCargoVo.java @@ -47,7 +47,6 @@ public class ExportInspectCargoVo implements Serializable { */ @ApiModelProperty(value = "车架号", required = true) @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "车架号/条码不能为空") - @Size(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, min = 17, max = 17, message = "车架号长度为17位") private String vin; /** diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInspectVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInspectVo.java index 015ab76..e6ba1b5 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInspectVo.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportInspectVo.java @@ -43,7 +43,7 @@ public class ExportInspectVo implements Serializable { * 航次 */ @ApiModelProperty(value = "航次", required = true) - @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "航次不能为空") +// @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "航次不能为空") private String voyage; /** @@ -85,7 +85,7 @@ public class ExportInspectVo implements Serializable { * 公司名 */ @ApiModelProperty(value = "公司名", required = true) - @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "公司名不能为空") +// @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "公司名不能为空") private String company; @ApiModelProperty(value = "申请对象ID") @@ -96,7 +96,7 @@ public class ExportInspectVo implements Serializable { * 申请对象(从基础数据库获取客户类型为进口货代的数据) */ @ApiModelProperty(value = "申请对象", required = true) - @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "审请对象不能为空") + @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "申请对象不能为空") private String applyObj; /** @@ -144,7 +144,7 @@ public class ExportInspectVo implements Serializable { * 航次ID */ @ApiModelProperty(value = "航次ID") - @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "航次ID不能为空") +// @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "航次ID不能为空") private String voyageId; @ApiModelProperty(value = "港区ID") diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportLoadCargoVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportLoadCargoVo.java index 8deaf1c..e88ec39 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportLoadCargoVo.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportLoadCargoVo.java @@ -39,7 +39,6 @@ public class ExportLoadCargoVo implements Serializable { * 车架号/条码 */ @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "车架号/条码不能为空") - @Size(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, min = 17, max = 17, message = "车架号长度为17位") @ApiModelProperty(value = "车架号/条码", required = true) private String vin; diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportLoadCheckVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportLoadCheckVo.java index 28e4b1e..ed1b9e0 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportLoadCheckVo.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ExportLoadCheckVo.java @@ -48,6 +48,12 @@ public class ExportLoadCheckVo implements Serializable { @NotNull(groups = {ValidationGroup.insert.class}, message = "审核状态不能为空") private AuditEnum checkStatus; + @ApiModelProperty("提单号") + private List billNos; + + @ApiModelProperty(value = "是否为备件") + private Boolean spare; + /** * 审核原因 */ diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/InspectValidVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/InspectValidVo.java new file mode 100644 index 0000000..6292b8e --- /dev/null +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/InspectValidVo.java @@ -0,0 +1,25 @@ +package com.haitonggauto.rtosc.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; +import java.util.List; + +@ApiModel("出口查验检验") +@Data +public class InspectValidVo implements Serializable { + + @ApiModelProperty("船ID") + @NotBlank(message = "船ID不能为空") + private String shipId; + + @ApiModelProperty("提单号") + @NotBlank(message = "提单号不能为空") + private String billNo; + + @ApiModelProperty("车架号") + private List vins; +} diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/UpdatePlanArrivePortVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/UpdatePlanArrivePortVo.java new file mode 100644 index 0000000..2767149 --- /dev/null +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/UpdatePlanArrivePortVo.java @@ -0,0 +1,33 @@ +package com.haitonggauto.rtosc.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Date; + +/** + * 出口进场货物表 + * @TableName customer_export_in_cargo + */ +@Data +@ApiModel(value = "同步预靠泊时间",description = "") +public class UpdatePlanArrivePortVo implements Serializable { + + @ApiModelProperty(value = "船ID") + @NotBlank(message = "船ID不能为空") + private String shipId; + + @ApiModelProperty(value = "航次ID") + @NotBlank(message = "航次ID不能为空") + private String voyageId; + + @ApiModelProperty(value = "预靠泊时间") + @NotNull(message = "预靠泊时间不能为空") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date planArrivePortTime; +} \ No newline at end of file diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/UpdatePreArrivalTimeVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/UpdatePreArrivalTimeVo.java new file mode 100644 index 0000000..caa94c1 --- /dev/null +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/UpdatePreArrivalTimeVo.java @@ -0,0 +1,44 @@ +package com.haitonggauto.rtosc.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.haitonggauto.rtosc.repository.enums.AuditEnum; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 出口进场货物表 + * @TableName customer_export_in_cargo + */ +@Data +@ApiModel(value = "同步预进港时间",description = "") +public class UpdatePreArrivalTimeVo implements Serializable { + + @ApiModelProperty(value = "船ID") + @NotBlank(message = "船ID不能为空") + private String shipId; + + @ApiModelProperty(value = "航次ID") + @NotBlank(message = "航次ID不能为空") + private String voyageId; + + @ApiModelProperty(value = "原预进港时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date oldPreArrivalTime; + + @ApiModelProperty(value = "预进港时间") + @NotNull(message = "预进港时间不能为空") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date preArrivalTime; + + @ApiModelProperty(value = "新航次名称") + private String newVoyage; +} \ No newline at end of file diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/UpdateVoyageVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/UpdateVoyageVo.java index 611747d..c050f81 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/UpdateVoyageVo.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/UpdateVoyageVo.java @@ -19,10 +19,10 @@ public class UpdateVoyageVo implements Serializable { /** * 船名 */ - @Valid +// @Valid @ApiModelProperty(value = "计划ID") - @Size(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, min = 1, message = "计划ID不能为空") - @NotNull(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "计划ID不能为空") +// @Size(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, min = 1, message = "计划ID不能为空") +// @NotNull(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "计划ID不能为空") private List ids; /** @@ -39,4 +39,9 @@ public class UpdateVoyageVo implements Serializable { @NotBlank(groups = {ValidationGroup.insert.class, ValidationGroup.update.class}, message = "航次不能为空") private String voyage; + @ApiModelProperty(value = "提单号列表") + private List billNums; + + @ApiModelProperty(value = "是否验证") + private Boolean valid; } diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ValidVinActivateVo.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ValidVinActivateVo.java new file mode 100644 index 0000000..e9c8d5e --- /dev/null +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/dto/ValidVinActivateVo.java @@ -0,0 +1,31 @@ +package com.haitonggauto.rtosc.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.List; + +@Data +@ApiModel(value = "验证车架号是否激活",description = "") +public class ValidVinActivateVo implements Serializable { + + @ApiModelProperty(value = "船ID") + private String shipId; + + /** + * 受理号 + */ + @ApiModelProperty(value = "航次ID") + private String voyageId; + + @ApiModelProperty(value = "车架号列表") + @NotNull(message = "请传入车架号列表") + @Size(min = 1, message = "车架号列表不能为空") + private List vins; + +} diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/DepartureImportExcel.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/DepartureImportExcel.java new file mode 100644 index 0000000..c36ff8a --- /dev/null +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/DepartureImportExcel.java @@ -0,0 +1,59 @@ +package com.haitonggauto.rtosc.excel; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.math.BigDecimal; + +@Data +@ApiModel("提离港区导入") +public class DepartureImportExcel { + @ApiModelProperty("提单号") + @ExcelProperty(value = "提单号") + @NotBlank(message = "提单号不能为空") + private String billNo; + + @ApiModelProperty("车架号/备件号") + @ExcelProperty(value = "车架号/备件号") + @NotBlank(message = "车架号/备件号不能为空") + private String vin; + + @ApiModelProperty("车型") + @ExcelProperty(value = "车型") + private String cartType; + + @ApiModelProperty(value = "型号") + @ExcelProperty(value = "型号") + private String models; + + @ApiModelProperty(value = "长(米)") + @ExcelProperty(value = "长(米)") + private BigDecimal length; + + @ApiModelProperty(value = "宽(米)") + @ExcelProperty(value = "宽(米)") + private BigDecimal width; + + @ApiModelProperty(value = "高(米)") + @ExcelProperty(value = "高(米)") + private BigDecimal height; + + @ApiModelProperty(value = "重量(kg)") + @ExcelProperty(value = "重量(kg)") + private BigDecimal weight; + + @ApiModelProperty(value = "是否报关") + @ExcelProperty(value = "是否报关") + private String isCustoms; + + @ApiModelProperty(value = "是否退关提离") + @ExcelProperty(value = "是否退关提离") + private String isShutout; + + @ApiModelProperty(value = "是否随车备件") + @ExcelProperty(value = "是否随车备件") + private String isSpare; +} diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInBillSpareExcel.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInBillSpareExcel.java index fb68600..0eb50ff 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInBillSpareExcel.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInBillSpareExcel.java @@ -9,23 +9,23 @@ import javax.validation.constraints.Size; @Data public class ExportInBillSpareExcel { - @ExcelProperty("*船名") + @ExcelProperty(value = "*船名") @NotBlank(message = "船名不能为空") private String shipName; - @ExcelProperty("*航次") + @ExcelProperty(value = "*航次") @NotBlank(message = "航次不能为空") private String voyage; - @ExcelProperty("*提单号") + @ExcelProperty(value = "*提单号") @NotBlank(message = "提单号不能为空") private String billNo; - @ExcelProperty("*品牌") + @ExcelProperty(value = "*品牌") @NotBlank(message = "品牌不能为空") private String brand; - @ExcelProperty("*备件号") + @ExcelProperty(value = "*备件号") @NotBlank(message = "备件号不能为空") @Size(min = 17, max = 17, message = "备件号长度为17位") private String vin; diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInCargoExportExcel.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInCargoExportExcel.java index d35436f..86d7454 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInCargoExportExcel.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInCargoExportExcel.java @@ -12,31 +12,31 @@ import java.math.BigDecimal; @Data public class ExportInCargoExportExcel { - @ExcelProperty("船名") + @ExcelProperty(value = "船名") private String shipName; - @ExcelProperty("航次") + @ExcelProperty(value = "航次") private String voyage; - @ExcelProperty("提单号") + @ExcelProperty(value = "提单号") private String billNum; - @ExcelProperty("品牌") + @ExcelProperty(value = "品牌") private String brand; - @ExcelProperty("型号") + @ExcelProperty(value = "型号") private String models; - @ExcelProperty("车架号") + @ExcelProperty(value = "车架号") private String vin; - @ExcelProperty("实际进港时间") + @ExcelProperty(value = "实际进港时间") private String enterPortTime; - @ExcelProperty("场地") + @ExcelProperty(value = "场地") private String position; - @ExcelProperty("港口") + @ExcelProperty(value = "港口") private String portName; } \ No newline at end of file diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInExcel.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInExcel.java index 9259be1..27514f5 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInExcel.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInExcel.java @@ -9,28 +9,27 @@ import javax.validation.constraints.Size; @Data public class ExportInExcel { - @ExcelProperty("*船名") + @ExcelProperty(value = "*船名") @NotBlank(message = "船名不能为空") private String shipName; - @ExcelProperty("*航次") + @ExcelProperty(value = "*航次") @NotBlank(message = "航次不能为空") private String voyage; - @ExcelProperty("*提单号") + @ExcelProperty(value = "*提单号") @NotBlank(message = "提单号不能为空") private String billNo; - @ExcelProperty("*品牌") + @ExcelProperty(value = "*品牌") @NotBlank(message = "品牌不能为空") private String brand; - @ExcelProperty("*型号") + @ExcelProperty(value = "*型号") @NotBlank(message = "型号不能为空") private String models; - @ExcelProperty("*车架号") + @ExcelProperty(value = "*车架号") @NotBlank(message = "车架号不能为空") - @Size(min = 17, max = 17, message = "车架号长度为17位") private String vin; } diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInPlanExcel.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInPlanExcel.java index cc4564d..304477a 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInPlanExcel.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInPlanExcel.java @@ -43,39 +43,39 @@ public class ExportInPlanExcel { /** * 港区 */ - @ExcelProperty("*港区") + @ExcelProperty(value = "*港区") @NotBlank(message = "港区不能为空") private String portArea; /** * 船名 */ - @ExcelProperty("*船名") + @ExcelProperty(value = "*船名") @NotBlank(message = "船名不能为空") private String shipName; /** * 航次 */ - @ExcelProperty("*航次") + @ExcelProperty(value = "*航次") @NotBlank(message = "航次不能为空") private String voyage; - @ExcelProperty("*货物性质") + @ExcelProperty(value = "*货物性质") @NotBlank(message = "货物性质不能为空") private String natureFlagName; - @ExcelProperty("中转进口船名") + @ExcelProperty(value = "中转进口船名") private String transferShipName; - @ExcelProperty("中转进口航次") + @ExcelProperty(value = "中转进口航次") private String transferVoyage; /** * 货代 */ - @ExcelProperty("*货代") + @ExcelProperty(value = "*货代") @NotBlank(message = "货代不能为空") private String freight; @@ -83,43 +83,43 @@ public class ExportInPlanExcel { /** * 联系人 */ - @ExcelProperty("*联系人") + @ExcelProperty(value = "*联系人") @NotBlank(message = "联系人不能为空") private String contact; /** * 联系方式 */ - @ExcelProperty("*联系方式") + @ExcelProperty(value = "*联系方式") @NotBlank(message = "联系方式不能为空") private String contactPhone; /** * 港口 */ - @ExcelProperty("*国家") + @ExcelProperty(value = "*国家") @NotBlank(message = "国家不能为空") private String country; /** * 港口 */ - @ExcelProperty("*港口") + @ExcelProperty(value = "*港口") @NotBlank(message = "港口不能为空") private String portName; /** * 运输方式 */ - @ExcelProperty("*运输方式") + @ExcelProperty(value = "*运输方式") @NotBlank(message = "运输方式不能为空") private String transportWay; - @ExcelProperty("*进场开始日期") + @ExcelProperty(value = "*进场开始日期") @NotBlank(message = "进场开始日期不能为空") private String beginEnterTime; - @ExcelProperty("*进场结束日期") + @ExcelProperty(value = "*进场结束日期") @NotBlank(message = "进场结束日期不能为空") private String endEnterTime; @@ -127,26 +127,26 @@ public class ExportInPlanExcel { * 进场时间 */ // @DateTimeFormat("yyyy-MM-dd HH:mm") - @ExcelProperty("进场时间") + @ExcelProperty(value = "进场时间") private String enterTime; /** * 进场数量 */ - @ExcelProperty("进场数量") + @ExcelProperty(value = "进场数量") private Integer enterQuantity; /** * 提单号 */ - @ExcelProperty("*提单号") + @ExcelProperty(value = "*提单号") @NotBlank(message = "提单号不能为空") private String billNum; /** * 单票数量 */ - @ExcelProperty("*单票件数") + @ExcelProperty(value = "*单票件数") @NotNull(message = "单票件数不能为空") private Integer eachQuantity; @@ -160,7 +160,7 @@ public class ExportInPlanExcel { /** * 单票体积 */ - @ExcelProperty("*单票体积") + @ExcelProperty(value = "*单票体积") @NotNull(message = "单票体积不能为空") @NumberFormat("#.####") private BigDecimal eachVolume; @@ -168,7 +168,7 @@ public class ExportInPlanExcel { /** * 单票重量 */ - @ExcelProperty("*单票重量(千克)") + @ExcelProperty(value = "*单票重量(千克)") @NotNull(message = "单票重量不能为空") @NumberFormat("#.####") private BigDecimal eachWeight; @@ -176,49 +176,49 @@ public class ExportInPlanExcel { /** * 品牌 */ - @ExcelProperty("*品牌") + @ExcelProperty(value = "*品牌") @NotBlank(message = "品牌不能为空") private String brand; /** * 车型 */ - @ExcelProperty("*车型") + @ExcelProperty(value = "*车型") @NotBlank(message = "车型不能为空") private String cartType; /** * 车型明细 */ - @ExcelProperty("*车型明细") + @ExcelProperty(value = "*车型明细") @NotBlank(message = "车型明细不能为空") private String cartTypeDetail; /** * 型号 */ - @ExcelProperty("*型号") + @ExcelProperty(value = "*型号") @NotBlank(message = "型号不能为空") private String models; /** * 产地 */ - @ExcelProperty("*产地") + @ExcelProperty(value = "*产地") @NotBlank(message = "产地不能为空") private String originPlace; /** * 数量 */ - @ExcelProperty("*数量") + @ExcelProperty(value = "*数量") @NotNull(message = "数量不能为空") private Integer quantity; /** * 长 */ - @ExcelProperty("*长") + @ExcelProperty(value = "*长") @NotNull(message = "长不能为空") @NumberFormat("#.####") private BigDecimal length; @@ -226,7 +226,7 @@ public class ExportInPlanExcel { /** * 宽 */ - @ExcelProperty("*宽") + @ExcelProperty(value = "*宽") @NotNull(message = "宽不能为空") @NumberFormat("#.####") private BigDecimal width; @@ -234,7 +234,7 @@ public class ExportInPlanExcel { /** * 高 */ - @ExcelProperty("*高") + @ExcelProperty(value = "*高") @NotNull(message = "高不能为空") @NumberFormat("#.####") private BigDecimal height; @@ -242,34 +242,37 @@ public class ExportInPlanExcel { /** * 重量(吨) */ - @ExcelProperty("*重量(吨)") + @ExcelProperty(value = "*重量(吨)") @NotNull(message = "重量不能为空") @NumberFormat("#.####") private BigDecimal weight; - @ExcelProperty("*体积") + @ExcelProperty(value = "*体积") @ApiModelProperty(value = "体积") private BigDecimal volume; /** * 操作模式 */ - @ExcelProperty("*操作模式") + @ExcelProperty(value = "*操作模式") @NotBlank(message = "操作模式不能为空") private String operateType; @NotBlank(message = "特殊作业不能为空") - @ExcelProperty("*特殊作业") + @ExcelProperty(value = "*特殊作业") private String specWork; /** * 源类型 */ - @ExcelProperty("*能源类型") + @ExcelProperty(value = "*能源类型") // @NotBlank(message = "*能源类型不能为空") private String energyTypeName; - @ExcelProperty("*是否二手车") + @ExcelProperty(value = "*是否二手车") // @NotBlank(message = "是否是二手车不能为空") private String secondHand; + + @ExcelProperty(value = "备注") + private String remark; } \ No newline at end of file diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInSpareExcel.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInSpareExcel.java index 52ab629..fdf02f7 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInSpareExcel.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportInSpareExcel.java @@ -22,7 +22,7 @@ public class ExportInSpareExcel { @NotBlank(message = "备件号不能为空") @Size(min = 17, max = 17, message = "备件号长度为17位") @ApiModelProperty(value = "备件号") - @ExcelProperty("*备件号") + @ExcelProperty(value = "*备件号") private String vin; } \ No newline at end of file diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportLoadExcel.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportLoadExcel.java index 5473ca3..f28f8d1 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportLoadExcel.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportLoadExcel.java @@ -9,28 +9,27 @@ import javax.validation.constraints.Size; @Data public class ExportLoadExcel { - @ExcelProperty("*船名") + @ExcelProperty(value = "*船名") @NotBlank(message = "船名不能为空") private String shipName; - @ExcelProperty("*航次") + @ExcelProperty(value = "*航次") @NotBlank(message = "航次不能为空") private String voyage; - @ExcelProperty("*提单号") + @ExcelProperty(value = "*提单号") @NotBlank(message = "提单号不能为空") private String billNo; - @ExcelProperty("*车架号") + @ExcelProperty(value = "*车架号") @NotBlank(message = "车架号不能为空") - @Size(min = 17, max = 17, message = "车架号长度为17位") private String vin; @ExcelProperty(value = "*目的港") @NotBlank(message = "目的港不能为空") private String destPort; - @ExcelProperty("*品牌") + @ExcelProperty(value = "*品牌") @NotBlank(message = "品牌不能为空") private String brand; diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportLoadExportExcel.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportLoadExportExcel.java new file mode 100644 index 0000000..206d05d --- /dev/null +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportLoadExportExcel.java @@ -0,0 +1,60 @@ +package com.haitonggauto.rtosc.excel; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +@ApiModel("出口装船导出") +@Data +public class ExportLoadExportExcel implements Serializable { + @ApiModelProperty(value = "中文船名") + @ExcelProperty("船名") + private String shipName; + + @ApiModelProperty(value = "航次") + @ExcelProperty("船名") + private String voyage; + + @ApiModelProperty(value = "货物性质名称") + @ExcelProperty("货物性质") + private String natureFlagName; + + @ApiModelProperty(value = "中转进口船名") + @ExcelProperty("中转进口船名") + private String transferShipName; + + @ApiModelProperty(value = "中转进口航次") + @ExcelProperty("中转进口航次") + private String transferVoyage; + + @ApiModelProperty(value = "提单号") + @ExcelProperty("提单号") + private String billNo; + + @ApiModelProperty(value = "品牌") + @ExcelProperty("品牌") + private String brand; + + @ApiModelProperty(value = "目的港") + @ExcelProperty("目的港") + private String destPort; + + @ApiModelProperty(value = "车架号") + @ExcelProperty("车架号") + private String vin; + + @ApiModelProperty(value = "结算单位") + @ExcelProperty("结算单位") + private String settleCompName; + + @ApiModelProperty(value = "联系人") + @ExcelProperty("联系人") + private String contact; + + @ApiModelProperty(value = "联系方式") + @ExcelProperty("联系方式") + private String contactPhone; +} diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportLoadInsideExcel.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportLoadInsideExcel.java index d53b5ab..5717d46 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportLoadInsideExcel.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportLoadInsideExcel.java @@ -12,56 +12,55 @@ import javax.validation.constraints.Size; @DependsOn(field1 = "natureFlagName", fields = {"transferShipName", "transferVoyage"}, message = "货物性质为“正常”时,中转船名,中转航次为空, 否则必填") public class ExportLoadInsideExcel { - @ExcelProperty("*船名") + @ExcelProperty(value = "*船名") @NotBlank(message = "船名不能为空") private String shipName; - @ExcelProperty("*航次") + @ExcelProperty(value = "*航次") @NotBlank(message = "航次不能为空") private String voyage; - @ExcelProperty("*货物性质") + @ExcelProperty(value = "*货物性质") @NotBlank(message = "货物性质不能为空") private String natureFlagName; - @ExcelProperty("中转进口船名") + @ExcelProperty(value = "中转进口船名") private String transferShipName; - @ExcelProperty("中转进口航次") + @ExcelProperty(value = "中转进口航次") private String transferVoyage; - @ExcelProperty("*港区") - @NotBlank(message = "港区不能为空") - private String portArea; +// @ExcelProperty("*港区") +// @NotBlank(message = "港区不能为空") +// private String portArea; - @ExcelProperty("*提单号") + @ExcelProperty(value = "*提单号") @NotBlank(message = "提单号不能为空") private String billNo; - @ExcelProperty("*品牌") + @ExcelProperty(value = "*品牌") @NotBlank(message = "品牌不能为空") private String brand; - @ExcelProperty("*目的港") + @ExcelProperty(value = "*目的港") @NotBlank(message = "目的港不能为空") private String destPort; - @ExcelProperty("*车架号") + @ExcelProperty(value = "*车架号") @NotBlank(message = "车架号不能为空") - @Size(min = 17, max = 17, message = "车架号长度为17位") private String vin; - @ExcelProperty("*结算单位") + @ExcelProperty(value = "*结算单位") @ApiModelProperty(value = "结算单位") @NotBlank(message = "结算单位不能为空") private String settleCompName; - @ExcelProperty("*联系人") + @ExcelProperty(value = "*联系人") @ApiModelProperty(value = "联系人") @NotBlank(message = "联系人不能为空") private String contact; - @ExcelProperty("*联系方式") + @ExcelProperty(value = "*联系方式") @ApiModelProperty(value = "联系方式") @NotBlank(message = "联系方式不能为空") private String contactPhone; diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportLoadSpareExcel.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportLoadSpareExcel.java index 73b8866..c596ffb 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportLoadSpareExcel.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportLoadSpareExcel.java @@ -10,15 +10,15 @@ import javax.validation.constraints.Size; @Data public class ExportLoadSpareExcel { - @ExcelProperty("*船名") + @ExcelProperty(value = "*船名") @NotBlank(message = "船名不能为空") private String shipName; - @ExcelProperty("*航次") + @ExcelProperty(value = "*航次") @NotBlank(message = "航次不能为空") private String voyage; - @ExcelProperty("*提单号") + @ExcelProperty(value = "*提单号") @NotBlank(message = "提单号不能为空") private String billNo; @@ -26,11 +26,11 @@ public class ExportLoadSpareExcel { @NotBlank(message = "目的港不能为空") private String destPort; - @ExcelProperty("*品牌") + @ExcelProperty(value = "*品牌") @NotBlank(message = "品牌不能为空") private String brand; - @ExcelProperty("*数量") + @ExcelProperty(value = "*数量") @NotNull(message = "数量不能为空") private Integer num; diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportVinExcel.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportVinExcel.java index 070e7bd..5085dbe 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportVinExcel.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ExportVinExcel.java @@ -22,16 +22,15 @@ public class ExportVinExcel { */ @ApiModelProperty(value = "提单号") @NotBlank(message = "提单号不能为空") - @ExcelProperty("*提单号") + @ExcelProperty(value = "*提单号") private String billNo; /** * 船名 */ @NotBlank(message = "车架号不能为空") - @Size(min = 17, max = 17, message = "车架号长度为17位") @ApiModelProperty(value = "车架号") - @ExcelProperty("*车架号") + @ExcelProperty(value = "*车架号") private String vin; } \ No newline at end of file diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/FreeTradeExcel.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/FreeTradeExcel.java index 1180e11..a2dd4cb 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/FreeTradeExcel.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/FreeTradeExcel.java @@ -18,104 +18,125 @@ public class FreeTradeExcel { * 港区 */ @NotBlank(message = "港区不能为空") - @ExcelProperty("*港区") + @ExcelProperty(value = "*港区") @ApiModelProperty(value = "港区") private String portArea; + /** + * 船名 + */ + @ExcelProperty(value = "*船名") + @NotBlank(message = "船名不能为空") + private String shipName; + + /** + * 航次 + */ + @ExcelProperty(value = "*航次") + @NotBlank(message = "航次不能为空") + private String voyage; + // 批次号 @ApiModelProperty(value = "批次号") @NotBlank(message = "批次号不能为空") - @ExcelProperty("批次号") + @ExcelProperty(value = "批次号") private String batchNo; // 企业编码 @ApiModelProperty(value = "企业编码") @NotBlank(message = "企业编码不能为空") - @ExcelProperty("*企业编码") + @ExcelProperty(value = "*企业编码") private String companyCode; // 企业社会信用代码 @ApiModelProperty(value = "企业社会信用代码") @NotBlank(message = "企业社会信用代码不能为空") - @ExcelProperty("*企业社会信用代码") + @ExcelProperty(value = "*企业社会信用代码") private String companySocialCode; // 企业名称 @ApiModelProperty(value = "企业名称") @NotBlank(message = "企业名称不能为空") - @ExcelProperty("*企业名称") + @ExcelProperty(value = "*企业名称") private String companyName; // 企业所在国家 @ApiModelProperty(value = "企业所在国家") @NotBlank(message = "企业所在国家不能为空") - @ExcelProperty("*企业所在国家") + @ExcelProperty(value = "*企业所在国家") private String country; // 企业所在城市 @ApiModelProperty(value = "企业所在城市") @NotBlank(message = "企业所在城市不能为空") - @ExcelProperty("*企业所在城市") + @ExcelProperty(value = "*企业所在城市") private String city; - // 商品料号 + /** + * 商品料号 + */ @ApiModelProperty(value = "商品料号") @NotBlank(message = "商品料号不能为空") - @ExcelProperty("*商品料号") + @ExcelProperty(value = "*商品料号") + private String cargoItemNo; + + // 商品料号 + @ApiModelProperty(value = "商品编码") + @NotBlank(message = "商品编码不能为空") + @ExcelProperty(value = "*商品编码") private String cargoCode; // 商品名称 @ApiModelProperty(value = "商品名称") @NotBlank(message = "商品名称不能为空") - @ExcelProperty("*商品名称") + @ExcelProperty(value = "*商品名称") private String cargoName; // 规格型号 @ApiModelProperty(value = "规格型号") @NotBlank(message = "规格型号不能为空") - @ExcelProperty("*规格型号") + @ExcelProperty(value = "*规格型号") private String spec; // 币制 @ApiModelProperty(value = "币制") @NotBlank(message = "币制不能为空") - @ExcelProperty("*币制") + @ExcelProperty(value = "*币制") private String currency; // 总价 @ApiModelProperty(value = "总价") @NotNull(message = "总价不能为空") - @ExcelProperty("*总价") + @ExcelProperty(value = "*总价") private BigDecimal totalPrice; // 净重 @ApiModelProperty(value = "净重") @NotNull(message = "净重不能为空") - @ExcelProperty("*净重") + @ExcelProperty(value = "*净重") private BigDecimal netWeight; // 申报计量单位 @ApiModelProperty(value = "申报计量单位") @NotBlank(message = "申报计量单位不能为空") - @ExcelProperty("*申报计量单位") + @ExcelProperty(value = "*申报计量单位") private String unitMeasure; // 法定单位 @ApiModelProperty(value = "法定单位") @NotBlank(message = "法定单位不能为空") - @ExcelProperty("*法定单位") + @ExcelProperty(value = "*法定单位") private String unitLegal; // 原产国(地区) @ApiModelProperty(value = "原产国") @NotBlank(message = "原产国不能为空") - @ExcelProperty("*原产国(地区)") + @ExcelProperty(value = "*原产国(地区)") private String originArea; // 车架号 @ApiModelProperty(value = "车架号") @NotBlank(message = "车架号不能为空") - @Size(min = 17, max = 17, message = "车架号长度为17位") - @ExcelProperty("*车架号") + @ExcelProperty(value = "*车架号") private String vin; } diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ImportUnloadExcel.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ImportUnloadExcel.java index 23ac159..9864b4d 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ImportUnloadExcel.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/ImportUnloadExcel.java @@ -31,6 +31,5 @@ public class ImportUnloadExcel { @ExcelProperty("*车架号") @NotBlank(message = "车架号不能为空") - @Size(min = 17, max = 17, message = "车架号长度为17位") private String vin; } diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/InspectExcel.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/InspectExcel.java new file mode 100644 index 0000000..440459c --- /dev/null +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/excel/InspectExcel.java @@ -0,0 +1,58 @@ +package com.haitonggauto.rtosc.excel; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.Date; + +@Data +@ApiModel("查验导入") +public class InspectExcel { + /** + * 港区 + */ + @ExcelProperty(value = "*港区") + @NotBlank(message = "港区不能为空") + private String portArea; + + /** + * 船名 + */ + @ExcelProperty(value = "*船名") + @NotBlank(message = "船名不能为空") + private String shipName; + + @ApiModelProperty(value = "航次") + @ExcelProperty(index = 2) + private String voyage; + + @ExcelProperty(value = "*提单号") + @NotBlank(message = "提单号不能为空") + private String billNo; + + @ApiModelProperty(value = "报关单号") + private String passport; + + @ApiModelProperty(value = "*查验日期") + @NotNull(message = "查验日期不能为空") + private Date inspectTime; + + @ApiModelProperty(value = "公司名") + private String company; + + @ApiModelProperty(value = "*联系人") + @NotBlank(message = "联系人不能为空") + private String contact; + + @ApiModelProperty(value = "*联系电话") + @NotBlank(message = "联系电话不能为空") + private String contactPhone; + + @ApiModelProperty(value = "*车架号/备件号") + @NotBlank(message = "车架号/备件号不能为空") + private String vin; +} diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/CargoQuery.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/CargoQuery.java index 04cbbda..328e61c 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/CargoQuery.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/CargoQuery.java @@ -19,4 +19,11 @@ public class CargoQuery extends BaseQuery { @ApiModelProperty(value = "品牌ID") private String brandId; + + @ApiModelProperty(value = "提单号") + @DbQuery(field = "select id from customer_export_load where export_load_id=customer_export_load.id and bill_no like {0}", symbol = SqlSymbol.EXISTS) + private String billNum; + + @ApiModelProperty(value = "是否填充车辆状态") + private Boolean vinStatus; } diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/CargoVinQuery.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/CargoVinQuery.java new file mode 100644 index 0000000..4a049c5 --- /dev/null +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/CargoVinQuery.java @@ -0,0 +1,16 @@ +package com.haitonggauto.rtosc.query; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + + +@Data +@ApiModel(value = "货物明细查询") +public class CargoVinQuery { + @ApiModelProperty(value = "车架号") + private String vin; + + @ApiModelProperty("提单号") + private String billNum; +} diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/DepartureQuery.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/DepartureQuery.java index fd12d82..568e9f0 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/DepartureQuery.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/DepartureQuery.java @@ -74,6 +74,22 @@ public class DepartureQuery extends BaseQuery { @ApiModelProperty(value = "港区ID") private String portAreaId; + @ApiModelProperty(value = "提单号") + @DbQuery(field = "select id from customer_departure_cargo where departure_id=customer_departure.id and bill_no like {0}", symbol = SqlSymbol.EXISTS) + private String billNum; + + @ApiModelProperty(value = "精确提单号") + @DbQuery(field = "select id from customer_departure_cargo where departure_id=customer_departure.id and bill_no={0}", symbol = SqlSymbol.EXISTS) + private String billNumAccurate; + + @ApiModelProperty(value = "品牌ID") +// @DbQuery(field = "select id from customer_departure_cargo where departure_id=customer_departure.id and brand_id={0}", symbol = SqlSymbol.EXISTS) + private String brandId; + + @ApiModelProperty(value = "车架号") + @DbQuery(field = "select id from customer_departure_cargo where departure_id=customer_departure.id and vin like {0}", symbol = SqlSymbol.EXISTS) + private String vin; + @ApiModelProperty(value = "港区ID集合") @DbQuery(field = "portAreaId", symbol = SqlSymbol.IN) private List pamIds; diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInBathCheckQuery.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInBathCheckQuery.java new file mode 100644 index 0000000..b53bf5d --- /dev/null +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInBathCheckQuery.java @@ -0,0 +1,28 @@ +package com.haitonggauto.rtosc.query; + +import com.haitonggauto.rtosc.common.db.query.BaseQuery; +import com.haitonggauto.rtosc.repository.enums.AuditEnum; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Data +@ApiModel(value = "出口进港查询") +public class ExportInBathCheckQuery extends BaseQuery { + + @ApiModelProperty(value = "船ID") + private String shipId; + + @ApiModelProperty(value = "航次ID") + private String voyageId; + + @ApiModelProperty(value = "港区ID") + private String portAreaId; + + @ApiModelProperty(value = "审核状态") + @NotNull(message = "审核状态不能为空") + private AuditEnum checkStatus; + +} diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInCheckQuery.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInCheckQuery.java index dd78093..e0f319e 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInCheckQuery.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInCheckQuery.java @@ -56,12 +56,12 @@ public class ExportInCheckQuery extends BaseQuery { @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @ApiModelProperty(value = "开始进场时间") - @DbQuery(field = "beginEnterTime", symbol = SqlSymbol.GTE) + @DbQuery(field = "beginEnterTime", symbol = SqlSymbol.LTE) private Date beginEnterTime; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @ApiModelProperty(value = "结束进场时间") - @DbQuery(field = "endEnterTime", symbol = SqlSymbol.LTE) + @DbQuery(field = "endEnterTime", symbol = SqlSymbol.GTE) private Date endEnterTime; @ApiModelProperty(value = "贸易类型") @@ -90,6 +90,10 @@ public class ExportInCheckQuery extends BaseQuery { @DbQuery(symbol = SqlSymbol.LIKE) private String billNum; + @ApiModelProperty(value = "精确提单号") + @DbQuery(field = "billNum") + private String billNumAccurate; + @ApiModelProperty(value = "受理号") @DbQuery(symbol = SqlSymbol.LIKE) private String batchNo; @@ -101,6 +105,7 @@ public class ExportInCheckQuery extends BaseQuery { private String freightId; @ApiModelProperty(value = "车架号") + @DbQuery(field = "select id from customer_export_in_cargo where export_in_id=customer_export_in.id and vin like {0}", symbol = SqlSymbol.EXISTS) private String vin; @ApiModelProperty(value = "国家Id") @@ -109,12 +114,18 @@ public class ExportInCheckQuery extends BaseQuery { @ApiModelProperty(value = "港口ID") private String portId; - @ApiModelProperty(hidden = true) - @DbQuery(field = "vin", symbol = SqlSymbol.IN) - private List vins; + @ApiModelProperty(value = "联系人") + @DbQuery(symbol = SqlSymbol.LIKE) + private String contact; // 明细表查询时会用到 @ApiModelProperty(hidden = true) private Long exportInId; + @ApiModelProperty(value = "是否加载车架号列表") + private Boolean vinStatus; + + @ApiModelProperty(value = "是否调用车架号状态接口") + private Boolean vinStatusApi; + } diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInQuery.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInQuery.java index d8b4861..b0d2a1e 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInQuery.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInQuery.java @@ -66,6 +66,10 @@ public class ExportInQuery extends BaseQuery { @DbQuery(symbol = SqlSymbol.LIKE) private String billNum; + @ApiModelProperty(value = "精确提单号") + @DbQuery(field = "billNum") + private String billNumAccurate; + @ApiModelProperty(value = "受理号") @DbQuery(symbol = SqlSymbol.LIKE) private String batchNo; @@ -82,9 +86,13 @@ public class ExportInQuery extends BaseQuery { @ApiModelProperty(value = "货代ID") private String freightId; - @ApiModelProperty(hidden = true) - @DbQuery(field = "vin", symbol = SqlSymbol.IN) - private List vins; + @ApiModelProperty(value = "联系人") + @DbQuery(symbol = SqlSymbol.LIKE) + private String contact; + + @ApiModelProperty(value = "车架号") + @DbQuery(field = "select id from customer_export_in_cargo where export_in_id=customer_export_in.id and vin like {0}", symbol = SqlSymbol.EXISTS) + private String vin; // 明细表查询时会用到 @ApiModelProperty(hidden = true) diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInspectCheckQuery.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInspectCheckQuery.java index 9c68441..941df1c 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInspectCheckQuery.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInspectCheckQuery.java @@ -1,5 +1,6 @@ package com.haitonggauto.rtosc.query; +import com.fasterxml.jackson.annotation.JsonFormat; import com.haitonggauto.rtosc.common.db.anno.DbQuery; import com.haitonggauto.rtosc.common.db.enums.SqlSymbol; import com.haitonggauto.rtosc.common.db.query.BaseQuery; @@ -7,7 +8,9 @@ import com.haitonggauto.rtosc.repository.enums.AuditEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; +import java.util.Date; import java.util.List; @Data @@ -24,6 +27,9 @@ public class ExportInspectCheckQuery extends BaseQuery { @ApiModelProperty(value = "航次ID") private String voyageId; + @ApiModelProperty(value = "申请对象ID") + private String applyObjId; + @ApiModelProperty(value = "航次") private String voyage; @@ -45,6 +51,38 @@ public class ExportInspectCheckQuery extends BaseQuery { @DbQuery(symbol = SqlSymbol.LIKE) private String batchNo; + @ApiModelProperty(value = "报关单号") + @DbQuery(symbol = SqlSymbol.LIKE) + private String passport; + + @ApiModelProperty(value = "提单号") + @DbQuery(field = "billNo", symbol = SqlSymbol.LIKE) + private String billNum; + + @ApiModelProperty(value = "精确提单号") + @DbQuery(field = "billNo") + private String billNumAccurate; + + @ApiModelProperty(value = "品牌ID") + @DbQuery(field = "select id from customer_export_inspect_cargo where export_inspect_id=customer_export_inspect.id and brand_id={0}", symbol = SqlSymbol.EXISTS) + private String brandId; + + @ApiModelProperty(value = "车架号") + @DbQuery(field = "select id from customer_export_inspect_cargo where export_inspect_id=customer_export_inspect.id and vin like {0}", symbol = SqlSymbol.EXISTS) + private String vin; + + @ApiModelProperty(value = "开始查验日期") + @JsonFormat(pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + @DbQuery(field = "inspectTime", symbol = SqlSymbol.GTE) + private Date beginInspectTime; + + @ApiModelProperty(value = "结束查验日期") + @JsonFormat(pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + @DbQuery(field = "inspectTime", symbol = SqlSymbol.LTE) + private Date endInspectTime; + @ApiModelProperty(hidden = true) private String tradType; diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInspectQuery.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInspectQuery.java index add28f9..642770d 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInspectQuery.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportInspectQuery.java @@ -1,5 +1,6 @@ package com.haitonggauto.rtosc.query; +import com.fasterxml.jackson.annotation.JsonFormat; import com.haitonggauto.rtosc.common.db.anno.DbQuery; import com.haitonggauto.rtosc.common.db.enums.SqlSymbol; import com.haitonggauto.rtosc.common.db.query.BaseQuery; @@ -8,6 +9,7 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import java.util.Date; import java.util.List; @Data @@ -20,6 +22,9 @@ public class ExportInspectQuery extends BaseQuery { @ApiModelProperty(value = "航次ID") private String voyageId; + @ApiModelProperty(value = "申请对象ID") + private String applyObjId; + @ApiModelProperty(value = "船名") @DbQuery(symbol = SqlSymbol.LIKE) private String shipName; @@ -42,6 +47,36 @@ public class ExportInspectQuery extends BaseQuery { @DbQuery(symbol = SqlSymbol.LIKE) private String batchNo; + @ApiModelProperty(value = "报关单号") + @DbQuery(symbol = SqlSymbol.LIKE) + private String passport; + + @ApiModelProperty(value = "提单号") + @DbQuery(field = "billNo", symbol = SqlSymbol.LIKE) + private String billNum; + + @ApiModelProperty(value = "精确提单号") + @DbQuery(field = "billNo") + private String billNumAccurate; + + @ApiModelProperty(value = "品牌ID") + @DbQuery(field = "select id from customer_export_inspect_cargo where export_inspect_id=customer_export_inspect.id and brand_id={0}", symbol = SqlSymbol.EXISTS) + private String brandId; + + @ApiModelProperty(value = "车架号") + @DbQuery(field = "select id from customer_export_inspect_cargo where export_inspect_id=customer_export_inspect.id and vin like {0}", symbol = SqlSymbol.EXISTS) + private String vin; + + @ApiModelProperty(value = "开始查验日期") + @JsonFormat(pattern = "yyyy-MM-dd") + @DbQuery(field = "inspectTime", symbol = SqlSymbol.GTE) + private Date beginInspectTime; + + @ApiModelProperty(value = "结束查验日期") + @JsonFormat(pattern = "yyyy-MM-dd") + @DbQuery(field = "inspectTime", symbol = SqlSymbol.LTE) + private Date endInspectTime; + @ApiModelProperty(hidden = true) private String tradType; diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportLoadCheckQuery.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportLoadCheckQuery.java index ef8f0cf..dff0f96 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportLoadCheckQuery.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportLoadCheckQuery.java @@ -54,6 +54,13 @@ public class ExportLoadCheckQuery extends BaseQuery { @ApiModelProperty(hidden = true) private Long exportLoadId; + @DbQuery(field = "billNo", symbol = SqlSymbol.IN) + private List billNos; + + @ApiModelProperty(value = "车架号") + @DbQuery(field = "select id from customer_export_load_cargo where export_load_id=customer_export_load.id and vin like {0}", symbol = SqlSymbol.EXISTS) + private String vin; + @ApiModelProperty(hidden = true) @DbQuery(field = "vin", symbol = SqlSymbol.IN) private List vins; diff --git a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportLoadQuery.java b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportLoadQuery.java index e15f78d..fa15235 100644 --- a/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportLoadQuery.java +++ b/nuzar-customer-client/src/main/java/com/haitonggauto/rtosc/query/ExportLoadQuery.java @@ -51,6 +51,10 @@ public class ExportLoadQuery extends BaseQuery { @ApiModelProperty(hidden = true) private Long exportLoadId; + @ApiModelProperty(value = "车架号") + @DbQuery(field = "select id from customer_export_load_cargo where export_load_id=customer_export_load.id and vin like {0}", symbol = SqlSymbol.EXISTS) + private String vin; + @ApiModelProperty(hidden = true) @DbQuery(field = "vin", symbol = SqlSymbol.IN) private List vins; diff --git a/nuzar-customer-common/src/main/java/com/haitonggauto/rtosc/common/dto/LoginUser.java b/nuzar-customer-common/src/main/java/com/haitonggauto/rtosc/common/dto/LoginUser.java index a749f13..2ec9546 100644 --- a/nuzar-customer-common/src/main/java/com/haitonggauto/rtosc/common/dto/LoginUser.java +++ b/nuzar-customer-common/src/main/java/com/haitonggauto/rtosc/common/dto/LoginUser.java @@ -11,6 +11,9 @@ public class LoginUser implements Serializable { // 用户ID private String userId; + // 用户名 + private String username; + // 角色ID private Long roleId; @@ -57,4 +60,12 @@ public class LoginUser implements Serializable { public void setPermList(Set permList) { this.permList = permList; } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } } diff --git a/nuzar-customer-common/src/main/java/com/haitonggauto/rtosc/common/utils/WrapperKit.java b/nuzar-customer-common/src/main/java/com/haitonggauto/rtosc/common/utils/WrapperKit.java index d74cadc..2afec3c 100644 --- a/nuzar-customer-common/src/main/java/com/haitonggauto/rtosc/common/utils/WrapperKit.java +++ b/nuzar-customer-common/src/main/java/com/haitonggauto/rtosc/common/utils/WrapperKit.java @@ -189,12 +189,18 @@ public interface WrapperKit { return; } - if (!fieldMetadataMap.containsKey(fName)) { + if (symbol != SqlSymbol.EXISTS && symbol != SqlSymbol.NOT_EXISTS && symbol != SqlSymbol.EXPRESSION && !fieldMetadataMap.containsKey(fName)) { throw new FieldNotExistsException(String.format("类:%s, 不存在属性: %s" , classMetadata.getClazz().getName(), fName)); } - String column = fieldMetadataMap.get(fName).getColumn(); - if (StringUtils.isNotEmpty(alias)) { - column = alias + "." + column; + String column = null; + + if (symbol == SqlSymbol.EXISTS || symbol == SqlSymbol.NOT_EXISTS || symbol == SqlSymbol.EXPRESSION) { + column = fName; + } else { + column = fieldMetadataMap.get(fName).getColumn(); + if (StringUtils.isNotEmpty(alias)) { + column = alias + "." + column; + } } if (symbol == SqlSymbol.IN) { @@ -212,9 +218,9 @@ public interface WrapperKit { } else if (symbol.equals(SqlSymbol.RLIKE)) { queryWrapper.likeRight(column, fValue); } else if (symbol.equals(SqlSymbol.EXISTS)) { - queryWrapper.exists(column, fValue); + queryWrapper.exists(column, StringUtils.containsIgnoreCase(column, " like ") ? "%" + fValue + "%" : fValue); } else if (symbol.equals(SqlSymbol.NOT_EXISTS)) { - queryWrapper.notExists(column, fValue); + queryWrapper.notExists(column, StringUtils.containsIgnoreCase(column, " like ") ? "%" + fValue + "%" : fValue); } else if (symbol.equals(SqlSymbol.GTE)) { queryWrapper.ge(column, fValue); } else if (symbol.equals(SqlSymbol.GT)) { diff --git a/nuzar-customer-common/src/main/java/com/haitonggauto/rtosc/common/validate/DependsOnValidator.java b/nuzar-customer-common/src/main/java/com/haitonggauto/rtosc/common/validate/DependsOnValidator.java index 0b45f8b..8e0b6ad 100644 --- a/nuzar-customer-common/src/main/java/com/haitonggauto/rtosc/common/validate/DependsOnValidator.java +++ b/nuzar-customer-common/src/main/java/com/haitonggauto/rtosc/common/validate/DependsOnValidator.java @@ -39,7 +39,7 @@ public class DependsOnValidator implements ConstraintValidator haveShipPlan(@RequestParam("vvyId") String vvyId); + @PostMapping("/customer/shipment/shipLoad/getShipPlans") + Map> haveShipPlans(@RequestBody CheckShipPlanReq req); + // 装船审核获取国际中转备件 @PostMapping("/customer/shipment/shipLoad/transitPart") Map> getTransitPart(@RequestBody TransitPartRequest request); @@ -140,4 +145,23 @@ public interface NuzarOpenApi { // 获取绑定货代 @GetMapping("/rtos/user/getFreightId") List getUserBindFreight(); + + @PostMapping("/customer/shipment/queryTrendShips") + List getTrendShipList(@RequestBody List shipNames); + + @PostMapping("/customer/yard/batchConfirmRevise") + Boolean batchConfirmRevise(UpdateVoyageVo req); + + @PostMapping("/customer/yard/getCarPickTime") + Map getCarPickTime(@RequestBody List vinCodes); + + @GetMapping("/rtos/user/searchUser") + UserInfoDto getUserInfo(); + + // 提离港区车架号验证 + @PostMapping("/customer/pickDeparture/vinCheckInfo") + List vinCheckInfo(@RequestBody VinCheckReq req); + + @PostMapping("/customer/yard/batchConfirmReview") + Boolean batchConfirmReview(@RequestBody BatchConfirmReviewReq req); } diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/NuzarShpApi.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/NuzarShpApi.java index 19b7001..54b656c 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/NuzarShpApi.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/NuzarShpApi.java @@ -1,9 +1,6 @@ package com.haitonggauto.rtosc.api; -import com.haitonggauto.rtosc.api.dto.CheckVinReq; -import com.haitonggauto.rtosc.api.dto.VoyageDTO; -import com.haitonggauto.rtosc.api.dto.VoyageReq; -import com.haitonggauto.rtosc.api.dto.VoyageResp; +import com.haitonggauto.rtosc.api.dto.*; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -32,4 +29,15 @@ public interface NuzarShpApi { @PostMapping("/vesselVoyages/shipNameFilter") List checkShipStatus(@RequestBody List req); + + @PostMapping("/shipment/unload/plans/unloadInfoVerify") + List unloadInfoVerify(@RequestBody List req); + + /** + * 离泊状态 + * @param vvyIds + * @return + */ + @PostMapping("/vesselVoyages/queryBerthsStatusByVvyIds") + List queryVoyagesBerthsStatusByVvyIds(@RequestBody List vvyIds); } diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/BatchConfirmReviewReq.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/BatchConfirmReviewReq.java new file mode 100644 index 0000000..91a70ad --- /dev/null +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/BatchConfirmReviewReq.java @@ -0,0 +1,27 @@ +package com.haitonggauto.rtosc.api.dto; + +import io.swagger.annotations.ApiModel; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +@Data +@ApiModel("审核后批量修对对应航次") +public class BatchConfirmReviewReq implements Serializable { + private List billNos; + + private List ids; + + private List mnfBls; + + private String shipId; + + private String shipName; + + private String voyage; + + private String voyageId; + + private String vvyId; +} diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/CheckShipPlanReq.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/CheckShipPlanReq.java new file mode 100644 index 0000000..a71fe4a --- /dev/null +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/CheckShipPlanReq.java @@ -0,0 +1,16 @@ +package com.haitonggauto.rtosc.api.dto; + + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +@Data +@ApiModel("验证是否有装船计划") +public class CheckShipPlanReq implements Serializable { + @ApiModelProperty("航次ID") + private List vvyIds; +} diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/CheckVinReq.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/CheckVinReq.java index 1f2093b..e54efef 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/CheckVinReq.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/CheckVinReq.java @@ -19,4 +19,7 @@ public class CheckVinReq implements Serializable { @ApiModelProperty("车架号") private String vinCode; + + @ApiModelProperty("航次ID") + private String vvyId; } diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/ImportInspectReq.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/ImportInspectReq.java new file mode 100644 index 0000000..12a9733 --- /dev/null +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/ImportInspectReq.java @@ -0,0 +1,31 @@ +package com.haitonggauto.rtosc.api.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +@Data +@ApiModel("进口查验检验请求") +public class ImportInspectReq implements Serializable { + @ApiModelProperty("提单号") + private String mnfBl; + + @ApiModelProperty("船ID") + private String spmId; + + @ApiModelProperty("船名") + private String spmName; + + @ApiModelProperty("车架号") + private String vinCode; + + @ApiModelProperty("航次ID") + private String vvyId; + + @ApiModelProperty("船次") + private String vvyName; + + +} diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/ImportInspectResp.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/ImportInspectResp.java new file mode 100644 index 0000000..3a76a9c --- /dev/null +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/ImportInspectResp.java @@ -0,0 +1,55 @@ +package com.haitonggauto.rtosc.api.dto; + +import io.swagger.annotations.ApiModel; +import lombok.Data; + +import java.io.Serializable; + +@Data +@ApiModel("进口查验返回") +public class ImportInspectResp implements Serializable { + private String errorMsg; + + private String mnfBl; + + private String spmName; + + private String vinCode; + + private String vvyName; + + private YardGoodsDTO yardGoodsDTO; + + @Data + public static class YardGoodsDTO implements Serializable { + private String brdId; + + private String brdName; + + private String bvmName; + + private String goodsType; + + private String model; + + private String position; + + private String spmId; + + private String storeArea; + + private String vvyId; + + private String yacId; + + private String yalId; + + private String yarId; + + private String yardId; + + private String pamId; + + private String pamName; + } +} diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/ShipmentBerthsStatusRespDTO.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/ShipmentBerthsStatusRespDTO.java new file mode 100644 index 0000000..6dd57d8 --- /dev/null +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/ShipmentBerthsStatusRespDTO.java @@ -0,0 +1,23 @@ +package com.haitonggauto.rtosc.api.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author zhaoyusheng + * @version 1.0.0 + * @classname ShipmentBerthsStatusRespDTO + * @date 2024/7/23 + * @time 13:13 + * @description 航次泊位状态 + */ +@Data +public class ShipmentBerthsStatusRespDTO implements Serializable { + private static final long serialVersionUID = 1566352212034798745L; + @ApiModelProperty(value = "航次id") + private String vvyId; + @ApiModelProperty(value = "是否离泊:0否 1是") + private String unberthedStatus; +} diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/TrendShipResp.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/TrendShipResp.java new file mode 100644 index 0000000..e8c1bf3 --- /dev/null +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/TrendShipResp.java @@ -0,0 +1,26 @@ +package com.haitonggauto.rtosc.api.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +@Data +@ApiModel("旬度计划船名") +public class TrendShipResp { + @ApiModelProperty("船舶id") + private String spmId; + + @ApiModelProperty("船名") + private String spmName; + + @ApiModelProperty("船code") + private String vslCode; + + @ApiModelProperty("预计到港时间") + private Date planArrivePortTime; + + @ApiModelProperty("英文名") + private String spmEname; +} diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/UserInfoDto.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/UserInfoDto.java new file mode 100644 index 0000000..e4e3e16 --- /dev/null +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/UserInfoDto.java @@ -0,0 +1,94 @@ +package com.haitonggauto.rtosc.api.dto; + +import com.fasterxml.jackson.annotation.JsonAlias; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * @author wangzhengyan + * @Date 2023/5/5 0005 13:55 + */ +@Data +public class UserInfoDto implements Serializable { + private static final long serialVersionUID = -2463058823324072492L; + + @ApiModelProperty(value = "用户id") + private String id; + + @ApiModelProperty(value = "客户姓名") + private String name; + + @ApiModelProperty(value = "登录账号") + private String account; + + @ApiModelProperty(value = "联系人") + @JsonAlias("memo") + private String contactPerson; + + @ApiModelProperty(value = "邮箱") + private String email; + + @ApiModelProperty(value = "客户地址") + private String address; + + @ApiModelProperty(value = "创建时间") + protected Date createTime; + + @ApiModelProperty(value = "创建人") + protected String createUser; + + @ApiModelProperty(value = "更新时间") + protected String updateUser; + + @ApiModelProperty(value = "更新人") + protected Date updateTime; + + @ApiModelProperty(value = "登录时间") + private String loginTime; + + @ApiModelProperty(value = "是否启用") + private String enabled; + + + @ApiModelProperty(value = "手机号") + private String phone; + + + @ApiModelProperty(value = "头像地址") + private String uploadUrl; + + @ApiModelProperty(value = "身份证号") + private String idCard; + +// @ApiModelProperty(value = "手机号群组") +// private List phones; + + + /** + * 货代Id + */ + @ApiModelProperty(value = "货代ID") + private String freightId; + + /** + * 货代Id + */ + @ApiModelProperty(value = "货代类型") + private String freightType; + + /** + * 用户角色id + */ + @ApiModelProperty(value = "用户角色id") + private List roleIds; + + @ApiModelProperty(value = "货代类型") + private String med; + + private String mediaType; + +} diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/VinCheckReq.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/VinCheckReq.java new file mode 100644 index 0000000..b6cc2f2 --- /dev/null +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/VinCheckReq.java @@ -0,0 +1,27 @@ +package com.haitonggauto.rtosc.api.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +@Data +@ApiModel("提离港区车架号验证") +public class VinCheckReq implements Serializable { + @ApiModelProperty("品牌ID") + private String brdId; + + @ApiModelProperty("港区ID") + private String pamId; + + @ApiModelProperty("船舶ID") + private String spmId; + + @ApiModelProperty("航次ID") + private String vvyId; + + @ApiModelProperty("车架号列表") + private List vinCodeList; +} diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/VinCheckResp.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/VinCheckResp.java new file mode 100644 index 0000000..a7061ef --- /dev/null +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/VinCheckResp.java @@ -0,0 +1,20 @@ +package com.haitonggauto.rtosc.api.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +@Data +@ApiModel("提离港区车架号验证") +public class VinCheckResp implements Serializable { + @ApiModelProperty("是否退关扫描") + private Boolean hasShutoutScan; + + @ApiModelProperty("是否无计划收车") + private Boolean noPlanCollect; + + @ApiModelProperty("车架号") + private String vinCode; +} diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/VoyageResp.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/VoyageResp.java index 9479227..eddc57d 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/VoyageResp.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/api/dto/VoyageResp.java @@ -16,6 +16,9 @@ public class VoyageResp { @ApiModelProperty("船舶id") private String spmId; + @ApiModelProperty("港区ID") + private String pamId; + @ApiModelProperty("内贸/外贸/内外贸") private String tradeType; diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/config/InterceptorConfiguration.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/config/InterceptorConfiguration.java index 5522972..b9b2d8e 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/config/InterceptorConfiguration.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/config/InterceptorConfiguration.java @@ -2,7 +2,11 @@ package com.haitonggauto.rtosc.config; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import com.haitonggauto.rtosc.api.NuzarOpenApi; +import com.nuzar.rtops.log.service.SpringApplicationContextHolder; +import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -11,6 +15,7 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import javax.annotation.PostConstruct; +import javax.annotation.Resource; /** * 拦截器的属性配置 @@ -34,12 +39,15 @@ public class InterceptorConfiguration implements WebMvcConfigurer { * @return */ @Bean - public PermInterceptor permInterceptor() { return new PermInterceptor(); } + public PermInterceptor permInterceptor() { + return new PermInterceptor(); + } @Override + @ConditionalOnBean(PermInterceptor.class) public void addInterceptors(InterceptorRegistry registry) { // 拦截器 - InterceptorRegistration registration = registry.addInterceptor(this.permInterceptor()); + InterceptorRegistration registration = registry.addInterceptor(permInterceptor()); } } \ No newline at end of file diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/config/PermInterceptor.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/config/PermInterceptor.java index dd83361..7332240 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/config/PermInterceptor.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/config/PermInterceptor.java @@ -1,15 +1,13 @@ package com.haitonggauto.rtosc.config; +import com.haitonggauto.rtosc.api.NuzarOpenApi; +import com.haitonggauto.rtosc.api.dto.UserInfoDto; import com.haitonggauto.rtosc.common.context.UserContext; import com.haitonggauto.rtosc.common.dto.LoginUser; -import com.haitonggauto.rtosc.common.exception.NoLoginException; -import com.haitonggauto.rtosc.common.exception.NoPermException; -import com.haitonggauto.rtosc.common.handler.anno.HandlerMethod; -import com.haitonggauto.rtosc.common.service.AuthService; -import com.haitonggauto.rtosc.common.utils.MethodInterceptorUtils; -import com.nuzar.common.security5.common.util.SecurityUtils; import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.util.AntPathMatcher; +import org.springframework.web.context.support.WebApplicationContextUtils; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; @@ -19,23 +17,51 @@ import javax.servlet.http.HttpServletResponse; * 权限过滤器 */ public class PermInterceptor implements HandlerInterceptor { + public static final String[] SWAGGER_EXCLUDE_PATHS = {"/doc.html", "/swagger-resources/**", "/webjars/**", "/v2/**", "/favicon.ico", "/swagger-ui.htmL/**", "/health/ping"}; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - //判断是否登录 - String userId = ""; - try { - userId = SecurityUtils.getUserId(); - } catch (Exception e) { -// e.printStackTrace(); - userId = "0"; + String uri = request.getRequestURI(); + AntPathMatcher antPathMatcher = new AntPathMatcher(); + for (String p : SWAGGER_EXCLUDE_PATHS) { + if (antPathMatcher.match(p, uri)) { + return true; + } } - System.err.println(userId); + //判断是否登录 + String userId = ""; + String username = ""; + try { +// userId = SecurityUtils.getUserId(); + + BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext()); + NuzarOpenApi openApi = factory.getBean(NuzarOpenApi.class); + + UserInfoDto info = openApi.getUserInfo(); + + userId = info.getId(); + username = info.getName(); + + if (StringUtils.equalsIgnoreCase(info.getMediaType(), "MINIAPP") && !StringUtils.equalsAny(request.getRequestURI(), "/dd/ship/all" + , "/ee/plan/ship", "/dd/port", "/ee/plan/port", "/dd/brand", "/ee/voyage/brand", "/it/shipVoyage", "/spz/valid-vins")) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + // 可以设置响应体 + response.getWriter().write("Access Forbidden"); + return false; + } + } catch (Exception e) { + throw new RuntimeException(e); +// response.setStatus(HttpServletResponse.SC_FORBIDDEN); +// // 可以设置响应体 +// response.getWriter().write("Access Forbidden"); +// return false; + } LoginUser tmpUser = new LoginUser(); tmpUser.setUserId(userId); tmpUser.setRoleId(0L); + tmpUser.setUsername(username); tmpUser.setAdmin(true); UserContext.setUser(tmpUser); diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/DepartureHandler.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/DepartureHandler.java index d9605f3..ab4466e 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/DepartureHandler.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/DepartureHandler.java @@ -4,9 +4,11 @@ import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.exception.ExcelDataConvertException; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.fill.FillConfig; import com.alibaba.excel.write.metadata.fill.FillWrapper; +import com.alibaba.fastjson2.JSON; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -22,16 +24,14 @@ import com.haitonggauto.rtosc.common.enums.ErrorType; import com.haitonggauto.rtosc.common.handler.BaseHandler; import com.haitonggauto.rtosc.common.utils.*; import com.haitonggauto.rtosc.dto.*; +import com.haitonggauto.rtosc.excel.DepartureImportExcel; +import com.haitonggauto.rtosc.handler.excel.ReadExcelListener; import com.haitonggauto.rtosc.query.CargoQuery; import com.haitonggauto.rtosc.query.DepartureQuery; -import com.haitonggauto.rtosc.query.ExportInCheckQuery; import com.haitonggauto.rtosc.repository.entity.*; import com.haitonggauto.rtosc.handler.mapper.PoMapper; import com.haitonggauto.rtosc.repository.enums.AuditEnum; -import com.haitonggauto.rtosc.repository.service.CustomerDepartureCargoService; -import com.haitonggauto.rtosc.repository.service.CustomerDepartureDriversService; -import com.haitonggauto.rtosc.repository.service.CustomerDeparturePlanService; -import com.haitonggauto.rtosc.repository.service.CustomerDepartureService; +import com.haitonggauto.rtosc.repository.service.*; import com.haitonggauto.rtosc.service.CustomerService; import com.itextpdf.forms.PdfAcroForm; import com.itextpdf.forms.fields.PdfFormField; @@ -51,11 +51,12 @@ import com.itextpdf.layout.layout.LayoutArea; import com.itextpdf.layout.layout.LayoutResult; import com.itextpdf.layout.properties.UnitValue; import com.itextpdf.layout.renderer.DocumentRenderer; -import com.nuzar.common.security5.common.util.SecurityUtils; import com.nuzar.rtops.log.dto.LogRecordDTO; import com.nuzar.rtops.log.service.EsLogApprovalUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; @@ -65,15 +66,18 @@ import org.springframework.core.io.ClassPathResource; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; +import java.io.*; import java.net.URLEncoder; import java.util.*; import java.util.stream.Collectors; @@ -82,6 +86,7 @@ import java.util.stream.Collectors; @RestController @RequestMapping("/ep") @Validated +@Slf4j public class DepartureHandler implements BaseHandler { @Resource @@ -99,6 +104,12 @@ public class DepartureHandler implements BaseHandler { @Resource private CustomerDeparturePlanService departurePlanService; + @Resource + private CustomerExportInCargoService exportInCargoService; + + @Resource + private CustomerExportInService exportInService; + @Resource private NuzarOpenApi openApi; @@ -217,6 +228,32 @@ public class DepartureHandler implements BaseHandler { return ResultUtil.success(rst, String.valueOf(page.getTotal())); } + @ApiOperation("提单号模糊匹配") + @PostMapping("/billNo/query") + public Result> getExportInBillNoList( + @ApiParam(name = "操作方式, 0为前端,1为审核端") @RequestParam(required = false, defaultValue = "0") String type, + @RequestParam(required = false, defaultValue = "1") Integer current, + @RequestParam(required = false, defaultValue = "10") Integer size, + @RequestParam(required = false) String shipId, + @RequestParam(required = false) String voyageId, + @RequestParam(required = false) String q) { + QueryWrapper query = new QueryWrapper<>(); + query.select("distinct bill_no"); + query.eq(StringUtils.equals(type, "0"), "create_by", UserContext.getUser().getUserId()); + query.exists(StringUtils.isNotEmpty(shipId), "select id from customer_departure where departure_id=customer_departure.id and ship_id={0}", shipId); + query.exists(StringUtils.isNotEmpty(voyageId), "select id from customer_departure where departure_id=customer_departure.id and voyage_id={0}", shipId); +// query.eq("create_by", UserContext.getUser().getUserId()); + query.like(StringUtils.isNotEmpty(q), "bill_no", q); + + Page page = departureCargoService.page(new Page<>(current, size), query); + List list = page.getRecords(); + + List rst = list.stream().map(tmp -> tmp.getBillNo()).collect(Collectors.toList()); + + + return ResultUtil.success(rst, String.valueOf(page.getTotal())); + } + /** * 分页查询 * @param query @@ -324,6 +361,10 @@ public class DepartureHandler implements BaseHandler { return entity; }).collect(Collectors.toList()); + departure.setQuantity(cargos.size()); + departure.setSpareQuantity((int)cargos.stream().filter(s -> StringUtils.startsWith(s.getVin(), "BJ")).count()); + departure.setCarQuantity(departure.getQuantity() - departure.getSpareQuantity()); + List drivers = form.getDrivers().stream().map(item -> { CustomerDepartureDrivers entity = PoMapper.instance.departureDriverVo2Entity(item); entity.setTermcd(departure.getPortAreaId()); @@ -336,6 +377,11 @@ public class DepartureHandler implements BaseHandler { return entity; }).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(plans)) { + String collect = plans.stream().filter(s -> StringUtils.isNotEmpty(s.getMachine())).map(s -> s.getMachine()).collect(Collectors.joining(",")); + departure.setWorkStatus(collect); + } + Long id = customerService.saveDeparture(departure, cargos, drivers, plans); return ResultUtil.success(String.valueOf(id)); @@ -352,7 +398,7 @@ public class DepartureHandler implements BaseHandler { .in("vin", vo.getVins()) .exists("select id from customer_departure where customer_departure.id=customer_departure_cargo.departure_id and customer_departure.voyage_id={0}", vo.getVoyageId()) .groupBy("vin") - .having("count(quantity) > 1") + .having("count(*) > 1") .list(); rst.put(vo.getVoyageId(), cargos.stream().map(item -> item.getVin()).collect(Collectors.toList())); } @@ -366,7 +412,7 @@ public class DepartureHandler implements BaseHandler { .select("count(*) as quantity, vin") .in("vin", vins) .groupBy("vin") - .having("count(quantity) > 0") + .having("count(*) > 0") .list(); return ResultUtil.success(cargos.stream().map(item -> item.getVin()).collect(Collectors.toList())); } @@ -475,6 +521,10 @@ public class DepartureHandler implements BaseHandler { return entity; }).collect(Collectors.toList()); + departure.setQuantity(cargos.size()); + departure.setSpareQuantity((int)cargos.stream().filter(s -> StringUtils.startsWith(s.getVin(), "BJ")).count()); + departure.setCarQuantity(departure.getQuantity() - departure.getSpareQuantity()); + List drivers = form.getDrivers().stream().map(item -> { CustomerDepartureDrivers entity = PoMapper.instance.departureDriverVo2Entity(item); entity.setTermcd(departure.getPortAreaId()); @@ -487,6 +537,11 @@ public class DepartureHandler implements BaseHandler { return entity; }).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(plans)) { + String collect = plans.stream().filter(s -> StringUtils.isNotEmpty(s.getMachine())).map(s -> s.getMachine()).collect(Collectors.joining(",")); + departure.setWorkStatus(collect); + } + customerService.updateDeparture(false, departure, cargos, drivers, plans); return ResultUtil.success(String.valueOf(departure.getId())); @@ -572,6 +627,16 @@ public class DepartureHandler implements BaseHandler { customerService.wrapperEntity(cargos); + // 获取进港时间 + Map carPickTime = openApi.getCarPickTime(cargos.stream().map(s -> s.getVin()).collect(Collectors.toList())); + if (MapUtils.isNotEmpty(carPickTime)) { + cargos.stream().forEach(s -> { + if (carPickTime.containsKey(s.getVin()) && carPickTime.get(s.getVin()) != null) { + s.setCarPickTime(DateUtils.formatDate(carPickTime.get(s.getVin()))); + } + }); + } + List drivers = departureDriversService.list(new LambdaQueryWrapper().eq(CustomerDepartureDrivers::getDepartureId, id)); customerService.wrapperEntity(drivers); @@ -632,13 +697,23 @@ public class DepartureHandler implements BaseHandler { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); queryWrapper.eq(query.getId() != null, CustomerDepartureCargo::getDepartureId, query.getId()); if (query.getCargoType() != null) { - queryWrapper.eq(query.getCargoType() != null, CustomerDepartureCargo::getCargoType, query.getCargoType()); + queryWrapper.eq(query.getCargoType() != null, CustomerDepartureCargo::getCartType, query.getCargoType()); } Page page = departureCargoService.page(new Page<>(query.getPage(), query.getRows()), queryWrapper); customerService.wrapperEntity(page.getRecords()); if (CollectionUtils.isNotEmpty(page.getRecords())) { + // 获取进港时间 + Map carPickTime = openApi.getCarPickTime(page.getRecords().stream().map(s -> s.getVin()).collect(Collectors.toList())); + if (MapUtils.isNotEmpty(carPickTime)) { + page.getRecords().stream().forEach(s -> { + if (carPickTime.containsKey(s.getVin()) && carPickTime.get(s.getVin()) != null) { + s.setCarPickTime(DateUtils.formatDate(carPickTime.get(s.getVin()))); + } + }); + } + CustomerDeparture departure = departureService.getById(page.getRecords().get(0).getDepartureId()); // 获取作业状态 @@ -699,8 +774,8 @@ public class DepartureHandler implements BaseHandler { log.setOperateData(l); log.setStatus(check.getCheckStatus() == AuditEnum.AUDIT_PASS ? 0 : 1); log.setOperateTime(new Date()); - log.setUserId(SecurityUtils.getUserId()); - log.setUserName(SecurityUtils.getUserName()); + log.setUserId(UserContext.getUser().getUserId()); + log.setUserName(UserContext.getUser().getUsername()); EsLogApprovalUtil.writeLog(log); } } @@ -755,8 +830,8 @@ public class DepartureHandler implements BaseHandler { log.setOperateData(l); log.setStatus(check.getCheckStatus() == AuditEnum.AUDIT_PASS ? 0 : 1); log.setOperateTime(new Date()); - log.setUserId(SecurityUtils.getUserId()); - log.setUserName(SecurityUtils.getUserName()); + log.setUserId(UserContext.getUser().getUserId()); + log.setUserName(UserContext.getUser().getUsername()); EsLogApprovalUtil.writeLog(log); } } @@ -820,6 +895,7 @@ public class DepartureHandler implements BaseHandler { // 查询出要加载的数据 List departures = departureService.list(new LambdaQueryWrapper().in(CustomerDeparture::getBatchNo, nos)); + customerService.wrapperEntity(departures); ExcelWriter excelWriter = null; try(ByteArrayOutputStream bos = new ByteArrayOutputStream()){ @@ -863,18 +939,19 @@ public class DepartureHandler implements BaseHandler { // 简单的说 如果你的模板有list,且list不是最后一行,下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存 // 如果数据量大 list不是最后一行 参照下一个 - FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); + FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.FALSE).build(); List before = CollectionUtil.sub(plans, 0, 1); - List after = CollectionUtil.sub(plans, 1, plans.size() - 1); + List after = CollectionUtil.sub(plans, 1, plans.size()); excelWriter.fill(new FillWrapper("plan", before), writeSheet); excelWriter.fill(new FillWrapper("plan", after), fillConfig, writeSheet); Map map = new HashMap<>(); - map.put("batchNo", departures.get(i).getBatchNo()); // {batchNo} +// map.put("batchNo", departures.get(i).getBatchNo()); // {batchNo} map.put("receiveCompany", departures.get(i).getReceiveCompany()); // {receiveCompany} //{applicant} - map.put("applicant", departures.get(i).getApplicant()); + map.put("applicant", departures.get(i).getCheckMan()); + map.put("remark", departures.get(i).getRemark()); //{applyTime} map.put("applyTime", departures.get(i).getApplyTime()); //{shipName} @@ -933,10 +1010,13 @@ public class DepartureHandler implements BaseHandler { List cargos = departureCargoService.list(new LambdaQueryWrapper().eq(CustomerDepartureCargo::getDepartureId, departure.getId())); - Integer num = cargos.stream().mapToInt(CustomerDepartureCargo::getQuantity).sum(); + Integer num = cargos.size(); List drivers = departureDriversService.list(new LambdaQueryWrapper().eq(CustomerDepartureDrivers::getDepartureId, departure.getId())); + // 获取进港时间 + Map carPickTime = openApi.getCarPickTime(cargos.stream().map(s -> s.getVin()).collect(Collectors.toList())); + PdfDocument pdfDoc = new PdfDocument(new PdfReader(inputStream), new PdfWriter(response.getOutputStream())); org.springframework.core.io.Resource resource = new ClassPathResource("templates/SourceHanSansCN-Regular.ttf"); @@ -944,20 +1024,24 @@ public class DepartureHandler implements BaseHandler { byte[] bytes = IOUtils.toByteArray(stream); PdfFont font = PdfFontFactory.createFont(bytes, PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED); + PdfFont enFont = PdfFontFactory.createFont(); + PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, false); Map fields = form.getFormFields(); fields.get("batchNo").setValue(departure.getBatchNo()).setFont(font).setFontSize(12); fields.get("shipName").setValue(departure.getShipName()).setFont(font).setFontSize(12); - fields.get("voyage").setValue(departure.getVoyage()).setFont(font).setFontSize(12); + fields.get("voyage").setValue(StringUtils.isNotEmpty(departure.getVoyage()) ? departure.getVoyage() : "").setFont(font).setFontSize(12); fields.get("arrivalTime").setValue(DateUtil.format(departure.getArrivalTime(), "yyyy-MM-dd")).setFont(font).setFontSize(12); fields.get("deliveryTime").setValue(DateUtil.format(departure.getDeliveryTime(), "yyyy-MM-dd")).setFont(font).setFontSize(12); - fields.get("returnTime").setValue(DateUtil.format(departure.getReturnTime(), "yyyy-MM-dd")).setFont(font).setFontSize(12); - fields.get("num").setValue(String.valueOf(num)).setFont(font).setFontSize(12); - if (StringUtils.isNotEmpty(departure.getRemark())) { - fields.get("remark").setValue(departure.getRemark()).setFont(font).setFontSize(12); + if (departure.getReturnTime() != null) { + fields.get("returnTime").setValue(DateUtil.format(departure.getReturnTime(), "yyyy-MM-dd")).setFont(font).setFontSize(12); } + fields.get("num").setValue(String.valueOf(num)).setFont(font).setFontSize(12); + fields.get("brand").setValue(StringUtils.isNotEmpty(departure.getBrand()) ? departure.getBrand() : "").setFont(font).setFontSize(12); + fields.get("remark").setValue(StringUtils.isNotEmpty(departure.getRemark()) ? departure.getRemark() : "").setFont(font).setFontSize(12); + fields.get("reason").setValue(StringUtils.isNotEmpty(departure.getReason()) ? departure.getReason() : "").setFont(font).setFontSize(12); Table driverTable = new Table(UnitValue.createPercentArray(new float[] {30f, 50f, 50f})); driverTable.addHeaderCell(new Cell().add(new Paragraph("司机姓名").setFont(font))); @@ -969,18 +1053,30 @@ public class DepartureHandler implements BaseHandler { driverTable.addCell(new Paragraph(driver.getContactPhone()).setFont(font)); }); - Table cargoTable = new Table(UnitValue.createPercentArray(new float[] {30f, 50f, 50f, 50f, 50f})); + Table cargoTable = new Table(UnitValue.createPercentArray(new float[] {30f, 50f, 50f, 50f, 50f, 50f, 50f, 50f, 50f,50f})); + cargoTable.addHeaderCell(new Cell().add(new Paragraph("提单号").setFont(font))); - cargoTable.addHeaderCell(new Cell().add(new Paragraph("品牌").setFont(font))); - cargoTable.addHeaderCell(new Cell().add(new Paragraph("货物类型").setFont(font))); cargoTable.addHeaderCell(new Cell().add(new Paragraph("车架号").setFont(font))); - cargoTable.addHeaderCell(new Cell().add(new Paragraph("数量").setFont(font))); + cargoTable.addHeaderCell(new Cell().add(new Paragraph("车型").setFont(font))); + cargoTable.addHeaderCell(new Cell().add(new Paragraph("型号").setFont(font))); + cargoTable.addHeaderCell(new Cell().add(new Paragraph("通关性质").setFont(font))); + cargoTable.addHeaderCell(new Cell().add(new Paragraph("尺寸(米)").setFont(font))); + cargoTable.addHeaderCell(new Cell().add(new Paragraph("重量(KG)").setFont(font))); + cargoTable.addHeaderCell(new Cell().add(new Paragraph("是否退关提离").setFont(font))); + cargoTable.addHeaderCell(new Cell().add(new Paragraph("是否随车备件").setFont(font))); + cargoTable.addHeaderCell(new Cell().add(new Paragraph("进港时间").setFont(font))); + cargos.stream().forEach(cargo -> { cargoTable.addCell(new Paragraph(cargo.getBillNo()).setFont(font)); - cargoTable.addCell(new Paragraph(cargo.getBrand()).setFont(font)); - cargoTable.addCell(new Paragraph(cargo.getCargoType()).setFont(font)); cargoTable.addCell(cargo.getVin()); - cargoTable.addCell(String.valueOf(cargo.getQuantity())); + cargoTable.addCell(new Paragraph(StringUtils.isNotEmpty(cargo.getCartType()) ? cargo.getCartType() : "").setFont(font)); + cargoTable.addCell(new Paragraph(StringUtils.isNotEmpty(cargo.getModels()) ? cargo.getModels() : "").setFont(font)); + cargoTable.addCell(new Paragraph(cargo.getIsCustoms() != null ? (cargo.getIsCustoms() == 0 ? "未报关" : "已报关") : "").setFont(font)); + cargoTable.addCell(new Paragraph((cargo.getLength() != null && cargo.getWidth() != null && cargo.getHeight() != null) ? StringUtils.join(cargo.getLength(), "*", cargo.getWidth(), "\n*", cargo.getHeight()) : "").setFont(enFont)); + cargoTable.addCell(new Paragraph(cargo.getWeight() != null ? cargo.getWeight().toString() : "").setFont(font)); + cargoTable.addCell(new Paragraph(cargo.getIsShutout() != null ? (cargo.getIsShutout() == 0 ? "否" : "是") : "").setFont(font)); + cargoTable.addCell(new Paragraph(cargo.getIsSpare() != null ? (cargo.getIsSpare() == 0 ? "否" : "是") : "").setFont(font)); + cargoTable.addCell(new Paragraph(carPickTime != null && carPickTime.containsKey(cargo.getVin()) && carPickTime.get(cargo.getVin()) != null ? DateUtils.formatDate(carPickTime.get(cargo.getVin())) : "").setFont(font)); }); final Document doc = new Document(pdfDoc); @@ -1010,4 +1106,223 @@ public class DepartureHandler implements BaseHandler { doc.close(); } + + @ApiOperation("提离港区导入模板下载") + @GetMapping("/temp/down") + public void tempDownPlan(HttpServletResponse response) throws Exception { + // 加载模板 + ClassPathResource classPathResource = new ClassPathResource("templates/departure_temp.xlsx"); + InputStream inputStream = classPathResource.getInputStream(); + + XSSFWorkbook workbook = new XSSFWorkbook(inputStream); + + OutputStream out = response.getOutputStream(); + try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + + // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman + response.setContentType("application/vnd.ms-excel"); + response.setCharacterEncoding("utf-8"); + // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 + String fileName = URLEncoder.encode("提离港区导入模板", "UTF-8"); + response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); + + workbook.write(bos); + byte[] bArray = bos.toByteArray(); + InputStream is = new ByteArrayInputStream(bArray); + org.apache.commons.io.IOUtils.copy(is, out); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (out != null) { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + @ApiOperation("通过车架号获取信息") + @PostMapping("/getInfoByVin") + public Result getInfoByVin(@RequestParam(required = false) @NotBlank(message = "船ID不能为空") @ApiParam("船ID") String shipId, + @RequestParam(required = false) @NotBlank(message = "航次ID不能为空") @ApiParam("航次ID") String voyageId, + @RequestParam(required = false) @NotBlank(message = "港区ID不能为空") @ApiParam("港区ID") String portAreaId, + @RequestParam(required = false) @NotBlank(message = "品牌ID不能为空") @ApiParam("品牌ID") String brandId, + @RequestParam(required = false) @NotBlank(message = "提单号不能为空") @ApiParam("提单号") String billNo, + @RequestParam(required = false) @NotBlank(message = "车架号不能为空") @ApiParam("车架号") String vin) { + DepartureValidVo form = new DepartureValidVo(); + form.setBrandId(brandId); + form.setShipId(shipId); + form.setVoyageId(voyageId); + form.setPortAreaId(portAreaId); + DepartureValidVo.BillVin bvin = new DepartureValidVo.BillVin(); + bvin.setBillNo(billNo); + bvin.setVin(vin); + form.setVins(Arrays.asList(bvin)); + + Result> mapResult = this.validVins(form); + if (mapResult.getCode() != 0) { // 验证失败 + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), mapResult.getMsg()); + } + + return ResultUtil.success(mapResult.getData().get(vin)); + } + + @ApiOperation("提离港区导入") + @PostMapping("/import") + public Result> importExcel(@RequestParam(required = false) @NotBlank(message = "船ID不能为空") @ApiParam("船ID") String shipId, + @RequestParam(required = false) @NotBlank(message = "航次ID不能为空") @ApiParam("航次ID") String voyageId, + @RequestParam(required = false) @NotBlank(message = "港区ID不能为空") @ApiParam("港区ID") String portAreaId, + @RequestParam(required = false) @NotBlank(message = "品牌ID不能为空") @ApiParam("品牌ID") String brandId, + MultipartFile file) { + try { + // 所有读取的数据 + List dataList = new ArrayList<>(); + + EasyExcel.read(file.getInputStream(), DepartureImportExcel.class, new ReadExcelListener() { + @Override + protected void saveData(List list) { // 缓存数据 + dataList.addAll(list); + } + }).sheet().doRead(); + + if (CollectionUtils.isEmpty(dataList)) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "没有读取到数据"); + } + + ValidatorFactory vf = Validation.buildDefaultValidatorFactory(); + Validator validator = vf.getValidator(); + + // 数据验证 + for (DepartureImportExcel item : dataList) { + Set> set = validator.validate(item); + if (CollectionUtils.isNotEmpty(set)) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), set.stream().map(p -> p.getMessage()).collect(Collectors.joining(","))); + } + } + + DepartureValidVo form = new DepartureValidVo(); + form.setBrandId(brandId); + form.setShipId(shipId); + form.setVoyageId(voyageId); + form.setPortAreaId(portAreaId); + + List billVins = dataList.stream().map(item -> { + DepartureValidVo.BillVin vin = new DepartureValidVo.BillVin(); + vin.setBillNo(item.getBillNo()); + vin.setVin(item.getVin()); + return vin; + }).collect(Collectors.toList()); + + form.setVins(billVins); + + Result> mapResult = this.validVins(form); + if (mapResult.getCode() != 0) { // 验证失败 + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), mapResult.getMsg()); + } + + dataList.stream().forEach(item -> { + if (mapResult.getData().containsKey(item.getVin())) { + CustomerExportIn in = mapResult.getData().get(item.getVin()); + item.setCartType(in.getCartType()); + item.setModels(in.getModels()); + item.setHeight(in.getHeight()); + item.setLength(in.getLength()); + item.setWidth(in.getWidth()); + item.setWeight(in.getWeight()); + } + }); + + return ResultUtil.success(dataList); + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:" + e.getRowIndex() + " 列:" + e.getColumnIndex()); + } catch (Exception e) { + log.error("错误信息", e); + return ResultUtil.failure(ErrorType.PROGRAM_ERROR.id(), e.getMessage()); + } + } + + @ApiOperation("车架号验证") + @PostMapping("/vin/valid") + public Result> validVins(@RequestBody @Validated DepartureValidVo form) { + Map rst = new HashMap<>(); + // 所有车架号 + List vins = form.getVins().stream().map(s -> s.getVin()).collect(Collectors.toList()); + // 根据车架号查询进港申请 + List list = exportInCargoService.lambdaQuery() + .in(CustomerExportInCargo::getVin, vins) + .exists("select id from customer_export_in B where B.id=customer_export_in_cargo.export_in_id and B.ship_id={0} and B.voyage_id={1} and port_area_id={2} and brand_id={3} and check_status={4}", + form.getShipId(), form.getVoyageId(), form.getPortAreaId(), form.getBrandId(), AuditEnum.AUDIT_PASS).list(); + // 有进港计划的 + List strings = list.stream().map(s -> s.getVin()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(strings)) { + // 检验提单号是否属于这个账号 + List userBindFreight = openApi.getUserBindFreight(); + List ids = list.stream().map(s -> s.getExportInId()).distinct().collect(Collectors.toList()); + List exportIns = exportInService.lambdaQuery().in(CustomerExportIn::getId, ids).list(); + // 账号不一致的 + List ins = exportIns.stream().filter(item -> CollectionUtils.isEmpty(userBindFreight) || userBindFreight.stream().filter(s -> StringUtils.equalsAny(item.getFreightId(), s.getCueId())).count() == 0).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(ins)) { + // 提示车架号不存在 + List longs = ins.stream().map(s -> s.getId()).collect(Collectors.toList()); + String collect = list.stream().filter(s -> longs.contains(s.getExportInId())).map(s -> s.getVin()).collect(Collectors.joining(",")); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "车架号"+collect+"不存在"); + } + + // 提单号与车架号是否匹配 + Map stringMap = form.getVins().stream().collect(Collectors.toMap(s -> s.getVin(), s -> s.getBillNo())); + Map exportInMap = exportIns.stream().collect(Collectors.toMap(s -> s.getId(), s -> s.getBillNum())); + Map longMap = list.stream().collect(Collectors.toMap(s -> s.getVin(), s -> s.getExportInId())); + List collect = strings.stream().filter(s -> !StringUtils.equals(stringMap.get(s), exportInMap.get(longMap.get(s)))).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(collect)) { + String s1 = collect.stream().map(s -> "车架号" + s + "与提单号" + stringMap.get(s) + "不匹配").collect(Collectors.joining(",")); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), s1); + } + + // 是否做过退关退运扫描 + VinCheckReq req = new VinCheckReq(); + req.setPamId(form.getPortAreaId()); + req.setBrdId(form.getBrandId()); + req.setSpmId(form.getShipId()); + req.setVvyId(form.getVoyageId()); + req.setVinCodeList(strings); + List resp = openApi.vinCheckInfo(req); + System.err.println(JSON.toJSONString(req)); + System.err.println(JSON.toJSONString(resp)); + + List checkResps = resp.stream().filter(s -> !s.getHasShutoutScan()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(checkResps)) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), checkResps.stream().map(s -> s.getVinCode()).collect(Collectors.joining(",")) + "暂无提离车辆信息,请联系码头确认"); + } + + list.stream().forEach(s -> { + rst.put(s.getVin(), exportIns.stream().filter(i -> Long.compare(i.getId(), s.getExportInId()) == 0).findFirst().get()); + }); + } + // 没有进港计划的 + List noVins = vins.stream().filter(s -> !strings.contains(s)).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(noVins)) { + // 是否做过退关退运扫描 + VinCheckReq req = new VinCheckReq(); + req.setPamId(form.getPortAreaId()); + req.setBrdId(form.getBrandId()); + req.setSpmId(form.getShipId()); + req.setVvyId(form.getVoyageId()); + req.setVinCodeList(noVins); + List resp = openApi.vinCheckInfo(req); + + List checkResps = resp.stream().filter(s -> !s.getNoPlanCollect()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(checkResps)) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), checkResps.stream().map(s -> s.getVinCode()).collect(Collectors.joining(",")) + "车架号不正确"); + } + + checkResps = resp.stream().filter(s -> !s.getHasShutoutScan()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(checkResps)) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), checkResps.stream().map(s -> s.getVinCode()).collect(Collectors.joining(",")) + "暂无提离车辆信息,请联系码头确认"); + } + } + + return ResultUtil.success(rst); + } } diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ExportInHandler.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ExportInHandler.java index 105c87e..bb14d27 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ExportInHandler.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ExportInHandler.java @@ -5,8 +5,12 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.RandomUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.exception.ExcelDataConvertException; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.fastjson2.JSONObject; +import com.alicp.jetcache.Cache; +import com.alicp.jetcache.anno.CacheType; +import com.alicp.jetcache.anno.CreateCache; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -27,10 +31,7 @@ import com.haitonggauto.rtosc.common.utils.*; import com.haitonggauto.rtosc.dto.*; import com.haitonggauto.rtosc.excel.*; import com.haitonggauto.rtosc.handler.excel.ExcelMergeUtil; -import com.haitonggauto.rtosc.handler.excel.ExcelValidationUtils; -import com.haitonggauto.rtosc.query.CargoQuery; -import com.haitonggauto.rtosc.query.ExportInCheckQuery; -import com.haitonggauto.rtosc.query.ExportInQuery; +import com.haitonggauto.rtosc.query.*; import com.haitonggauto.rtosc.repository.entity.*; import com.haitonggauto.rtosc.handler.excel.ReadExcelListener; import com.haitonggauto.rtosc.handler.mapper.PoMapper; @@ -38,7 +39,6 @@ import com.haitonggauto.rtosc.repository.enums.AuditEnum; import com.haitonggauto.rtosc.repository.query.PrintQuery; import com.haitonggauto.rtosc.repository.service.*; import com.haitonggauto.rtosc.service.CustomerService; -import com.nuzar.common.security5.common.util.SecurityUtils; import com.nuzar.rtops.log.dto.LogRecordDTO; import com.nuzar.rtops.log.service.EsLogApprovalUtil; import io.swagger.annotations.Api; @@ -50,6 +50,8 @@ import org.apache.commons.collections4.MapUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.poi.xssf.usermodel.*; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; import org.springframework.core.io.ClassPathResource; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -70,6 +72,7 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.net.URLEncoder; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @@ -80,6 +83,9 @@ import java.util.stream.Collectors; @Slf4j public class ExportInHandler implements BaseHandler { + @Resource + private RedissonClient redissonClient; + @Resource private CustomerService customerService; @@ -107,6 +113,9 @@ public class ExportInHandler implements BaseHandler { @Resource private NuzarPubApi pubApi; + @CreateCache(name="bj_gen:", cacheType = CacheType.REMOTE, expire = 1, timeUnit = TimeUnit.MINUTES) + private Cache> bjNumCache; + @ApiOperation("船名航次模糊匹配") @PostMapping("/shipVoyage") public Result> getExportInShipNameList( @@ -208,16 +217,40 @@ public class ExportInHandler implements BaseHandler { @RequestParam(required = false) String shipName, @RequestParam(required = false) String voyage, @RequestParam(required = false) String q) { - LambdaQueryWrapper query = new LambdaQueryWrapper<>(); - query.eq(CustomerExportIn::getCreateBy, UserContext.getUser().getUserId()); - query.eq(StringUtils.isNotEmpty(shipName), CustomerExportIn::getShipName, shipName); - query.eq(StringUtils.isNotEmpty(voyage), CustomerExportIn::getVoyage, voyage); - query.like(StringUtils.isNotEmpty(q), CustomerExportIn::getBillNum, q); // 提单号 + QueryWrapper query = new QueryWrapper<>(); + query.select("distinct bill_num"); + query.eq("create_by", UserContext.getUser().getUserId()); + query.eq(StringUtils.isNotEmpty(shipName), "ship_name", shipName); + query.eq(StringUtils.isNotEmpty(voyage), "voyage", voyage); + query.like(StringUtils.isNotEmpty(q), "bill_num", q); Page page = customerExportInService.page(new Page<>(current, size), query); List list = page.getRecords(); - List rst = list.stream().map(item -> item.getBillNum()).collect(Collectors.toList()); + List rst = list.stream().map(tmp -> tmp.getBillNum()).collect(Collectors.toList()); + + + return ResultUtil.success(rst, String.valueOf(page.getTotal())); + } + + @ApiOperation("审核端提单号") + @PostMapping("/check/billNo/query") + public Result> getCheckExportInBillNoList( + @RequestParam(required = false, defaultValue = "1") Integer current, + @RequestParam(required = false, defaultValue = "10") Integer size, + @RequestParam(required = false) String shipId, + @RequestParam(required = false) String voyageId, + @RequestParam(required = false) String q) { + QueryWrapper query = new QueryWrapper<>(); + query.select("distinct bill_num"); + query.eq(StringUtils.isNotEmpty(shipId), "ship_id", shipId); + query.eq(StringUtils.isNotEmpty(voyageId), "voyage_id", voyageId); + query.like(StringUtils.isNotEmpty(q), "bill_num", q); + + Page page = customerExportInService.page(new Page<>(current, size), query); + List list = page.getRecords(); + + List rst = list.stream().map(tmp -> tmp.getBillNum()).collect(Collectors.toList()); return ResultUtil.success(rst, String.valueOf(page.getTotal())); } @@ -261,9 +294,9 @@ public class ExportInHandler implements BaseHandler { @ApiOperation("条件分页查询") @PostMapping("/query-list") public Result> query(@RequestBody ExportInQuery query) { - if (query.getEndEnterTime() != null) { - query.setEndEnterTime(DateUtils.getDayEnd(query.getEndEnterTime())); - } +// if (query.getEndEnterTime() != null) { +// query.setEndEnterTime(DateUtils.getDayEnd(query.getEndEnterTime())); +// } query.setCreateBy(UserContext.getUser().getUserId()); Wrapper queryWrapper = new WrapperKit() { }.changeBaseQueryToWrapper(CustomerExportIn.class, query); @@ -277,38 +310,52 @@ public class ExportInHandler implements BaseHandler { @ApiOperation("审核端条件分页查询") @PostMapping("/check/query-list") public Result> checkQuery(@RequestBody ExportInCheckQuery query) { - if (query.getEndEnterTime() != null) { - query.setEndEnterTime(DateUtils.getDayEnd(query.getEndEnterTime())); - } + long b = System.currentTimeMillis(); + Boolean vinStatus = query.getVinStatus(); + query.setVinStatus(null); if (query.getCheckStatus() == null) { query.setCheckStatusList(Arrays.asList(AuditEnum.SUBMIT, AuditEnum.AUDIT, AuditEnum.AUDIT_PASS, AuditEnum.AUDIT_REJECT)); } - Wrapper queryWrapper = new WrapperKit() { + Date beginEnterDate = query.getBeginEnterTime(); + Date endEnterDate = query.getEndEnterTime(); + query.setBeginEnterTime(null); + query.setEndEnterTime(null); + //搜索进场开始日期<=进场开始时间&&搜索进场结束时间>=进场开始时间 || 搜索进场开始日期<=进场结束时间&&搜索进场结束时间>=进场结束时间 + QueryWrapper queryWrapper = (QueryWrapper) new WrapperKit() { }.changeBaseQueryToWrapper(CustomerExportIn.class, query); + queryWrapper.ge(beginEnterDate != null, "begin_enter_time", beginEnterDate) + .le(endEnterDate != null, "end_enter_time", endEnterDate); +// queryWrapper.and(beginEnterDate != null || endEnterDate != null, (q) -> { +// q.and(beginEnterDate != null, (t) -> { +// t.ge("begin_enter_time", beginEnterDate).le("begin_enter_time", endEnterDate); +// }).or(endEnterDate != null, (s) -> { +// s.ge("end_enter_time", beginEnterDate).le("end_enter_time", endEnterDate); +// }); +// }); Page page = customerExportInService.page(new Page<>(query.getPage(), query.getRows()), queryWrapper); customerService.wrapperEntity(page.getRecords()); + log.info("进港计划查询,接口调用前,查询耗时:" + (System.currentTimeMillis() - b)); + long b1 = System.currentTimeMillis(); // 处理是否生成装船计划 - if(CollectionUtils.isNotEmpty(page.getRecords())) { - Map> map = new HashMap<>(); + if (CollectionUtils.isNotEmpty(page.getRecords())) { List collect = page.getRecords().stream().map(item -> item.getVoyageId()).distinct().collect(Collectors.toList()); - for (String v : collect) { - List list = openApi.haveShipPlan(v); - map.put(v, CollectionUtils.isNotEmpty(list) ? list : Collections.emptyList()); - } + CheckShipPlanReq req = new CheckShipPlanReq(); + req.setVvyIds(collect); + Map> list = openApi.haveShipPlans(req); page.getRecords().stream().forEach(item -> { - item.setShipPlan(map.get(item.getVoyageId()).contains(item.getId())); + item.setShipPlan((MapUtils.isNotEmpty(list) && list.containsKey(item.getVoyageId())) ? list.get(item.getVoyageId()).contains(item.getId()) : false); }); } - + log.info("进港计划查询,接口调用耗时:" + (System.currentTimeMillis() - b1)); + log.info("进港计划查询,总耗时:" + (System.currentTimeMillis() - b)); return ResultUtil.success(page); } @ApiOperation("出口进港货物跟踪查询") @PostMapping("/cargo/tracking") public Result> cargoTracking(@RequestBody ExportInCheckQuery query) { - if (query.getEndEnterTime() != null) { - query.setEndEnterTime(DateUtils.getDayEnd(query.getEndEnterTime())); - } + Boolean vinStatus = query.getVinStatus(); + query.setVinStatus(null); // if (query.getCheckStatus() == null) { // query.setCheckStatusList(Arrays.asList(AuditEnum.AUDIT, AuditEnum.AUDIT_PASS, AuditEnum.AUDIT_REJECT)); // } @@ -322,8 +369,21 @@ public class ExportInHandler implements BaseHandler { // 条件过滤查询 + Date beginEnterDate = query.getBeginEnterTime(); + Date endEnterDate = query.getEndEnterTime(); + query.setBeginEnterTime(null); + query.setEndEnterTime(null); QueryWrapper queryWrapper = (QueryWrapper) new WrapperKit() { }.changeBaseQueryToWrapper(CustomerExportIn.class, query); + queryWrapper.ge(beginEnterDate != null, "begin_enter_time", beginEnterDate) + .le(endEnterDate != null, "end_enter_time", endEnterDate); +// queryWrapper.and(beginEnterDate != null || endEnterDate != null, (q) -> { +// q.and(beginEnterDate != null, (t) -> { +// t.ge("begin_enter_time", beginEnterDate).le("begin_enter_time", endEnterDate); +// }).or(endEnterDate != null, (s) -> { +// s.ge("end_enter_time", beginEnterDate).le("end_enter_time", endEnterDate); +// }); +// }); queryWrapper.select("sum(quantity) as quantity, port_area_id, ship_id, voyage_id, max(update_date) as update_date"); queryWrapper.groupBy("port_area_id, ship_id, voyage_id"); @@ -357,17 +417,30 @@ public class ExportInHandler implements BaseHandler { @ApiOperation("审核端统计查询") @PostMapping("/check/query-list/count") public Result> checkCountQuery(@RequestBody ExportInCheckQuery query) { - if (query.getEndEnterTime() != null) { - query.setEndEnterTime(DateUtils.getDayEnd(query.getEndEnterTime())); - } + Boolean vinStatus = query.getVinStatus(); + query.setVinStatus(null); if (query.getCheckStatus() == null) { query.setCheckStatusList(Arrays.asList(AuditEnum.SUBMIT, AuditEnum.AUDIT, AuditEnum.AUDIT_PASS, AuditEnum.AUDIT_REJECT)); } query.setSorts(null); + Date beginEnterDate = query.getBeginEnterTime(); + Date endEnterDate = query.getEndEnterTime(); + query.setBeginEnterTime(null); + query.setEndEnterTime(null); QueryWrapper queryWrapper = (QueryWrapper) new WrapperKit() { }.changeBaseQueryToWrapper(CustomerExportIn.class, query); + //搜索进场开始日期<=进场开始时间&&搜索进场结東时间>=进场结東时间 + queryWrapper.ge(beginEnterDate != null, "begin_enter_time", beginEnterDate) + .le(endEnterDate != null, "end_enter_time", endEnterDate); +// queryWrapper.and(beginEnterDate != null || endEnterDate != null, (q) -> { +// q.and(beginEnterDate != null, (t) -> { +// t.ge("begin_enter_time", beginEnterDate).le("begin_enter_time", endEnterDate); +// }).or(endEnterDate != null, (s) -> { +// s.ge("end_enter_time", beginEnterDate).le("end_enter_time", endEnterDate); +// }); +// }); queryWrapper.select("sum(quantity) as quantity, sum(volume) as volume, sum(weight) as weight, sum(length) as length, sum(width) as width, sum(height) as height"); @@ -376,24 +449,92 @@ public class ExportInHandler implements BaseHandler { return ResultUtil.success(map); } + @ApiOperation("审核通过,且未有装船计划的进港计划列表") + @PostMapping("/auditPassAndNoPlan/list") + public Result> dataList(@RequestBody ExportInQueryVo query) { + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(StringUtils.isNotEmpty(query.getShipId()), CustomerExportIn::getShipId, query.getShipId()) + .eq(StringUtils.isNotEmpty(query.getVoyageId()), CustomerExportIn::getVoyageId, query.getVoyageId()) + .in(CollectionUtils.isNotEmpty(query.getBillNums()), CustomerExportIn::getBillNum, query.getBillNums()) + .eq(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_PASS); + List list = customerExportInService.list(wrapper); + customerService.wrapperEntity(list); + // 处理是否生成装船计划 + if (CollectionUtils.isNotEmpty(list)) { + List collect = list.stream().map(item -> item.getVoyageId()).distinct().collect(Collectors.toList()); + CheckShipPlanReq req = new CheckShipPlanReq(); + req.setVvyIds(collect); + Map> pList = openApi.haveShipPlans(req); + + list.stream().forEach(item -> { + item.setShipPlan((MapUtils.isNotEmpty(pList) && pList.containsKey(item.getVoyageId())) ? pList.get(item.getVoyageId()).contains(item.getId()) : false); + }); + } + + List rst = list.stream().filter(item -> !item.getShipPlan()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(rst)) { + // 港口和国家的英文明称 + Map portMap = new HashMap<>(); + Map countryMap = new HashMap<>(); + List countryIds = rst.stream().map(item -> item.getCountryId()).distinct().collect(Collectors.toList()); + List portIds = rst.stream().map(item -> item.getPortId()).distinct().collect(Collectors.toList()); + + List portByIds = openApi.getPortByIds(portIds); + List countryByIds = openApi.getCountryByIds(countryIds); + portMap.putAll(portByIds.stream().collect(Collectors.toMap(item -> item.getPotId(), item -> item.getPotEnname()))); + countryMap.putAll(countryByIds.stream().collect(Collectors.toMap(item -> item.getCtyId(), item -> item.getCtyEnname()))); + + rst.stream().forEach(item -> { + item.setPortEnName(portMap.get(item.getPortId())); + item.setCountryEnName(countryMap.get(item.getCountryId())); + }); + } + + return ResultUtil.success(rst); + } + @ApiOperation("全量数据查询") @PostMapping("/data/list") public Result> dataList(@RequestBody ExportInCheckQuery query) { + long begin = System.currentTimeMillis(); + Boolean vinStatus = query.getVinStatus(); + Boolean vinStatusApi = query.getVinStatusApi(); + query.setVinStatus(null); + query.setVinStatusApi(null); if (query.getId() != null && Long.compare(0L, query.getId()) == 0) { query.setId(null); } - if (query.getEndEnterTime() != null) { - query.setEndEnterTime(DateUtils.getDayEnd(query.getEndEnterTime())); - } if (query.getCheckStatus() == null) { query.setCheckStatusList(Arrays.asList(AuditEnum.SUBMIT, AuditEnum.AUDIT, AuditEnum.AUDIT_PASS, AuditEnum.AUDIT_REJECT)); } - Wrapper queryWrapper = new WrapperKit() { + Date beginEnterDate = query.getBeginEnterTime(); + Date endEnterDate = query.getEndEnterTime(); + query.setBeginEnterTime(null); + query.setEndEnterTime(null); + QueryWrapper queryWrapper = (QueryWrapper) new WrapperKit() { }.changeBaseQueryToWrapper(CustomerExportIn.class, query); + queryWrapper.ge(beginEnterDate != null, "begin_enter_time", beginEnterDate) + .le(endEnterDate != null, "end_enter_time", endEnterDate); +// queryWrapper.and(beginEnterDate != null || endEnterDate != null, (q) -> { +// q.and(beginEnterDate != null, (t) -> { +// t.ge("begin_enter_time", beginEnterDate).le("begin_enter_time", endEnterDate); +// }).or(endEnterDate != null, (s) -> { +// s.ge("end_enter_time", beginEnterDate).le("end_enter_time", endEnterDate); +// }); +// }); List list = customerExportInService.list(queryWrapper); customerService.wrapperEntity(list); + long end = System.currentTimeMillis(); if (CollectionUtils.isNotEmpty(list)) { + List cargos = new ArrayList<>(); + if (vinStatus == null || vinStatus) { + cargos.addAll(customerExportInCargoService.lambdaQuery() + .in(CustomerExportInCargo::getExportInId, list.stream().map(s -> s.getId()).collect(Collectors.toList())).list()); + } + log.info("全量查询,数据返回耗时:" + (end - begin)); + // 港口和国家的英文明称 Map portMap = new HashMap<>(); Map countryMap = new HashMap<>(); @@ -405,20 +546,13 @@ public class ExportInHandler implements BaseHandler { portMap.putAll(portByIds.stream().collect(Collectors.toMap(item -> item.getPotId(), item -> item.getPotEnname()))); countryMap.putAll(countryByIds.stream().collect(Collectors.toMap(item -> item.getCtyId(), item -> item.getCtyEnname()))); - List cargos = customerExportInCargoService.lambdaQuery() - .in(CustomerExportInCargo::getExportInId, list.stream().map(item -> item.getId()).collect(Collectors.toList())).list(); - - // 按进港ID进行分组 - Map> collect = cargos.stream().collect(Collectors.groupingBy(CustomerExportInCargo::getExportInId)); - - // 数据拼装 - list.stream().forEach(item -> { - List cs = collect.get(item.getId()); - - item.setPortEnName(portMap.get(item.getPortId())); - item.setCountryEnName(countryMap.get(item.getCountryId())); - - if (CollectionUtils.isNotEmpty(cs)) { + // 获取车辆状态 + if (CollectionUtils.isNotEmpty(cargos) && (vinStatusApi == null || vinStatusApi) && (vinStatus == null || vinStatus)) { + // 按航次进行分组 + Map> listMap = list.stream().collect(Collectors.groupingBy(CustomerExportIn::getVoyageId)); + listMap.entrySet().stream().forEach(item -> { + List ids = item.getValue().stream().map(s -> s.getId()).collect(Collectors.toList()); + List cs = cargos.stream().filter(s -> ids.contains(s.getExportInId())).collect(Collectors.toList()); // 获取作业状态 Map statCollect = null; List vins = cs.stream().map(s -> s.getVin()).collect(Collectors.toList()); @@ -427,8 +561,8 @@ public class ExportInHandler implements BaseHandler { req.setBusinessType("IN_PORT"); req.setImportExportType("E"); req.setVinCodeList(vins); - if (!StringUtils.equalsAnyIgnoreCase(item.getVoyageId(), "HT6", "HTLG", "HTTC")) { - req.setVvyId(item.getVoyageId()); + if (!StringUtils.equalsAnyIgnoreCase(item.getKey(), "HT6", "HTLG", "HTTC")) { + req.setVvyId(item.getKey()); } List status = openApi.getVinStatus(req); statCollect = status.stream().collect(Collectors.toMap(WorkStatusDTO::getVinCode, WorkStatusDTO::getWorkStatus)); @@ -439,23 +573,37 @@ public class ExportInHandler implements BaseHandler { cargo.setWorkStatus(statCollect.get(cargo.getVin())); } } - } + }); + } - item.setVins(cs); + // 数据拼装 + list.stream().forEach(item -> { + item.setPortEnName(portMap.get(item.getPortId())); + item.setCountryEnName(countryMap.get(item.getCountryId())); + + if (vinStatus == null || vinStatus) { + List cs = cargos.stream().filter(s -> Long.compare(s.getExportInId(), item.getId()) == 0).collect(Collectors.toList()); + + item.setVins(cs); + } }); } - + long allEnd = System.currentTimeMillis(); + log.info("全量查询,数据拼装耗时:" + (allEnd - end) + " ,共计耗时: " + (allEnd - begin)); return ResultUtil.success(list); } @ApiOperation("根据航次ID查询审核通过进港记录") @PostMapping("/query-list/voyage") - public Result> checkQuery(@RequestParam(required = false) @NotBlank(message = "航次ID不能为空") String voyageId, - @RequestParam(required = false) AuditEnum status) { + public Result> checkQuery( + @RequestParam(required = false) @NotBlank(message = "船ID不能为空") @ApiParam("船ID") String shipId, + @RequestParam(required = false) @NotBlank(message = "航次ID不能为空") @ApiParam("航次ID") String voyageId, + @RequestParam(required = false) @ApiParam("提单号列表") List billNos, + @RequestParam(required = false) AuditEnum status) { if (status == null) { status = AuditEnum.AUDIT_PASS; } - List list = customerExportInService.getListByVoyageId(voyageId, status); + List list = customerExportInService.getListByVoyageId(shipId, voyageId, billNos, status); customerService.wrapperEntity(list); // 判断是否换船,找出车架号重复,且航次不一样的记录 @@ -474,13 +622,25 @@ public class ExportInHandler implements BaseHandler { @ApiOperation("出口条码打印列表查询") @PostMapping("/check/list") public Result> checkList(@RequestBody ExportInCheckQuery query) { - if (query.getEndEnterTime() != null) { - query.setEndEnterTime(DateUtils.getDayEnd(query.getEndEnterTime())); - } + Boolean vinStatus = query.getVinStatus(); + query.setVinStatus(null); query.setCheckStatus(AuditEnum.AUDIT_PASS); - Wrapper queryWrapper = new WrapperKit() { + Date beginEnterDate = query.getBeginEnterTime(); + Date endEnterDate = query.getEndEnterTime(); + query.setBeginEnterTime(null); + query.setEndEnterTime(null); + QueryWrapper queryWrapper = (QueryWrapper) new WrapperKit() { }.changeBaseQueryToWrapper(CustomerExportIn.class, query); - List list = customerExportInService.list(queryWrapper); + queryWrapper.ge(beginEnterDate != null, "begin_enter_time", beginEnterDate) + .le(endEnterDate != null, "end_enter_time", endEnterDate); +// queryWrapper.and(beginEnterDate != null || endEnterDate != null, (q) -> { +// q.and(beginEnterDate != null, (t) -> { +// t.ge("begin_enter_time", beginEnterDate).le("begin_enter_time", endEnterDate); +// }).or(endEnterDate != null, (s) -> { +// s.ge("end_enter_time", beginEnterDate).le("end_enter_time", endEnterDate); +// }); +// }); + List list = customerExportInService.list(queryWrapper); customerService.wrapperEntity(list); return ResultUtil.success(list); } @@ -488,8 +648,45 @@ public class ExportInHandler implements BaseHandler { @ApiOperation("出口条码(航次)打印列表查询") @PostMapping("/print/voyage") public Result> getPrintList(@RequestBody PrintQuery query) { + String s1 = null; + if (CollectionUtils.isNotEmpty(query.getBillNo())) { + s1 = query.getBillNo().stream().map(s -> "'" + s + "'").collect(Collectors.joining(",")); + } - return ResultUtil.success(customerExportInCargoService.getListByVoyageId(query)); +// List rst = customerExportInCargoService.getListByVoyageId(query); + // StringUtils.equalsAnyIgnoreCase(exportIn.getCartType(), "备件" + + List rst = customerExportInCargoService.lambdaQuery() + .in(CollectionUtils.isNotEmpty(query.getId()), CustomerExportInCargo::getId, query.getId()) + .eq(StringUtils.isNotEmpty(query.getFlag()), CustomerExportInCargo::getCargoType, query.getFlag()) + .exists(StringUtils.isNotEmpty(query.getShipId()), "select id from customer_export_in B where export_in_id=B.id and B.ship_id={0}", query.getShipId()) + .exists(StringUtils.isNotEmpty(query.getVoyageId()), "select id from customer_export_in B where export_in_id=B.id and B.voyage_id={0}", query.getVoyageId()) + .exists(StringUtils.isNotEmpty(s1), "select id from customer_export_in B where export_in_id=B.id and B.bill_num in ("+s1+")").list(); + + if (CollectionUtils.isNotEmpty(rst)) { + List list = customerExportInService.lambdaQuery().in(CustomerExportIn::getId, rst.stream().map(s -> s.getExportInId()).collect(Collectors.toList())).list(); + list.stream().forEach(item -> { + rst.stream().filter(s -> Long.compare(s.getExportInId(), item.getId()) == 0).forEach(s -> { + s.setBrandId(item.getBrandId()); + s.setBrand(item.getBrand()); + s.setCartTypeId(item.getCartTypeId()); + s.setCartType(item.getCartType()); + s.setBillNum(item.getBillNum()); + s.setShipEnName(item.getShipEnName()); + s.setVoyage(item.getVoyage()); + s.setShipName(item.getShipName()); + s.setModels(item.getModels()); + s.setPortId(item.getPortId()); + s.setPortName(item.getPortName()); + s.setLength(item.getLength()); + s.setWeight(item.getWeight()); + s.setWidth(item.getWidth()); + s.setHeight(item.getHeight()); + }); + }); + } + + return ResultUtil.success(rst); } @ApiOperation("审核端导出数据") @@ -510,8 +707,8 @@ public class ExportInHandler implements BaseHandler { } rst.stream().forEach(exportIn -> { - exportIn.setSpareNum(exportIn.getVins().stream().filter(item -> item.getCargoType() == 1).count()+""); - exportIn.setCarNum(exportIn.getVins().stream().filter(item -> item.getCargoType() == 0).count()+""); + exportIn.setSpareNum(exportIn.getVins().stream().filter(item -> item.getCargoType() == 1).count() + ""); + exportIn.setCarNum(exportIn.getVins().stream().filter(item -> item.getCargoType() == 0).count() + ""); exportIn.setPortEnName(portMap.get(exportIn.getPortId())); exportIn.setCountryEnName(countryMap.get(exportIn.getCountryId())); // 补足货物缺失的数据 @@ -593,6 +790,8 @@ public class ExportInHandler implements BaseHandler { @ApiOperation("货物明细分页列表") @PostMapping("/cargos/page") public Result> cargoList(@RequestBody @Validated(ValidationGroup.update.class) CargoQuery query) { + Boolean vinStatus = query.getVinStatus(); + query.setVinStatus(null); List ids = new ArrayList<>(); if (query.getId() != null) { ids.add(query.getId()); @@ -600,7 +799,7 @@ public class ExportInHandler implements BaseHandler { ids.addAll(query.getIds()); } List exportInList = customerExportInService.lambdaQuery().in(CustomerExportIn::getId, ids).list(); - Map eMap = exportInList.stream().collect(Collectors.toMap(CustomerExportIn::getId, item->item)); + Map eMap = exportInList.stream().collect(Collectors.toMap(CustomerExportIn::getId, item -> item)); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); queryWrapper.eq(query.getId() != null, CustomerExportInCargo::getExportInId, query.getId()); @@ -625,38 +824,147 @@ public class ExportInHandler implements BaseHandler { item.setVoyage(exportIn.getVoyage()); item.setShipName(exportIn.getShipName()); item.setModels(exportIn.getModels()); + item.setPortName(exportIn.getPortName()); }); - - Map> collect1 = page.getRecords().stream().collect(Collectors.groupingBy(CustomerExportInCargo::getExportInId)); - - collect1.entrySet().stream().forEach(m->{ - // 获取作业状态 - Map collect = null; - List vins = m.getValue().stream().map(item -> item.getVin()).collect(Collectors.toList()); - if (CollectionUtils.isNotEmpty(vins)) { - CustomerExportIn exportIn = eMap.get(m.getKey()); - - VinStatusRequest req = new VinStatusRequest(); - req.setBusinessType("IN_PORT"); - req.setImportExportType("E"); - req.setVinCodeList(vins); - if (!StringUtils.equalsAnyIgnoreCase(exportIn.getVoyageId(), "HT6", "HTLG", "HTTC")) { - req.setVvyId(exportIn.getVoyageId()); + + if (CollectionUtils.isNotEmpty(page.getRecords()) && (vinStatus == null || vinStatus)) { + // 按航次进行分组 + Map> listMap = exportInList.stream().collect(Collectors.groupingBy(CustomerExportIn::getVoyageId)); + listMap.entrySet().stream().forEach(item -> { + List cids = item.getValue().stream().map(s -> s.getId()).collect(Collectors.toList()); + List cs = page.getRecords().stream().filter(s -> cids.contains(s.getExportInId())).collect(Collectors.toList()); + // 获取作业状态 + Map statCollect = null; + List vins = cs.stream().map(s -> s.getVin()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(vins)) { + VinStatusRequest req = new VinStatusRequest(); + req.setBusinessType("IN_PORT"); + req.setImportExportType("E"); + req.setVinCodeList(vins); + if (!StringUtils.equalsAnyIgnoreCase(item.getKey(), "HT6", "HTLG", "HTTC")) { + req.setVvyId(item.getKey()); + } + List status = openApi.getVinStatus(req); + statCollect = status.stream().collect(Collectors.toMap(WorkStatusDTO::getVinCode, WorkStatusDTO::getWorkStatus)); } - List status = openApi.getVinStatus(req); - collect = status.stream().collect(Collectors.toMap(WorkStatusDTO::getVinCode, WorkStatusDTO::getWorkStatus)); - } - if (MapUtils.isNotEmpty(collect)) { - for (CustomerExportInCargo cargo : page.getRecords()) { - cargo.setWorkStatus(collect.get(cargo.getVin())); + if (MapUtils.isNotEmpty(statCollect)) { + for (CustomerExportInCargo cargo : cs) { + cargo.setWorkStatus(statCollect.get(cargo.getVin())); + } } - } - }); + }); + } return ResultUtil.success(page); } + @ApiOperation("提单号,车架号查询车辆信息") + @PostMapping("/cargos/list") + public Result> cargoList(@RequestBody CargoVinQuery query) { + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); + queryWrapper.like(StringUtils.isNotEmpty(query.getVin()), CustomerExportInCargo::getVin, query.getVin()); + queryWrapper.exists("select id from customer_export_in B where B.id=customer_export_in_cargo.export_in_id and B.bill_num={0}", query.getBillNum()); + List list = customerExportInCargoService.list(queryWrapper); + + customerService.wrapperEntity(list); + + if (CollectionUtils.isNotEmpty(list)) { + + List ids = list.stream().map(s -> s.getExportInId()).collect(Collectors.toList()); + + List exportInList = customerExportInService.lambdaQuery().in(CustomerExportIn::getId, ids).list(); + Map eMap = exportInList.stream().collect(Collectors.toMap(CustomerExportIn::getId, item -> item)); + + list.forEach(item -> { + CustomerExportIn exportIn = eMap.get(item.getExportInId()); + item.setBrandId(exportIn.getBrandId()); + item.setBrand(exportIn.getBrand()); + item.setCartTypeId(exportIn.getCartTypeId()); + item.setCartType(exportIn.getCartType()); + item.setBillNum(exportIn.getBillNum()); + item.setShipEnName(exportIn.getShipEnName()); + item.setVoyage(exportIn.getVoyage()); + item.setShipName(exportIn.getShipName()); + item.setModels(exportIn.getModels()); + }); + + } + + return ResultUtil.success(list); + } + + @ApiOperation("验证货代提单号是否可用") + @PostMapping("/billNum/valid") + public Result billNumValid(@RequestBody @Validated(ValidationGroup.insert.class) BillNumValidVo form) { + List repeatBillNum = customerExportInService.lambdaQuery().eq(CustomerExportIn::getShipId, form.getShipId()) + .eq(CustomerExportIn::getVoyageId, form.getVoyageId()) + .eq(CustomerExportIn::getBillNum, form.getBillNum()) + .ne(CustomerExportIn::getFreightId, form.getFreightId()) + .ne(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_REJECT).list(); + if (CollectionUtils.isNotEmpty(repeatBillNum)) { + return ResultUtil.failure(1, "当前已有其他货代" + repeatBillNum.get(0).getFreight() + "使用该提单号,不可重复申请"); + } + + return ResultUtil.success("success"); + } + + /** + * 生成备件号 + * @param size + * @return + */ + private List genBjNo(int size, List tmp) { + if (tmp == null) { + tmp = new ArrayList<>(size); + } + if (size == 0) { + return tmp; + } + String prefix = StringUtils.join("BJ", DateUtil.format(new Date(), "yyMMddHHmm")); + List vins = new ArrayList<>(size); + RLock lock = redissonClient.getLock(prefix); + try { + lock.lock(30, TimeUnit.SECONDS); + do { + String vin = prefix + RandomUtil.randomNumbers(5); + if (!vins.contains(vin)) { + vins.add(vin); + } + } while (vins.size() < size); + + // 验证是否有重复的 + List strings = bjNumCache.get(prefix); + if (CollectionUtils.isNotEmpty(strings)) { + List finalStrings = strings; + List collect = vins.stream().filter(s -> finalStrings.contains(s)).collect(Collectors.toList()); // 重复的 + if (CollectionUtils.isNotEmpty(collect)) { + vins.removeAll(collect); + } + if (CollectionUtils.isNotEmpty(vins)) { + tmp.addAll(vins); + strings.addAll(vins); + bjNumCache.put(prefix, strings); + } + if (CollectionUtils.isNotEmpty(collect)) { + genBjNo(collect.size(), tmp); + } + } else { + strings = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(vins)) { + tmp.addAll(vins); + strings.addAll(vins); + bjNumCache.put(prefix, strings); + } + } + } finally { + lock.unlock(); + } + + return tmp; + } + /** * 新增 * @@ -690,7 +998,14 @@ public class ExportInHandler implements BaseHandler { List repeat = form.getSpares().stream().collect(Collectors.groupingBy(ExportInCargoVo::getVin, Collectors.counting())) .entrySet().stream().filter(entry -> entry.getValue() > 1).map(entry -> entry.getKey()).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(repeat)) { - return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), StringUtils.join(repeat, ",") + "车架号重复"); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), StringUtils.join(repeat, ",") + "备件号重复"); + } + // 数据库中是否已经存在 + List list = customerExportInCargoService.lambdaQuery() + .in(CustomerExportInCargo::getVin, form.getSpares().stream().map(s -> s.getVin()).collect(Collectors.toList())) + .notExists("select id from customer_export_in where customer_export_in.id=customer_export_in_cargo.export_in_id and customer_export_in.check_status={0}", AuditEnum.AUDIT_REJECT).list(); + if (CollectionUtils.isNotEmpty(list)) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), list.stream().map(s -> s.getVin()).collect(Collectors.joining(",")) + "备件号重复"); } } String batchNo = customerService.getSequenceNo("export_in_batch_no", "出口进场", "EI"); @@ -736,14 +1051,7 @@ public class ExportInHandler implements BaseHandler { }).collect(Collectors.toList()); if (CollectionUtils.isEmpty(spares) && StringUtils.equalsAnyIgnoreCase(exportIn.getCartType(), "备件", "BJ") && StringUtils.equals("正常", exportIn.getNatureFlagName())) { // 出口进场计划备件条码生成的规则要变一下,BJ+年月日时分+5随机数,一共要17位 - String prefix = StringUtils.join("BJ", DateUtil.format(new Date(), "yyMMddHHmm")); - List vins = new ArrayList<>(exportIn.getQuantity()); - do { - String vin = prefix + RandomUtil.randomNumbers(5); - if (!vins.contains(vin)) { - vins.add(vin); - } - } while (vins.size() < exportIn.getQuantity()); + List vins = genBjNo(exportIn.getQuantity(), null); spares = vins.stream().map(item -> { CustomerExportInCargo entity = new CustomerExportInCargo(); entity.setBrand(exportIn.getBrand()); @@ -771,6 +1079,16 @@ public class ExportInHandler implements BaseHandler { return ResultUtil.failure(ErrorType.PROGRAM_ERROR.id(), "进场货物的数量,要等于进场货物的所有数量"); } + // 最终逻辑确认了,客户服务平台-出口进港申请,加一个限制,同船名航次提单号只能被一个货代录入,如果A货代已经录入提单号A,B货代再录入提单A的时候弹窗提示“当前已有其他货代#货代名称#使用该提单号,不可重复申请”。 + List repeatBillNum = customerExportInService.lambdaQuery().eq(CustomerExportIn::getShipId, exportIn.getShipId()) + .eq(CustomerExportIn::getVoyageId, exportIn.getVoyageId()) + .eq(CustomerExportIn::getBillNum, exportIn.getBillNum()) + .ne(CustomerExportIn::getFreightId, exportIn.getFreightId()) + .ne(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_REJECT).list(); + if (CollectionUtils.isNotEmpty(repeatBillNum)) { + return ResultUtil.failure(1, "当前已有其他货代" + repeatBillNum.get(0).getFreight() + "使用该提单号,不可重复申请"); + } + // 验证同一提单下,所有进场的数量,体积,重量和提单号的每票的数量进行, 船名,航次 QueryWrapper nQuery = new QueryWrapper<>(); nQuery.select("sum(quantity) as quantity, sum(volume) as volume, sum(weight) as weight") @@ -785,7 +1103,19 @@ public class ExportInHandler implements BaseHandler { map.put("volume", new BigDecimal(0)); } if (new BigDecimal(exportIn.getEachQuantity()).compareTo(((BigDecimal) map.get("quantity")).add(new BigDecimal(exportIn.getQuantity()))) < 0) { - return ResultUtil.failure(ErrorType.PROGRAM_ERROR.id(), "数量不得超过单票件数"); + QueryWrapper rQuery = new QueryWrapper<>(); + rQuery.eq("bill_num", exportIn.getBillNum()) + .eq("ship_id", exportIn.getShipId()) + .eq("voyage_id", exportIn.getVoyageId()).ne("check_status", AuditEnum.AUDIT_REJECT); + List rList = customerExportInService.list(rQuery); + Optional first = rList.stream().filter(item -> !StringUtils.equals(item.getFreightId(), exportIn.getFreightId())).findFirst(); + if (first.isPresent()) { + String str = first.get().getFreight(); + return ResultUtil.failure(1, "同提单数量之和超过单票数量 注:当前已有其他货代【" + str + "】使用该提单号"); + } else { + return ResultUtil.failure(1, "同提单数量之和超过单票数量"); + } + } if (exportIn.getEachWeight().divide(new BigDecimal(1000)).compareTo(((BigDecimal) map.get("weight")).add(exportIn.getWeight())) < 0) { // return ResultUtil.failure(ErrorType.PROGRAM_ERROR.id(), "重量不得超过单票重量"); @@ -805,16 +1135,22 @@ public class ExportInHandler implements BaseHandler { // 查询出对应的港区 List list = customerExportInService.lambdaQuery().in(CustomerExportIn::getId, exists.stream().map(item -> item.getExportInId()).collect(Collectors.toList())).list(); Map portAreaMap = list.stream().collect(Collectors.toMap(CustomerExportIn::getId, CustomerExportIn::getPortAreaId)); + Map vvyIdMap = list.stream().collect(Collectors.toMap(CustomerExportIn::getId, CustomerExportIn::getVoyageId)); // 通过接口再次验证 List req = exists.stream().map(item -> { CheckVinReq v = new CheckVinReq(); v.setIsRepetition(true); v.setPamId(portAreaMap.get(item.getExportInId())); v.setVinCode(item.getVin()); + v.setVvyId(vvyIdMap.get(item.getExportInId())); return v; }).collect(Collectors.toList()); List rst = shpApi.checkVinRepeat(req); if (CollectionUtils.isNotEmpty(rst)) { + List strings = rst.stream().filter(ss -> !ss.getIsRepetition()).map(s -> s.getVinCode()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(strings)) { + log.info("接口验证,可以再次导入的车架号:" + strings.stream().collect(Collectors.joining(","))); + } // 再次过滤出重复的 List collect = rst.stream().filter(item -> item.getIsRepetition()).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(collect)) { @@ -998,6 +1334,7 @@ public class ExportInHandler implements BaseHandler { // 使用LambdaUpdateWrapper只在特定需求下做处理(推荐) 将字段修改为空值的处理方法 public Result edit(@RequestParam(required = false, defaultValue = "false") Boolean flag, @RequestBody @Validated(ValidationGroup.update.class) ExportInVo form) { + Long b = System.currentTimeMillis(); // 验证是否有重复的车架号 if (CollectionUtils.isNotEmpty(form.getCargos())) { List repeat = form.getCargos().stream().collect(Collectors.groupingBy(ExportInCargoVo::getVin, Collectors.counting())) @@ -1010,7 +1347,16 @@ public class ExportInHandler implements BaseHandler { List repeat = form.getSpares().stream().collect(Collectors.groupingBy(ExportInCargoVo::getVin, Collectors.counting())) .entrySet().stream().filter(entry -> entry.getValue() > 1).map(entry -> entry.getKey()).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(repeat)) { - return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), StringUtils.join(repeat, ",") + "车架号重复"); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), StringUtils.join(repeat, ",") + "备件号重复"); + } + + // 数据库中是否已经存在 + List list = customerExportInCargoService.lambdaQuery() + .ne(CustomerExportInCargo::getExportInId, form.getId()) + .in(CustomerExportInCargo::getVin, form.getSpares().stream().map(s -> s.getVin()).collect(Collectors.toList())) + .notExists("select id from customer_export_in where customer_export_in.id=customer_export_in_cargo.export_in_id and customer_export_in.check_status={0}", AuditEnum.AUDIT_REJECT).list(); + if (CollectionUtils.isNotEmpty(list)) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), list.stream().map(s -> s.getVin()).collect(Collectors.joining(",")) + "备件号重复"); } } @@ -1071,14 +1417,8 @@ public class ExportInHandler implements BaseHandler { return ResultUtil.failure(ErrorType.PROGRAM_ERROR.id(), "备件列表不能大于备件总数"); } if (exportIn.getQuantity() > spares.size()) { // 自动生成备件号 - String prefix = StringUtils.join("BJ", DateUtil.format(new Date(), "yyMMddHHmm")); - List vins = new ArrayList<>(exportIn.getQuantity() - spares.size()); - do { - String vin = prefix + RandomUtil.randomNumbers(5); - if (!vins.contains(vin)) { - vins.add(vin); - } - } while (vins.size() < exportIn.getQuantity() - spares.size()); + List vins = genBjNo(exportIn.getQuantity() - spares.size(), null); + List addSpares = vins.stream().map(item -> { CustomerExportInCargo entity = new CustomerExportInCargo(); entity.setBrand(exportIn.getBrand()); @@ -1110,7 +1450,16 @@ public class ExportInHandler implements BaseHandler { } // 数量必须≤单票件数,否则不能跳转下一步,并提示“数量不得超过单票件数” if (num > exportIn.getEachQuantity()) { - return ResultUtil.failure(ErrorType.PROGRAM_ERROR.id(), "数量不得超过单票件数"); + return ResultUtil.failure(ErrorType.PROGRAM_ERROR.id(), "同提单数量之和超过单票数量"); + } + + List repeatBillNum = customerExportInService.lambdaQuery().eq(CustomerExportIn::getShipId, exportIn.getShipId()) + .eq(CustomerExportIn::getVoyageId, exportIn.getVoyageId()) + .eq(CustomerExportIn::getBillNum, exportIn.getBillNum()) + .ne(CustomerExportIn::getFreightId, exportIn.getFreightId()) + .ne(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_REJECT).list(); + if (CollectionUtils.isNotEmpty(repeatBillNum)) { + return ResultUtil.failure(1, "当前已有其他货代" + repeatBillNum.get(0).getFreight() + "使用该提单号,不可重复申请"); } // 验证同一提单下,所有进场的数量,体积,重量和提单号的每票的数量进行 @@ -1127,7 +1476,18 @@ public class ExportInHandler implements BaseHandler { vmap.put("volume", new BigDecimal(0)); } if (new BigDecimal(exportIn.getEachQuantity()).compareTo(((BigDecimal) vmap.get("quantity")).add(new BigDecimal(exportIn.getQuantity()))) < 0) { - return ResultUtil.failure(ErrorType.PROGRAM_ERROR.id(), "数量不得超过单票件数"); + QueryWrapper rQuery = new QueryWrapper<>(); + rQuery.eq("bill_num", exportIn.getBillNum()) + .eq("ship_id", exportIn.getShipId()) + .eq("voyage_id", exportIn.getVoyageId()).ne("check_status", AuditEnum.AUDIT_REJECT).ne("id", exportIn.getId()); + List rList = customerExportInService.list(rQuery); + Optional first = rList.stream().filter(item -> !StringUtils.equals(item.getFreightId(), exportIn.getFreightId())).findFirst(); + if (first.isPresent()) { + String str = first.get().getFreight(); + return ResultUtil.failure(1, "同提单数量之和超过单票数量 注:当前已有其他货代【" + str + "】使用该提单号"); + } else { + return ResultUtil.failure(1, "同提单数量之和超过单票数量"); + } } if (exportIn.getEachWeight().divide(new BigDecimal(1000)).compareTo(((BigDecimal) vmap.get("weight")).add(exportIn.getWeight())) < 0) { // return ResultUtil.failure(ErrorType.PROGRAM_ERROR.id(), "重量不得超过单票重量"); @@ -1137,10 +1497,10 @@ public class ExportInHandler implements BaseHandler { } //* 异常情况有,必填项车架号,车架号必须17位,数据重复,如果重复进行覆盖更新 - count = cargos.stream().filter(item -> item.getVin().length() != 17).count(); - if (count > 0) { - return ResultUtil.failure(ErrorType.PROGRAM_ERROR.id(), "车架号必须17位"); - } +// count = cargos.stream().filter(item -> item.getVin().length() != 17).count(); +// if (count > 0) { +// return ResultUtil.failure(ErrorType.PROGRAM_ERROR.id(), "车架号必须17位"); +// } //* 车架号重复不支持导入或新增 if (CollectionUtils.isNotEmpty(cargos)) { // 查询 车架号在系统中是否已经存在, 编辑的和新增的判断方式是不一样的 @@ -1149,19 +1509,26 @@ public class ExportInHandler implements BaseHandler { .notExists("select id from customer_export_in where customer_export_in.id=customer_export_in_cargo.export_in_id and customer_export_in.check_status={0}", AuditEnum.AUDIT_REJECT) .ne(CustomerExportInCargo::getExportInId, exportIn.getId())); if (CollectionUtils.isNotEmpty(exists)) { + Long s = System.currentTimeMillis(); // 查询出对应的港区 List list = customerExportInService.lambdaQuery().in(CustomerExportIn::getId, exists.stream().map(item -> item.getExportInId()).collect(Collectors.toList())).list(); Map portAreaMap = list.stream().collect(Collectors.toMap(CustomerExportIn::getId, CustomerExportIn::getPortAreaId)); + Map vvyIdMap = list.stream().collect(Collectors.toMap(CustomerExportIn::getId, CustomerExportIn::getVoyageId)); // 通过接口再次验证 List req = exists.stream().map(item -> { CheckVinReq v = new CheckVinReq(); v.setIsRepetition(true); v.setPamId(portAreaMap.get(item.getExportInId())); v.setVinCode(item.getVin()); + v.setVvyId(vvyIdMap.get(item.getExportInId())); return v; }).collect(Collectors.toList()); List rst = shpApi.checkVinRepeat(req); if (CollectionUtils.isNotEmpty(rst)) { + List strings = rst.stream().filter(ss -> !ss.getIsRepetition()).map(ss -> ss.getVinCode()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(strings)) { + log.info("接口验证,可以再次导入的车架号:" + strings.stream().collect(Collectors.joining(","))); + } // 再次过滤出重复的 List collect = rst.stream().filter(item -> item.getIsRepetition()).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(collect)) { @@ -1170,6 +1537,7 @@ public class ExportInHandler implements BaseHandler { } else { return ResultUtil.failure(ErrorType.PROGRAM_ERROR.id(), "车架号已存在:" + exists.stream().map(item -> item.getVin()).collect(Collectors.joining(","))); } + log.info("编辑验证车架号接口耗时:" + (System.currentTimeMillis() - s)); } } @@ -1180,6 +1548,8 @@ public class ExportInHandler implements BaseHandler { customerService.updateExportIn(false, exportIn, cargos, times, spares); + log.info("编辑耗时:" + (System.currentTimeMillis() - b)); + return ResultUtil.success(String.valueOf(exportIn.getId())); } @@ -1256,30 +1626,52 @@ public class ExportInHandler implements BaseHandler { @PostMapping("/check") @Transactional(rollbackFor = {Exception.class}) public Result check(@RequestBody @Validated(ValidationGroup.insert.class) ExportInCheckVo check) throws Exception { - List exportIns = new ArrayList<>(); - for (Long id : check.getIds()) { - CustomerExportIn exportIn = PoMapper.instance.exportInCheckVo2Entity(check); - exportIn.setCheckManId(UserContext.getUser().getUserId()); - exportIn.setCheckTime(new Date()); - exportIn.setId(id); - exportIns.add(exportIn); + // 待审核的数据 + List list = customerExportInService.lambdaQuery() + .in(CustomerExportIn::getId, check.getIds()).list(); + + if (CollectionUtils.isNotEmpty(list)) { + BatchConfirmReviewReq req = new BatchConfirmReviewReq(); + req.setIds(list.stream().map(s -> s.getId() + "").collect(Collectors.toList())); + Boolean rst = openApi.batchConfirmReview(req); + if (!rst) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "审核失败"); + } + + if (check.getCheckStatus() == AuditEnum.AUDIT_PASS) { + // 获取航次的离泊状态 + List collect = list.stream().map(s -> s.getVoyageId()).filter(s -> !StringUtils.equalsAny(s, "HT6", "HTLG", "HTTC")).distinct().collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(collect)) { + List shipmentBerthsStatusRespDTOS = shpApi.queryVoyagesBerthsStatusByVvyIds(collect); + if (CollectionUtils.isNotEmpty(shipmentBerthsStatusRespDTOS)) { + List strings = shipmentBerthsStatusRespDTOS.stream().filter(s -> StringUtils.equalsAny(s.getUnberthedStatus(), "1")).map(s -> s.getVvyId()).distinct().collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(strings)) { + customerExportInService.lambdaUpdate().in(CustomerExportIn::getVoyageId, strings) + .set(CustomerExportIn::getUnberthFlag, "1").update(); + } + } + } + } } - boolean row = customerExportInService.updateBatchById(exportIns); - - // 如果是审核通过,还需要将数据同步到旧系统 + boolean row = customerExportInService.lambdaUpdate() + .set(CustomerExportIn::getCheckManId, UserContext.getUser().getUserId()) + .set(CustomerExportIn::getCheckTime, new Date()) + .set(CustomerExportIn::getCheckStatus, check.getCheckStatus()) + .set(CustomerExportIn::getCheckResult, check.getCheckResult()) + .setSql(check.getCheckStatus() == AuditEnum.AUDIT_REJECT, "voyage_id = case when port_area='外高桥' then 'HT6' when port_area='临港' then 'HTLG' when port_area='太仓' then 'HTTC' else voyage_id end, voyage = case when port_area='外高桥' then 'HT6' when port_area='临港' then 'HTLG' when port_area='太仓' then 'HTTC' else voyage end") + .in(CustomerExportIn::getId, check.getIds()) + .update(); if (row) { - List list = customerExportInService.lambdaQuery().in(CustomerExportIn::getId, check.getIds()).list(); - // 记录日志 for (CustomerExportIn exportIn : list) { LogRecordDTO log = new LogRecordDTO(); log.setOperateData(exportIn); log.setStatus(check.getCheckStatus() == AuditEnum.AUDIT_PASS ? 0 : 1); log.setOperateTime(new Date()); - log.setUserId(SecurityUtils.getUserId()); - log.setUserName(SecurityUtils.getUserName()); + log.setUserId(UserContext.getUser().getUserId()); + log.setUserName(UserContext.getUser().getUsername()); EsLogApprovalUtil.writeLog(log); } @@ -1290,7 +1682,7 @@ public class ExportInHandler implements BaseHandler { return ResultUtil.success("success"); } - return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "修改失败,ID不存在"); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "没有待审核数据"); } @ApiOperation("整船待审核数量查询") @@ -1305,6 +1697,88 @@ public class ExportInHandler implements BaseHandler { return ResultUtil.success(row); } + /** + * 审核 + * + * @param check + * @return + */ + @ApiOperation("新进港审核") + @PostMapping("/check/byShipAndVoyage") + public Result checkByShipAndVoyage(@RequestBody @Validated(ValidationGroup.insert.class) ExportInAuditVo check) throws Exception { + List voyageIds = Arrays.asList("HT6", "HTTC", "HTLG", check.getVoyageId()); + // 待审核的数据 + List list = customerExportInService.lambdaQuery() + .eq(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_PASS) + .eq(CustomerExportIn::getShipId, check.getShipId()) + .in(CustomerExportIn::getVoyageId, voyageIds) + .in(CustomerExportIn::getBillNum, check.getBillNums()).list(); + + List billNums = list.stream().map(item -> item.getBillNum()).collect(Collectors.toList()); + // 系统是否存在,不存在的提单号 + String s = check.getBillNums().stream().filter(item -> !billNums.contains(item)).collect(Collectors.joining(",")); + if (StringUtils.isNotEmpty(s)) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "审核通过的提单号:" + s + "不存在"); + } + + if (CollectionUtils.isNotEmpty(list)) { + BatchConfirmReviewReq req = new BatchConfirmReviewReq(); + req.setIds(list.stream().map(ss -> ss.getId() + "").collect(Collectors.toList())); + Boolean rst = openApi.batchConfirmReview(req); + if (!rst) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "审核失败"); + } + + if (check.getCheckStatus() == AuditEnum.AUDIT_PASS) { + // 获取航次的离泊状态 + List collect = list.stream().map(ss -> ss.getVoyageId()).filter(ss -> !StringUtils.equalsAny(ss, "HT6", "HTLG", "HTTC")).distinct().collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(collect)) { + List shipmentBerthsStatusRespDTOS = shpApi.queryVoyagesBerthsStatusByVvyIds(collect); + if (CollectionUtils.isNotEmpty(shipmentBerthsStatusRespDTOS)) { + List strings = shipmentBerthsStatusRespDTOS.stream().filter(ss -> StringUtils.equalsAny(ss.getUnberthedStatus(), "1")).map(ss -> ss.getVvyId()).distinct().collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(strings)) { + customerExportInService.lambdaUpdate().in(CustomerExportIn::getVoyageId, strings) + .set(CustomerExportIn::getUnberthFlag, "1").update(); + } + } + } + } + } + + boolean row = customerExportInService.lambdaUpdate() + .set(CustomerExportIn::getCheckManId, UserContext.getUser().getUserId()) + .set(CustomerExportIn::getCheckTime, new Date()) + .set(CustomerExportIn::getCheckStatus, check.getCheckStatus()) + .set(CustomerExportIn::getCheckResult, check.getCheckResult()) + .setSql(check.getCheckStatus() == AuditEnum.AUDIT_REJECT, "voyage_id = case when port_area='外高桥' then 'HT6' when port_area='临港' then 'HTLG' when port_area='太仓' then 'HTTC' else voyage_id end, voyage = case when port_area='外高桥' then 'HT6' when port_area='临港' then 'HTLG' when port_area='太仓' then 'HTTC' else voyage end") + .eq(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_PASS) + .eq(CustomerExportIn::getShipId, check.getShipId()) + .in(CustomerExportIn::getVoyageId, voyageIds) + .in(CustomerExportIn::getBillNum, check.getBillNums()) + .update(); + + if (row) { + // 记录日志 + for (CustomerExportIn exportIn : list) { + LogRecordDTO log = new LogRecordDTO(); + log.setOperateData(exportIn); + log.setStatus(check.getCheckStatus() == AuditEnum.AUDIT_PASS ? 0 : 1); + log.setOperateTime(new Date()); + log.setUserId(UserContext.getUser().getUserId()); + log.setUserName(UserContext.getUser().getUsername()); + EsLogApprovalUtil.writeLog(log); + } + + if (check.getCheckStatus() == AuditEnum.AUDIT_PASS) { + customerService.syncAddExportInToOld(list); + } + + return ResultUtil.success("success"); + } + + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "没有可修改的数据"); + } + /** * 审核 * @@ -1320,11 +1794,36 @@ public class ExportInHandler implements BaseHandler { .eq(CustomerExportIn::getShipId, check.getShipId()) .eq(CustomerExportIn::getVoyageId, check.getVoyageId()).list(); + if (CollectionUtils.isNotEmpty(list)) { + BatchConfirmReviewReq req = new BatchConfirmReviewReq(); + req.setIds(list.stream().map(s -> s.getId() + "").collect(Collectors.toList())); + Boolean rst = openApi.batchConfirmReview(req); + if (!rst) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "审核失败"); + } + + if (check.getCheckStatus() == AuditEnum.AUDIT_PASS) { + // 获取航次的离泊状态 + List collect = list.stream().map(s -> s.getVoyageId()).filter(s -> !StringUtils.equalsAny(s, "HT6", "HTLG", "HTTC")).distinct().collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(collect)) { + List shipmentBerthsStatusRespDTOS = shpApi.queryVoyagesBerthsStatusByVvyIds(collect); + if (CollectionUtils.isNotEmpty(shipmentBerthsStatusRespDTOS)) { + List strings = shipmentBerthsStatusRespDTOS.stream().filter(s -> StringUtils.equalsAny(s.getUnberthedStatus(), "1")).map(s -> s.getVvyId()).distinct().collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(strings)) { + customerExportInService.lambdaUpdate().in(CustomerExportIn::getVoyageId, strings) + .set(CustomerExportIn::getUnberthFlag, "1").update(); + } + } + } + } + } + boolean row = customerExportInService.lambdaUpdate() .set(CustomerExportIn::getCheckManId, UserContext.getUser().getUserId()) .set(CustomerExportIn::getCheckTime, new Date()) .set(CustomerExportIn::getCheckStatus, check.getCheckStatus()) .set(CustomerExportIn::getCheckResult, check.getCheckResult()) + .setSql(check.getCheckStatus() == AuditEnum.AUDIT_REJECT, "voyage_id = case when port_area='外高桥' then 'HT6' when port_area='临港' then 'HTLG' when port_area='太仓' then 'HTTC' else voyage_id end, voyage = case when port_area='外高桥' then 'HT6' when port_area='临港' then 'HTLG' when port_area='太仓' then 'HTTC' else voyage end") .eq(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT) .eq(CustomerExportIn::getShipId, check.getShipId()) .eq(CustomerExportIn::getVoyageId, check.getVoyageId()) @@ -1337,8 +1836,8 @@ public class ExportInHandler implements BaseHandler { log.setOperateData(exportIn); log.setStatus(check.getCheckStatus() == AuditEnum.AUDIT_PASS ? 0 : 1); log.setOperateTime(new Date()); - log.setUserId(SecurityUtils.getUserId()); - log.setUserName(SecurityUtils.getUserName()); + log.setUserId(UserContext.getUser().getUserId()); + log.setUserName(UserContext.getUser().getUsername()); EsLogApprovalUtil.writeLog(log); } @@ -1361,6 +1860,8 @@ public class ExportInHandler implements BaseHandler { @Transactional(rollbackFor = {Exception.class}) public Result cancelCheck(@RequestBody @Validated(ValidationGroup.update.class) ExportInCheckVo check) throws Exception { List exportIns = new ArrayList<>(); + Map> cMap = new HashMap<>(); + for (Long id : check.getIds()) { // 需要判断,是否有出口装船审核通过的数据 @@ -1369,7 +1870,15 @@ public class ExportInHandler implements BaseHandler { return ResultUtil.failure(ErrorType.PROGRAM_ERROR.id(), "id:" + id + "不存在"); } - List havePlans = openApi.haveShipPlan(ei.getVoyageId()); + List havePlans = null; + if (!cMap.containsKey(ei.getVoyageId())) { + List c = openApi.haveShipPlan(ei.getVoyageId()); // 这个接口做个缓存处理 + cMap.put(ei.getVoyageId(), c); + } + if (cMap.containsKey(ei.getVoyageId())) { + havePlans = cMap.get(ei.getVoyageId()); + } + if (CollectionUtils.isNotEmpty(havePlans)) { Boolean c = havePlans.contains(ei.getId()); if (c) { @@ -1382,6 +1891,7 @@ public class ExportInHandler implements BaseHandler { exportIn.setId(id); exportIn.setCheckManId(UserContext.getUser().getUserId()); exportIn.setCheckStatus(AuditEnum.AUDIT); + exportIn.setCheckResult(""); exportIns.add(exportIn); } @@ -1467,28 +1977,70 @@ public class ExportInHandler implements BaseHandler { @Transactional(rollbackFor = {Exception.class}) @PostMapping("/update/shipVoyage/new") public Result shipVoyageUpdate(@RequestBody @Validated(ValidationGroup.insert.class) UpdateVoyageVo form) { + long b = System.currentTimeMillis(); + if (CollectionUtils.isEmpty(form.getIds()) && CollectionUtils.isEmpty(form.getBillNums())) { + return ResultUtil.failure(ErrorType.ERROR_PASS.id(), "ID列表或提单号列表不能都为空"); + } + String idsStr = StringUtils.join(form.getIds(), ","); List exportIns = customerExportInService.query() - .select("distinct voyage_id, ship_id") - .in("id", form.getIds()) + .eq("check_status", AuditEnum.AUDIT_PASS) + .exists("select id from customer_export_in B where B.ship_id=customer_export_in.ship_id and B.voyage_id = customer_export_in.voyage_id and B.bill_num=customer_export_in.bill_num and B.id in ("+idsStr+")") .list(); - if (exportIns.size() > 1) { + if (CollectionUtils.isEmpty(exportIns)) { + return ResultUtil.failure(ErrorType.ERROR_PASS.id(), "没有可修改的记录"); + } + + if (StringUtils.equalsIgnoreCase(form.getVoyage(), "HT6")) { + if (exportIns.stream().filter(s -> !StringUtils.equals(s.getPortArea(), "外高桥")).count() > 0) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "虚拟航次名错误"); + } + } else if (StringUtils.equalsIgnoreCase(form.getVoyage(), "HTTC")) { + if (exportIns.stream().filter(s -> !StringUtils.equals(s.getPortArea(), "太仓")).count() > 0) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "虚拟航次名错误"); + } + } else if (StringUtils.equalsIgnoreCase(form.getVoyage(), "HTLG")) { + if (exportIns.stream().filter(s -> !StringUtils.equals(s.getPortArea(), "临港")).count() > 0) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "虚拟航次名错误"); + } + } + + // 首先按对船名,般次,提单进行分组 + Map> collect = exportIns.stream() + .collect(Collectors.groupingBy(item -> StringUtils.joinWith("#$#", item.getShipId(), item.getVoyageId()), Collectors.toList())); + + if (collect.keySet().size() > 1) { return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "所选船名航次不同,不支持批量修改航次"); } // 判断是不是备件,如果是备件,则需要重新生成 - List exportInList = customerExportInService.lambdaQuery() - .in(CustomerExportIn::getId, form.getIds()).list(); - List havePlans = openApi.haveShipPlan(exportIns.get(0).getVoyageId()); - if (CollectionUtils.isNotEmpty(exportInList) && CollectionUtils.isNotEmpty(havePlans)) { - long c = exportInList.stream().filter(item -> havePlans.contains(item.getId())).count(); - if (c > 0) { - return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "已生成装船计划,不支持批量修改航次"); +// List havePlans = openApi.haveShipPlan(exportIns.get(0).getVoyageId()); +// if (CollectionUtils.isNotEmpty(exportIns) && CollectionUtils.isNotEmpty(havePlans)) { +// long c = exportIns.stream().filter(item -> havePlans.contains(item.getId())).count(); +// if (c > 0) { +// return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "已生成装船计划,不支持批量修改航次"); +// } +// } + + List ids = exportIns.stream().map(s -> s.getId()).collect(Collectors.toList()); + + log.info("批量修改航次,查询耗时:" + (System.currentTimeMillis() - b)); + + long b1 = System.currentTimeMillis(); + if (form.getValid() != null && form.getValid()) { + form.setIds(ids); + if (!openApi.batchConfirmRevise(form)) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "修改舱单失败"); } + log.info("批量修改航次,调用[/customer/yard/batchConfirmRevise]耗时:" + (System.currentTimeMillis() - b1)); } - exportInList.stream().filter(item -> StringUtils.equals("备件", item.getCartType()) && StringUtils.equalsAnyIgnoreCase(item.getVoyage(), "HT6", "HTTC", "HTLG")) + long b2 = System.currentTimeMillis(); + // 按提单号进行分组 + /* + Map> listMap = exportIns.stream().filter(item -> StringUtils.equals("备件", item.getCartType()) && StringUtils.equalsAnyIgnoreCase(item.getVoyage(), "HT6", "HTTC", "HTLG")).collect(Collectors.groupingBy(CustomerExportIn::getBillNum)); + exportIns.stream().filter(item -> StringUtils.equals("备件", item.getCartType()) && StringUtils.equalsAnyIgnoreCase(item.getVoyage(), "HT6", "HTTC", "HTLG")) .forEach(item -> { String vvyId = item.getVoyageId(); TransitPartRequest request = new TransitPartRequest(); @@ -1516,12 +2068,16 @@ public class ExportInHandler implements BaseHandler { customerExportInCargoService.saveBatch(spares); } }); + log.info("批量修改航次,调用[/customer/shipment/shipLoad/transitPart, 同步虚拟航次备件]耗时:" + (System.currentTimeMillis() - b2)); + */ + long b3 = System.currentTimeMillis(); customerExportInService.lambdaUpdate() .set(CustomerExportIn::getVoyageId, form.getVoyageId()) .set(CustomerExportIn::getVoyage, form.getVoyage()) - .in(CustomerExportIn::getId, form.getIds()) + .in(CustomerExportIn::getId, ids) .update(); + log.info("批量修改航次,修改耗时:" + (System.currentTimeMillis() - b3)); return ResultUtil.success("success"); } @@ -1593,17 +2149,23 @@ public class ExportInHandler implements BaseHandler { if (CollectionUtils.isNotEmpty(exists)) { List list = customerExportInService.lambdaQuery().in(CustomerExportIn::getId, exists.stream().map(item -> item.getExportInId()).collect(Collectors.toList())).list(); Map portAreaMap = list.stream().collect(Collectors.toMap(CustomerExportIn::getId, CustomerExportIn::getPortAreaId)); + Map vvyIdMap = list.stream().collect(Collectors.toMap(CustomerExportIn::getId, CustomerExportIn::getVoyageId)); // 通过接口再次验证 List req = exists.stream().map(item -> { CheckVinReq v = new CheckVinReq(); v.setIsRepetition(true); v.setPamId(portAreaMap.get(item.getExportInId())); v.setVinCode(item.getVin()); + v.setVvyId(vvyIdMap.get(item.getExportInId())); return v; }).collect(Collectors.toList()); List rst = shpApi.checkVinRepeat(req); existVins.clear(); if (CollectionUtils.isNotEmpty(rst)) { + List strings = rst.stream().filter(ss -> !ss.getIsRepetition()).map(s -> s.getVinCode()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(strings)) { + log.info("接口验证,可以再次导入的车架号:" + strings.stream().collect(Collectors.joining(","))); + } // 再次过滤出重复的 List collect = rst.stream().filter(item -> item.getIsRepetition()).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(collect)) { @@ -1696,17 +2258,23 @@ public class ExportInHandler implements BaseHandler { // 查询出对应的港区 List sList = customerExportInService.lambdaQuery().in(CustomerExportIn::getId, existCargos.stream().map(ss -> ss.getExportInId()).collect(Collectors.toList())).list(); Map portAreaMap = sList.stream().collect(Collectors.toMap(CustomerExportIn::getId, CustomerExportIn::getPortAreaId)); + Map vvyIdMap = sList.stream().collect(Collectors.toMap(CustomerExportIn::getId, CustomerExportIn::getVoyageId)); // 通过接口再次验证 List req = existCargos.stream().map(ss -> { CheckVinReq v = new CheckVinReq(); v.setIsRepetition(true); v.setPamId(portAreaMap.get(ss.getExportInId())); v.setVinCode(ss.getVin()); + v.setVvyId(vvyIdMap.get(ss.getExportInId())); return v; }).collect(Collectors.toList()); List rst = shpApi.checkVinRepeat(req); existVins.clear(); if (CollectionUtils.isNotEmpty(rst)) { + List strings = rst.stream().filter(ss -> !ss.getIsRepetition()).map(s -> s.getVinCode()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(strings)) { + log.info("接口验证,可以再次导入的车架号:" + strings.stream().collect(Collectors.joining(","))); + } // 再次过滤出重复的 List sCollect = rst.stream().filter(ss -> ss.getIsRepetition()).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(sCollect)) { @@ -1762,6 +2330,8 @@ public class ExportInHandler implements BaseHandler { } return ResultUtil.success(rst); + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:" + e.getRowIndex() + " 列:" + e.getColumnIndex()); } catch (Exception e) { log.error("错误信息", e); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), e.getMessage()); @@ -1859,6 +2429,11 @@ public class ExportInHandler implements BaseHandler { }); if (CollectionUtils.isEmpty(validData)) { + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } @@ -1922,17 +2497,23 @@ public class ExportInHandler implements BaseHandler { // 查询出对应的港区 List sList = customerExportInService.lambdaQuery().in(CustomerExportIn::getId, existCargos.stream().map(ss -> ss.getExportInId()).collect(Collectors.toList())).list(); Map portAreaMap = sList.stream().collect(Collectors.toMap(CustomerExportIn::getId, CustomerExportIn::getPortAreaId)); + Map vvyIdMap = sList.stream().collect(Collectors.toMap(CustomerExportIn::getId, CustomerExportIn::getVoyageId)); // 通过接口再次验证 List req = existCargos.stream().map(ss -> { CheckVinReq v = new CheckVinReq(); v.setIsRepetition(true); v.setPamId(portAreaMap.get(ss.getExportInId())); v.setVinCode(ss.getVin()); + v.setVvyId(vvyIdMap.get(ss.getExportInId())); return v; }).collect(Collectors.toList()); List rst = shpApi.checkVinRepeat(req); existVins.clear(); if (CollectionUtils.isNotEmpty(rst)) { + List strings = rst.stream().filter(ss -> !ss.getIsRepetition()).map(s -> s.getVinCode()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(strings)) { + log.info("接口验证,可以再次导入的车架号:" + strings.stream().collect(Collectors.joining(","))); + } // 再次过滤出重复的 List sCollect = rst.stream().filter(ss -> ss.getIsRepetition()).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(sCollect)) { @@ -1961,7 +2542,7 @@ public class ExportInHandler implements BaseHandler { }); if (CollectionUtils.isNotEmpty(errorDataList)) { - errorDataList.addAll(successDataList); +// errorDataList.addAll(successDataList); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } @@ -1972,6 +2553,8 @@ public class ExportInHandler implements BaseHandler { } return ResultUtil.success(errorDataList); + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:" + e.getRowIndex() + " 列:" + e.getColumnIndex()); } catch (Exception e) { log.error("错误信息", e); return ResultUtil.failure(ErrorType.PROGRAM_ERROR.id(), e.getMessage()); @@ -2068,6 +2651,11 @@ public class ExportInHandler implements BaseHandler { }); if (CollectionUtils.isEmpty(validData)) { + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } @@ -2077,7 +2665,7 @@ public class ExportInHandler implements BaseHandler { if (CollectionUtils.isNotEmpty(repeat)) { errorDataList.addAll(validData.stream().filter(p -> repeat.contains(p.getVin())).map(p -> { JSONObject o = JSONObject.from(p); - o.put("status", "车架号重复"); + o.put("status", "备件号重复"); return o; }).collect(Collectors.toList())); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); @@ -2116,17 +2704,23 @@ public class ExportInHandler implements BaseHandler { // 查询出对应的港区 List sList = customerExportInService.lambdaQuery().in(CustomerExportIn::getId, existCargos.stream().map(ss -> ss.getExportInId()).collect(Collectors.toList())).list(); Map portAreaMap = sList.stream().collect(Collectors.toMap(CustomerExportIn::getId, CustomerExportIn::getPortAreaId)); + Map vvyIdMap = sList.stream().collect(Collectors.toMap(CustomerExportIn::getId, CustomerExportIn::getVoyageId)); // 通过接口再次验证 List req = existCargos.stream().map(ss -> { CheckVinReq v = new CheckVinReq(); v.setIsRepetition(true); v.setPamId(portAreaMap.get(ss.getExportInId())); v.setVinCode(ss.getVin()); + v.setVvyId(vvyIdMap.get(ss.getExportInId())); return v; }).collect(Collectors.toList()); List rst = shpApi.checkVinRepeat(req); existVins.clear(); if (CollectionUtils.isNotEmpty(rst)) { + List strings = rst.stream().filter(ss -> !ss.getIsRepetition()).map(s -> s.getVinCode()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(strings)) { + log.info("接口验证,可以再次导入的车架号:" + strings.stream().collect(Collectors.joining(","))); + } // 再次过滤出重复的 List sCollect = rst.stream().filter(ss -> ss.getIsRepetition()).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(sCollect)) { @@ -2154,7 +2748,7 @@ public class ExportInHandler implements BaseHandler { saveCargos.addAll(cargos.stream().filter(p -> !existVins.contains(p.getVin())).collect(Collectors.toList())); if (CollectionUtils.isNotEmpty(errorDataList)) { - errorDataList.addAll(successDataList); +// errorDataList.addAll(successDataList); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } @@ -2165,6 +2759,8 @@ public class ExportInHandler implements BaseHandler { } return ResultUtil.success(errorDataList); + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:" + e.getRowIndex() + " 列:" + e.getColumnIndex()); } catch (Exception e) { log.error("错误信息", e); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), e.getMessage()); @@ -2258,12 +2854,29 @@ public class ExportInHandler implements BaseHandler { // 所有数据验证都不通过 if (CollectionUtils.isEmpty(validData)) { + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } // 模型去空格处理 validData.stream().forEach(item -> item.setModels(StringUtils.trim(item.getModels()))); + // 是否有重复的车架号 + List repeat = validData.stream().collect(Collectors.groupingBy(ExportInExcel::getVin, Collectors.counting())) + .entrySet().stream().filter(entry -> entry.getValue() > 1).map(entry -> entry.getKey()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(repeat)) { + errorDataList.addAll(validData.stream().filter(p -> repeat.contains(p.getVin())).map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "车架号重复"); + return o; + }).collect(Collectors.toList())); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + // 首先按对船名,般次,提单进行分组 Map> collect = validData.stream() .collect(Collectors.groupingBy(item -> StringUtils.joinWith("#$#", item.getShipName(), item.getVoyage(), item.getBillNo(), item.getBrand(), item.getModels()), Collectors.toList())); @@ -2285,19 +2898,6 @@ public class ExportInHandler implements BaseHandler { .eq(CustomerExportIn::getModels, models) .ne(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_REJECT) .ne(CustomerExportIn::getCartType, "备件"); // 备件的不允许整船导入 -// if (StringUtils.equals(type, "0")) { -// cQuery.and((wrapper) -> { -// wrapper.eq(CustomerExportIn::getCheckStatus, AuditEnum.SUBMIT) -// .or() -// .eq(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_REJECT); -// }); -// } else { -// cQuery.and((wrapper) -> { -// wrapper.eq(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT) -// .or() -// .eq(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_REJECT); -// }); -// } // 同一个型号可能存在多个进港计划 @@ -2315,9 +2915,6 @@ public class ExportInHandler implements BaseHandler { // 计划总数量 int planQuantity = exportInList.stream().mapToInt(p -> p.getQuantity()).sum(); - // 找到和本次数量一致的 -// Optional first = exportInList.stream().filter(p -> p.getQuantity() == item.getValue().size()).findFirst(); - CustomerExportIn exportIn = exportInList.get(0); if (planQuantity != item.getValue().size()) { @@ -2330,7 +2927,6 @@ public class ExportInHandler implements BaseHandler { } ids.addAll(exportInList.stream().map(p -> p.getId()).collect(Collectors.toList())); -// ids.add(exportIn.getId()); // 已生成装船计划,不能导入 List havePlans = openApi.haveShipPlan(exportIn.getVoyageId()); @@ -2346,23 +2942,6 @@ public class ExportInHandler implements BaseHandler { } } -// if (exportIn.getCheckStatus() == AuditEnum.AUDIT_PASS) { // 审核 -// errorDataList.addAll(item.getValue().stream().map(p -> { -// JSONObject o = JSONObject.from(p); -// o.put("status", "审核通过状态的不可导入"); -// return o; -// }).collect(Collectors.toList())); -// return; -// } - -// if (exportIn.getEnterQuantity() != item.getValue().size()) { -// errorDataList.addAll(item.getValue().stream().map(p -> { -// JSONObject o = JSONObject.from(p); -// o.put("status", "车架号数量和实际货物数量不符合,无法导入"); -// return o; -// }).collect(Collectors.toList())); -// return; -// } // 按计划中的件数进行VIN的分配 int j = 0; List cargos = new ArrayList<>(); @@ -2382,42 +2961,36 @@ public class ExportInHandler implements BaseHandler { } } -// List cargos = item.getValue().stream().map(p -> { -// CustomerExportInCargo cargo = new CustomerExportInCargo(); -// cargo.setBrandId(exportIn.getBrandId()); -// cargo.setBrand(exportIn.getBrand()); -// cargo.setExportInId(exportIn.getId()); -// cargo.setCargoType(0); -// cargo.setVin(p.getVin()); -// cargo.setTermcd(exportIn.getPortAreaId()); -// cargo.setVinStatus(1); -// return cargo; -// }).collect(Collectors.toList()); - List vins = cargos.stream().map(p -> p.getVin()).collect(Collectors.toList()); // 验证哪些车架号已经存在了 List existCargos = customerExportInCargoService .list(new LambdaQueryWrapper().in(CustomerExportInCargo::getVin, vins) .notExists("select id from customer_export_in where customer_export_in.id=customer_export_in_cargo.export_in_id and customer_export_in.check_status={0}", AuditEnum.AUDIT_REJECT) - .ne(CustomerExportInCargo::getExportInId, exportIn.getId())); + .notIn(CustomerExportInCargo::getExportInId, exportInList.stream().map(s -> s.getId()).collect(Collectors.toList()))); List existVins = existCargos.stream().map(p -> p.getVin()).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(existCargos)) { // 查询出对应的港区 List sList = customerExportInService.lambdaQuery().in(CustomerExportIn::getId, existCargos.stream().map(ss -> ss.getExportInId()).collect(Collectors.toList())).list(); Map portAreaMap = sList.stream().collect(Collectors.toMap(CustomerExportIn::getId, CustomerExportIn::getPortAreaId)); + Map vvyIdMap = sList.stream().collect(Collectors.toMap(CustomerExportIn::getId, CustomerExportIn::getVoyageId)); // 通过接口再次验证 List req = existCargos.stream().map(ss -> { CheckVinReq v = new CheckVinReq(); v.setIsRepetition(true); v.setPamId(portAreaMap.get(ss.getExportInId())); v.setVinCode(ss.getVin()); + v.setVvyId(vvyIdMap.get(ss.getExportInId())); return v; }).collect(Collectors.toList()); List rst = shpApi.checkVinRepeat(req); existVins.clear(); // 先清空 if (CollectionUtils.isNotEmpty(rst)) { + List strings = rst.stream().filter(ss -> !ss.getIsRepetition()).map(s -> s.getVinCode()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(strings)) { + log.info("接口验证,可以再次导入的车架号:" + strings.stream().collect(Collectors.joining(","))); + } // 再次过滤出重复的 List sCollect = rst.stream().filter(ss -> ss.getIsRepetition()).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(sCollect)) { @@ -2428,9 +3001,13 @@ public class ExportInHandler implements BaseHandler { List existData = item.getValue().stream().filter(p -> existVins.contains(p.getVin())).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(existData)) { + // 获取使用货代 + List ts = existCargos.stream().map(s -> s.getExportInId()).distinct().collect(Collectors.toList()); + Map inMap = customerExportInService.lambdaQuery().in(CustomerExportIn::getId, ts).list().stream().collect(Collectors.toMap(CustomerExportIn::getId, s -> s)); errorDataList.addAll(existData.stream().map(p -> { + CustomerExportInCargo inCargo = existCargos.stream().filter(s -> StringUtils.equals(s.getVin(), p.getVin())).findFirst().get(); JSONObject o = JSONObject.from(p); - o.put("status", "数据已存在, 未导入"); + o.put("status", "车架号被" + inMap.get(inCargo.getExportInId()).getFreight() + "货代已使用,未导入"); return o; }).collect(Collectors.toList())); successDataList.addAll(item.getValue().stream().filter(p -> !existVins.contains(p.getVin())) @@ -2454,7 +3031,7 @@ public class ExportInHandler implements BaseHandler { }); if (CollectionUtils.isNotEmpty(errorDataList)) { - errorDataList.addAll(successDataList); +// errorDataList.addAll(successDataList); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } @@ -2465,6 +3042,8 @@ public class ExportInHandler implements BaseHandler { } return ResultUtil.success(errorDataList); + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:" + e.getRowIndex() + " 列:" + e.getColumnIndex()); } catch (Exception e) { log.error("错误信息", e); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), e.getMessage()); @@ -2532,7 +3111,7 @@ public class ExportInHandler implements BaseHandler { try { - EasyExcel.read(file.getInputStream(), ExportLoadExcel.class, new ReadExcelListener() { + EasyExcel.read(file.getInputStream(), ExportInBillSpareExcel.class, new ReadExcelListener() { @Override protected void saveData(List list) { // 保存数据 dataList.addAll(list); @@ -2558,6 +3137,23 @@ public class ExportInHandler implements BaseHandler { // 所有数据验证都不通过 if (CollectionUtils.isEmpty(validData)) { + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + // 是否有重复的车架号 + List repeat = validData.stream().collect(Collectors.groupingBy(ExportInBillSpareExcel::getVin, Collectors.counting())) + .entrySet().stream().filter(entry -> entry.getValue() > 1).map(entry -> entry.getKey()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(repeat)) { + errorDataList.addAll(validData.stream().filter(p -> repeat.contains(p.getVin())).map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "备件号重复"); + return o; + }).collect(Collectors.toList())); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } @@ -2676,17 +3272,23 @@ public class ExportInHandler implements BaseHandler { // 查询出对应的港区 List sList = customerExportInService.lambdaQuery().in(CustomerExportIn::getId, existCargos.stream().map(ss -> ss.getExportInId()).collect(Collectors.toList())).list(); Map portAreaMap = sList.stream().collect(Collectors.toMap(CustomerExportIn::getId, CustomerExportIn::getPortAreaId)); + Map vvyIdMap = sList.stream().collect(Collectors.toMap(CustomerExportIn::getId, CustomerExportIn::getVoyageId)); // 通过接口再次验证 List req = existCargos.stream().map(ss -> { CheckVinReq v = new CheckVinReq(); v.setIsRepetition(true); v.setPamId(portAreaMap.get(ss.getExportInId())); v.setVinCode(ss.getVin()); + v.setVvyId(vvyIdMap.get(ss.getExportInId())); return v; }).collect(Collectors.toList()); List rst = shpApi.checkVinRepeat(req); existVins.clear(); // 先清空 if (CollectionUtils.isNotEmpty(rst)) { + List strings = rst.stream().filter(ss -> !ss.getIsRepetition()).map(s -> s.getVinCode()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(strings)) { + log.info("接口验证,可以再次导入的车架号:" + strings.stream().collect(Collectors.joining(","))); + } // 再次过滤出重复的 List sCollect = rst.stream().filter(ss -> ss.getIsRepetition()).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(sCollect)) { @@ -2723,7 +3325,7 @@ public class ExportInHandler implements BaseHandler { }); if (CollectionUtils.isNotEmpty(errorDataList)) { - errorDataList.addAll(successDataList); +// errorDataList.addAll(successDataList); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } @@ -2734,6 +3336,8 @@ public class ExportInHandler implements BaseHandler { } return ResultUtil.success(errorDataList); + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:" + e.getRowIndex() + " 列:" + e.getColumnIndex()); } catch (Exception e) { log.error("错误信息", e); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), e.getMessage()); @@ -2788,9 +3392,13 @@ public class ExportInHandler implements BaseHandler { } query.setPage(1); query.setRows(500); - Wrapper queryWrapper = new WrapperKit() { + query.setSorts(null); +// query.setSorts(Arrays.asList(new BaseQuery.SortField("shipId", "asc"), new BaseQuery.SortField("voyageId", "asc"), new BaseQuery.SortField("billNum", "asc"))); + QueryWrapper queryWrapper = (QueryWrapper) new WrapperKit() { }.changeBaseQueryToWrapper(CustomerExportIn.class, query); + queryWrapper.orderByAsc(Arrays.asList("voyage_id", "bill_num")); + ExcelWriter excelWriter = null; OutputStream out = null; try { @@ -2804,7 +3412,7 @@ public class ExportInHandler implements BaseHandler { response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); //合并坐标 - int[] mergeColumeIndex = {22,23,24}; + int[] mergeColumeIndex = {22, 23, 24}; //从第二行后开始合并 int mergeRowIndex = 1; @@ -2853,6 +3461,7 @@ public class ExportInHandler implements BaseHandler { List rows = headers.stream().map(item -> { ExportInExportExcel e = PoMapper.instance.entity2Excel(item); e.setSerialNo(index.getAndIncrement()); + e.setCheckStatus(item.getCheckStatus().text()); return e; }).collect(Collectors.toList()); @@ -2861,34 +3470,31 @@ public class ExportInHandler implements BaseHandler { // 头映射 Map collect = headers.stream().collect(Collectors.toMap(item -> item.getId(), item -> item)); // 处理明细数据 - List list = customerExportInCargoService.lambdaQuery().in(CustomerExportInCargo::getExportInId, headers.stream().map(item -> item.getId()).collect(Collectors.toList())).list(); + List cargos = customerExportInCargoService.lambdaQuery().in(CustomerExportInCargo::getExportInId, headers.stream().map(item -> item.getId()).collect(Collectors.toList())).list(); - // 通过接口获取进场时间和位置 - headers.stream().forEach(item -> { - List cargos = list.stream().filter(p -> Long.compare(p.getExportInId(), item.getId()) == 0).collect(Collectors.toList()); - if (CollectionUtils.isEmpty(cargos)) return; + if (CollectionUtils.isNotEmpty(cargos)) { - GoodsStatusReq req = new GoodsStatusReq(); - req.setBusinessType("IN_PORT"); - req.setImportExportType("E"); - req.setVvyId(StringUtils.equalsAnyIgnoreCase(item.getVoyageId(), "HT6", "HTLG", "HTTC") ? "" : item.getVoyageId()); - req.setVinCodeList(cargos.stream().map(p -> p.getVin()).collect(Collectors.toList())); + GoodsStatusReq req = new GoodsStatusReq(); + req.setBusinessType("IN_PORT"); + req.setImportExportType("E"); +// req.setVvyId(StringUtils.equalsAnyIgnoreCase(item.getKey(), "HT6", "HTLG", "HTTC") ? "" : item.getKey()); + req.setVinCodeList(cargos.stream().map(p -> p.getVin()).collect(Collectors.toList())); - List resp = openApi.getGoodsStatus(req); + List resp = openApi.getGoodsStatus(req); - Map respMap = resp.stream().collect(Collectors.toMap(p -> p.getVinCode(), p -> p)); + Map respMap = resp.stream().collect(Collectors.toMap(p -> p.getVinCode(), p -> p)); - cargos.stream().forEach(p -> { - GoodsStatusResp r = respMap.get(p.getVin()); - if (r != null) { - p.setEnterPortTime(r.getInTime()); - p.setPosition(r.getPosition()); - } - }); + cargos.stream().forEach(p -> { + GoodsStatusResp r = respMap.get(p.getVin()); + if (r != null) { + p.setEnterPortTime(r.getInTime()); + p.setPosition(r.getPosition()); + } + }); + } - }); - List details = list.stream().map(item -> { + List details = cargos.stream().map(item -> { ExportInCargoExportExcel e = PoMapper.instance.entity2Excel(collect.get(item.getExportInId()), item); return e; }).collect(Collectors.toList()); @@ -3164,44 +3770,6 @@ public class ExportInHandler implements BaseHandler { try { - // 获取用户绑定的货代 - List userBindFreight = openApi.getUserBindFreight(); - - PubMappingMapDto pubMapping = pubApi.getPubMapping(); - - // 国家数据 - List countryList = openApi.getCountryList(); - // 港口基础数据 - List portList = dictHandler.getPortList(null).getData(); - // 船名基础数据 - List shipList = dictHandler.getAllShip(null).getData(); - // 港区基础数据 - List portAreaList = dictHandler.getPortAreaList(null).getData(); - // 品牌基础数据 - List brandList = dictHandler.getBrandList(null).getData(); - // 车型基础数据 - List carTypeList = dictHandler.getCartTypeList(null).getData(); - // 产地基础数据 - List originPlaceList = dictHandler.getAllCountryList(null).getData(); - // 运输模式 - List transportWayList = dictHandler.getTransportWayList(null).getData(); - // 操作模式 - List operateTypeList = dictHandler.getOperateTypeList(null).getData(); - // 特殊作业 - List specWorkList = dictHandler.getSpecWorkList().getData(); - // 新能源类型 - List energyTypeList = dictHandler.getEnergyTypeList().getData(); - // 根据港口ID 获取国家 - // Map portCountryList = new HashMap<>(); - // 货代列表 - Map companyMap = new HashMap<>(); - // 货物性质 - List goodsNature = dictHandler.getGoodsNature().getData(); - // 车型明细缓存 - Map> carDetailTypeList = new HashMap<>(); - // 航次缴存 - Map> voyageMap = new HashMap<>(); - EasyExcel.read(file.getInputStream(), ExportInPlanExcel.class, new ReadExcelListener() { @Override protected void saveData(List list) { // 保存数据 @@ -3230,9 +3798,55 @@ public class ExportInHandler implements BaseHandler { }); if (CollectionUtils.isEmpty(validData)) { // 数据完整性检验 + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } + // 获取用户绑定的货代 + List userBindFreight = openApi.getUserBindFreight(); + + PubMappingMapDto pubMapping = pubApi.getPubMapping(); + + // 国家数据 + List countryList = openApi.getCountryList(); + // 港口基础数据 + List portList = dictHandler.getPortList(null).getData(); +// // 船名基础数据 + List shipList = dictHandler.getAllShip(null).getData(); + // 旬度计划船名 +// Map> trendShipMap = new HashMap<>(); + List trendShipList = openApi.getTrendShipList(validData.stream().map(s -> s.getShipName()).distinct().collect(Collectors.toList())); + // 港区基础数据 + List portAreaList = dictHandler.getPortAreaList(null).getData(); + // 品牌基础数据 + List brandList = dictHandler.getBrandList(null).getData(); + // 车型基础数据 + List carTypeList = dictHandler.getCartTypeList(null).getData(); + // 产地基础数据 + List originPlaceList = dictHandler.getAllCountryList(null).getData(); + // 运输模式 + List transportWayList = dictHandler.getTransportWayList(null).getData(); + // 操作模式 + List operateTypeList = dictHandler.getOperateTypeList(null).getData(); + // 特殊作业 + List specWorkList = dictHandler.getSpecWorkList().getData(); + // 新能源类型 + List energyTypeList = dictHandler.getEnergyTypeList().getData(); + // 根据港口ID 获取国家 + // Map portCountryList = new HashMap<>(); + // 货代列表 + Map companyMap = new HashMap<>(); + // 货物性质 + List goodsNature = dictHandler.getGoodsNature().getData(); + // 车型明细缓存 + Map> carDetailTypeList = new HashMap<>(); + // 航次缴存 + Map> voyageMap = new HashMap<>(); + // 港区、船名、港口、品牌、车型 validData.stream().forEach(item -> { if (countryList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getCtyCnname(), item.getCountry())).count() == 0) { @@ -3254,7 +3868,7 @@ public class ExportInHandler implements BaseHandler { errorDataList.add(o); return; } - if (shipList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), item.getShipName())).count() == 0) { + if (trendShipList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getSpmName(), item.getShipName())).count() == 0) { JSONObject o = JSONObject.from(item); o.put("status", "船名不存在"); errorDataList.add(o); @@ -3387,7 +4001,7 @@ public class ExportInHandler implements BaseHandler { errorDataList.add(o); return; } - if (!StringUtils.equals(item.getNatureFlagName(), "正常")) { + if (StringUtils.equalsAny(item.getNatureFlagName(), "内进转外出", "外进转内出", "国际中转", "国内中转")) { if (shipList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), item.getTransferShipName())).count() == 0) { JSONObject o = JSONObject.from(item); o.put("status", "中转进口船名不存在"); @@ -3441,7 +4055,7 @@ public class ExportInHandler implements BaseHandler { }); if (CollectionUtils.isNotEmpty(errorDataList)) { - errorDataList.addAll(successDataList); +// errorDataList.addAll(successDataList); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } @@ -3461,8 +4075,9 @@ public class ExportInHandler implements BaseHandler { in.setTmpEnterDate(d); } - in.setShipId(shipList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), item.getShipName())).findFirst().get().getId()); - in.setShipEnName(shipList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), item.getShipName())).findFirst().get().getExtra1()); + in.setShipId(trendShipList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getSpmName(), item.getShipName())).findFirst().get().getSpmId()); + in.setShipEnName(trendShipList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getSpmName(), item.getShipName())).findFirst().get().getSpmEname()); + in.setPreArrivalTime(trendShipList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getSpmName(), item.getShipName())).findFirst().get().getPlanArrivePortTime()); in.setPortAreaId(portAreaList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), item.getPortArea())).findFirst().get().getId()); in.setBrandId(brandList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), item.getBrand())).findFirst().get().getId()); in.setCartTypeId(carTypeList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), item.getCartType())).findFirst().get().getId()); @@ -3521,10 +4136,26 @@ public class ExportInHandler implements BaseHandler { // 验证件,毛,体 // 件数 int totalQuantity = exportInList.stream().mapToInt(CustomerExportIn::getQuantity).sum() + item.getValue().stream().mapToInt(CustomerExportIn::getQuantity).sum(); + // 是否有其它的货代用了些提单号 + List repeatBillNum = exportInList.stream().filter(s -> !StringUtils.equals(s.getFreightId(), lastE.getFreightId())).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(repeatBillNum)) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "当前已有其他货代" + repeatBillNum.get(0).getFreight() + "使用该提单号,不可重复申请"); + return o; + }).collect(Collectors.toList())); + return; + } if (totalQuantity > lastE.getEachQuantity()) { errorDataList.addAll(item.getValue().stream().map(p -> { JSONObject o = JSONObject.from(p); - o.put("status", "数量不得超过单票件数"); + Optional first = exportInList.stream().filter(s -> !StringUtils.equals(s.getFreightId(), lastE.getFreightId())).findFirst(); + if (first.isPresent()) { + String str = first.get().getFreight(); + o.put("status", "同提单数量之和超过单票数量 注:当前已有其他货代【" + str + "】使用该提单号"); + } else { + o.put("status", "同提单数量之和超过单票数量"); + } return o; }).collect(Collectors.toList())); return; @@ -3558,7 +4189,7 @@ public class ExportInHandler implements BaseHandler { }); if (CollectionUtils.isNotEmpty(errorDataList)) { - errorDataList.addAll(successDataList); +// errorDataList.addAll(successDataList); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } @@ -3593,13 +4224,7 @@ public class ExportInHandler implements BaseHandler { if (StringUtils.equals(ss.getNatureFlagName(), "正常")) { // 需要自动生成 // vins.addAll(rst.get(vvyId).stream().map(t -> t.getVinCode()).collect(Collectors.toList())); // 出口进场计划备件条码生成的规则要变一下,BJ+年月日时分+5随机数,一共要17位 - String prefix = StringUtils.join("BJ", DateUtil.format(new Date(), "yyMMddHHmm")); - do { - String vin = prefix + RandomUtil.randomNumbers(5); - if (!vins.contains(vin)) { - vins.add(vin); - } - } while (vins.size() < ss.getQuantity()); + vins = genBjNo(ss.getQuantity(), null); } List spares = vins.stream().map(p -> { CustomerExportInCargo entity = new CustomerExportInCargo(); @@ -3638,6 +4263,8 @@ public class ExportInHandler implements BaseHandler { customerService.saveExportIn(ss, null, times, null); }); }); + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:" + e.getRowIndex() + " 列:" + e.getColumnIndex()); } catch (Exception e) { log.error("上传错误", e); return ResultUtil.failure(ErrorType.PROGRAM_ERROR.id(), e.getMessage()); @@ -3689,15 +4316,17 @@ public class ExportInHandler implements BaseHandler { @ApiOperation("出口进场计划船名航次") @PostMapping("/plan/ship") public Result> getExportInPlanShipList( - @RequestParam(required = false) @NotBlank(message = "港区ID不能为空") String portAreaId, + @RequestParam(required = false) String portAreaId, @RequestParam(required = false, defaultValue = "1") Integer current, @RequestParam(required = false, defaultValue = "10") Integer size, @RequestParam(required = false) String q) { QueryWrapper query = new QueryWrapper<>(); query.select("distinct ship_id, ship_name, ship_en_name"); query.eq("check_status", AuditEnum.AUDIT_PASS); - query.eq("port_area_id", portAreaId); + query.eq(StringUtils.isNotEmpty(portAreaId), "port_area_id", portAreaId); query.eq("load_ship_flag", 0); + query.eq("unberth_flag", 0); + query.gt("end_enter_time", DateUtils.getDayStart(DateUtils.addDay(new Date(), -15))); if (StringUtils.isNotEmpty(q)) { query.and((wrapper) -> { wrapper.like("ship_name", q); @@ -3730,6 +4359,16 @@ public class ExportInHandler implements BaseHandler { return ResultUtil.success("success"); } + @ApiOperation("离泊确认状态通知") + @PostMapping("/unberth/confirm") + public Result unberthConfirm(@RequestBody @Validated ShipStatusVo vo) { + customerExportInService.lambdaUpdate().eq(CustomerExportIn::getShipId, vo.getShipId()) + .eq(CustomerExportIn::getVoyageId, vo.getVoyageId()) + .set(CustomerExportIn::getUnberthFlag, StringUtils.equals("0", vo.getStatus()) ? 0 : 1) + .update(); + return ResultUtil.success("success"); + } + @ApiOperation("出口进场计划航次") @PostMapping("/plan/voyage") public Result> getPlanVoyageList( @@ -3816,4 +4455,209 @@ public class ExportInHandler implements BaseHandler { return ResultUtil.success(rst, String.valueOf(page.getTotal())); } + + @ApiOperation("同步预进港时间") + @PostMapping("/update/preArrivalTime") + public Result getCheckShipList(@RequestBody @Validated UpdatePreArrivalTimeVo form) { + if (StringUtils.equalsAny(form.getNewVoyage(), "HT6", "HTTC", "HTLG")) { + // 查找出港区 + Page page = customerExportInService.lambdaQuery() + .eq(CustomerExportIn::getShipId, form.getShipId()) + .eq(CustomerExportIn::getVoyageId, form.getVoyageId()) + .page(new Page<>(1, 1)); + + if (CollectionUtils.isEmpty(page.getRecords())) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "没有可修改的记录"); + } + + String portArea = page.getRecords().get(0).getPortArea(); + + if (StringUtils.equalsIgnoreCase(form.getNewVoyage(), "HT6") && StringUtils.equals(portArea, "外高桥")) { + + } else if (StringUtils.equalsIgnoreCase(form.getNewVoyage(), "HTTC") && StringUtils.equals(portArea, "太仓")) { + + } else if (StringUtils.equalsIgnoreCase(form.getNewVoyage(), "HTLG") && StringUtils.equals(portArea, "临港")) { + + } else { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "虚拟航次名错误"); + } + } + customerExportInService.lambdaUpdate() + .eq(CustomerExportIn::getShipId, form.getShipId()) + .eq(CustomerExportIn::getVoyageId, form.getVoyageId()) + .eq(form.getOldPreArrivalTime() != null, CustomerExportIn::getPreArrivalTime, form.getOldPreArrivalTime()) + .set(CustomerExportIn::getPreArrivalTime, form.getPreArrivalTime()) + .set(StringUtils.equalsAny(form.getNewVoyage(), "HT6", "HTTC", "HTLG"), CustomerExportIn::getVoyageId, form.getNewVoyage()) + .set(StringUtils.isNotEmpty(form.getNewVoyage()), CustomerExportIn::getVoyage, form.getNewVoyage()) + .update(); + if (StringUtils.isNotEmpty(form.getNewVoyage())) { + customerExportLoadService.lambdaUpdate() + .eq(CustomerExportLoad::getShipId, form.getShipId()) + .eq(CustomerExportLoad::getVoyageId, form.getVoyageId()) + .set(StringUtils.isNotEmpty(form.getNewVoyage()), CustomerExportLoad::getVoyage, form.getNewVoyage()) + .set(StringUtils.equalsAny(form.getNewVoyage(), "HT6", "HTTC", "HTLG"), CustomerExportLoad::getVoyageId, form.getNewVoyage()) + .update(); + } + + return ResultUtil.success("success"); + } + + @ApiOperation("同步预靠泊时间时间") + @PostMapping("/update/planArrivePortTime") + public Result getCheckShipList(@RequestBody @Validated UpdatePlanArrivePortVo form) { + customerExportInService.lambdaUpdate() + .eq(CustomerExportIn::getShipId, form.getShipId()) + .eq(CustomerExportIn::getVoyageId, form.getVoyageId()) + .set(CustomerExportIn::getPlanArrivePortTime, form.getPlanArrivePortTime()) + .update(); + + return ResultUtil.success("success"); + } + + @ApiOperation("审核端批量获取进港信息") + @PostMapping("/check/batchCheckShip/list") + public Result> getCheckShipList(@RequestBody @Validated ExportInBathCheckQuery query) { + QueryWrapper cQuery = new QueryWrapper<>(); + cQuery.select("distinct port_area_id, port_area, ship_id, ship_name, ship_en_name, voyage_id, voyage, pre_arrival_time, check_status"); + cQuery.eq(StringUtils.isNotEmpty(query.getPortAreaId()), "port_area_id", query.getPortAreaId()); + cQuery.eq(StringUtils.isNotEmpty(query.getShipId()), "ship_id", query.getShipId()); + cQuery.eq(StringUtils.isNotEmpty(query.getVoyageId()), "voyage_id", query.getVoyageId()); + cQuery.eq("check_status", query.getCheckStatus()); + cQuery.orderByDesc("pre_arrival_time"); + + Page page = customerExportInService.page(new Page<>(query.getPage(), query.getRows()), cQuery); + + return ResultUtil.success(page); + } + + + /** + * 审核 + * + * @param check + * @return + */ + @ApiOperation("多船审核") + @PostMapping("/check/more/ship") + public Result checkMoreVoyage(@RequestBody @Validated ExportInBatchCheckVo check) throws Exception { + LambdaQueryWrapper query = new LambdaQueryWrapper<>(); + query.eq(CustomerExportIn::getCheckStatus, check.getOriginalCheckStatus()); + if (!StringUtils.equals("0", check.getType())) { + // exportIn.getCartType(), "备件", "BJ" + query.ne(StringUtils.equals("1", check.getType()), CustomerExportIn::getCartType, "备件"); + query.eq(StringUtils.equals("2", check.getType()), CustomerExportIn::getCartType, "备件"); + } + query.and((wrapper) -> { + for (BatchCheckShipVo ship : check.getShips()) { + wrapper.or(i -> i.eq(CustomerExportIn::getPortAreaId, ship.getPortAreaId()) + .eq(CustomerExportIn::getShipId, ship.getShipId()) + .eq(CustomerExportIn::getVoyageId, ship.getVoyageId()) + .eq(ship.getPreArrivalTime() != null, CustomerExportIn::getPreArrivalTime, ship.getPreArrivalTime())); + } + }); + + + // 待审核的数据 + List list = customerExportInService.list(query); + + CustomerExportIn update = new CustomerExportIn(); + update.setCheckTime(new Date()); + update.setCheckStatus(check.getCheckStatus()); + update.setCheckResult(check.getCheckResult()); + update.setCheckManId(UserContext.getUser().getUserId()); + + if (CollectionUtils.isNotEmpty(list)) { + BatchConfirmReviewReq req = new BatchConfirmReviewReq(); + req.setIds(list.stream().map(s -> s.getId() + "").collect(Collectors.toList())); + Boolean rst = openApi.batchConfirmReview(req); + if (!rst) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "审核失败"); + } + + if (check.getCheckStatus() == AuditEnum.AUDIT_PASS) { + // 获取航次的离泊状态 + List collect = list.stream().map(s -> s.getVoyageId()).filter(s -> !StringUtils.equalsAny(s, "HT6", "HTLG", "HTTC")).distinct().collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(collect)) { + List shipmentBerthsStatusRespDTOS = shpApi.queryVoyagesBerthsStatusByVvyIds(collect); + if (CollectionUtils.isNotEmpty(shipmentBerthsStatusRespDTOS)) { + List strings = shipmentBerthsStatusRespDTOS.stream().filter(s -> StringUtils.equalsAny(s.getUnberthedStatus(), "1")).map(s -> s.getVvyId()).distinct().collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(strings)) { + customerExportInService.lambdaUpdate().in(CustomerExportIn::getVoyageId, strings) + .set(CustomerExportIn::getUnberthFlag, "1").update(); + } + } + } + } + } + + boolean row = customerExportInService.update(update, query); + + if (row) { + // 记录日志 + for (CustomerExportIn exportIn : list) { + LogRecordDTO log = new LogRecordDTO(); + log.setOperateData(exportIn); + log.setStatus(check.getCheckStatus() == AuditEnum.AUDIT_PASS ? 0 : 1); + log.setOperateTime(new Date()); + log.setUserId(UserContext.getUser().getUserId()); + log.setUserName(UserContext.getUser().getUsername()); + EsLogApprovalUtil.writeLog(log); + } + + if (check.getCheckStatus() == AuditEnum.AUDIT_PASS) { + customerService.syncAddExportInToOld(list); + } + + return ResultUtil.success("success"); + } + + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "没有待审核数据"); + } + + @ApiOperation("多船批量删除") + @PostMapping("/delete/more/ship") + @Transactional(rollbackFor = {Exception.class}) + public Result deleteMoreVoyage(@RequestBody @Validated @NotNull(message = "请传入船名,航次信息") @Size(min = 1, message = "请传入船名,航次信息") ValidList form) throws Exception { + LambdaQueryWrapper query = new LambdaQueryWrapper<>(); + query.and((wrapper) -> { + for (BatchCheckShipVo ship : form) { + wrapper.or(i -> i.eq(CustomerExportIn::getPortAreaId, ship.getPortAreaId()) + .eq(CustomerExportIn::getShipId, ship.getShipId()) + .eq(CustomerExportIn::getVoyageId, ship.getVoyageId()) + .eq(ship.getPreArrivalTime() != null, CustomerExportIn::getPreArrivalTime, ship.getPreArrivalTime())); + } + }); + + // 待审核的数据 + List list = customerExportInService.list(query); + + if (CollectionUtils.isNotEmpty(list)) { + // 删除明细 + List ids = list.stream().map(item -> item.getId()).collect(Collectors.toList()); + + customerExportInCargoService.lambdaUpdate().in(CustomerExportInCargo::getExportInId, ids).remove(); + + customerExportInService.removeByIds(ids); + } + + return ResultUtil.success("success"); + } + + + @PostMapping("/bj/gen") + public Result> genBjNos(@RequestParam Integer num) { + List rst = new ArrayList<>(); + for (int i =0 ; i < 10; i++) { + ((Runnable) () -> { + List vins = genBjNo(num, null); + rst.addAll(vins); + }).run(); + + } + Map collect = rst.stream().collect(Collectors.groupingBy(s -> s, Collectors.counting())); + List strings = collect.entrySet().stream().filter(s -> s.getValue() > 1).map(s -> s.getKey()).collect(Collectors.toList()); + System.err.println(strings); + System.err.println(rst.size()); + return ResultUtil.success(rst); + } } diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ExportInspectHandler.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ExportInspectHandler.java index e84f7a4..6be67e9 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ExportInspectHandler.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ExportInspectHandler.java @@ -1,10 +1,14 @@ package com.haitonggauto.rtosc.handler; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.exception.ExcelDataConvertException; import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -19,11 +23,15 @@ import com.haitonggauto.rtosc.common.dto.DictDTO; import com.haitonggauto.rtosc.common.dto.Result; import com.haitonggauto.rtosc.common.enums.ErrorType; import com.haitonggauto.rtosc.common.handler.BaseHandler; +import com.haitonggauto.rtosc.common.utils.DateUtils; import com.haitonggauto.rtosc.common.utils.ResultUtil; import com.haitonggauto.rtosc.common.utils.ValidationGroup; import com.haitonggauto.rtosc.common.utils.WrapperKit; import com.haitonggauto.rtosc.dto.*; +import com.haitonggauto.rtosc.excel.ExportInPlanExcel; import com.haitonggauto.rtosc.excel.ExportInspectExportExcel; +import com.haitonggauto.rtosc.excel.InspectExcel; +import com.haitonggauto.rtosc.handler.excel.ReadExcelListener; import com.haitonggauto.rtosc.query.CargoQuery; import com.haitonggauto.rtosc.query.ExportInspectCheckQuery; import com.haitonggauto.rtosc.query.ExportInspectQuery; @@ -31,6 +39,8 @@ import com.haitonggauto.rtosc.repository.entity.*; import com.haitonggauto.rtosc.handler.mapper.PoMapper; import com.haitonggauto.rtosc.repository.enums.AuditEnum; import com.haitonggauto.rtosc.repository.enums.InspectStatusEnum; +import com.haitonggauto.rtosc.repository.service.CustomerExportInCargoService; +import com.haitonggauto.rtosc.repository.service.CustomerExportInService; import com.haitonggauto.rtosc.repository.service.CustomerExportInspectCargoService; import com.haitonggauto.rtosc.repository.service.CustomerExportInspectService; import com.haitonggauto.rtosc.service.CustomerService; @@ -40,22 +50,34 @@ import com.nuzar.rtops.log.service.EsLogApprovalUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.core.io.ClassPathResource; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import java.io.*; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.net.URLEncoder; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; +@Slf4j @RestController @RequestMapping("/ci") @Api(tags = "出口海关查验") @@ -77,6 +99,15 @@ public class ExportInspectHandler implements BaseHandler { @Resource private NuzarYardApi yardApi; + @Resource + private CustomerExportInService exportInService; + + @Resource + private CustomerExportInCargoService exportInCargoService; + + @Resource + private DictHandler dictHandler; + @ApiOperation("船名航次模糊匹配") @PostMapping("/shipVoyage") public Result> getExportInShipNameList( @@ -176,16 +207,19 @@ public class ExportInspectHandler implements BaseHandler { @ApiOperation("提单号模糊匹配") @PostMapping("/billNo/query") public Result> getExportInBillNoList( + @ApiParam(name = "操作方式, 0为前端,1为审核端") @RequestParam(required = false, defaultValue = "0") String type, @RequestParam(required = false, defaultValue = "1") Integer current, @RequestParam(required = false, defaultValue = "10") Integer size, @RequestParam(required = false) String shipName, @RequestParam(required = false) String voyage, @RequestParam(required = false) String q) { - LambdaQueryWrapper query = new LambdaQueryWrapper<>(); - query.eq(CustomerExportInspect::getTradType, "E"); - query.eq(StringUtils.isNotEmpty(shipName), CustomerExportInspect::getShipName, shipName); - query.eq(StringUtils.isNotEmpty(voyage), CustomerExportInspect::getVoyage, voyage); - query.like(StringUtils.isNotEmpty(q), CustomerExportInspect::getBillNo, q); // 提单号 + QueryWrapper query = new QueryWrapper<>(); + query.select("distinct bill_no"); + query.eq("trad_type", "E"); + query.eq(StringUtils.equals(type, "0"), "create_by", UserContext.getUser().getUserId()); + query.eq(StringUtils.isNotEmpty(shipName), "ship_name", shipName); + query.eq(StringUtils.isNotEmpty(voyage), "voyage", voyage); + query.like(StringUtils.isNotEmpty(q), "bill_no", q); // 提单号 Page page = customerExportInspectService.page(new Page<>(current, size), query); List list = page.getRecords(); @@ -506,6 +540,28 @@ public class ExportInspectHandler implements BaseHandler { List cargos = customerExportInspectCargoService.list(new LambdaQueryWrapper().eq(CustomerExportInspectCargo::getExportInspectId, id)); + // 获取实时 + if (CollectionUtils.isNotEmpty(cargos)) { + GoodsStatusReq req = new GoodsStatusReq(); + req.setBusinessType("INSPECT"); + req.setImportExportType("E"); + req.setVvyId(StringUtils.equalsAnyIgnoreCase(exportInspect.getVoyageId(), "HT6", "HTLG", "HTTC") ? "" : exportInspect.getVoyageId()); + req.setVinCodeList(cargos.stream().map(p -> p.getVin()).collect(Collectors.toList())); + + List resp = openApi.getGoodsStatus(req); + + Map respMap = resp.stream().collect(Collectors.toMap(p -> p.getVinCode(), p -> p)); + + cargos.stream().forEach(p -> { + GoodsStatusResp r = respMap.get(p.getVin()); + if (r != null) { + p.setArea(r.getPosition()); + } else { + p.setArea(""); + } + }); + } + customerService.wrapperEntity(cargos); exportInspect.setCargos(cargos); @@ -549,6 +605,34 @@ public class ExportInspectHandler implements BaseHandler { } Page page = customerExportInspectCargoService.page(new Page<>(query.getPage(), query.getRows()), queryWrapper); + // 获取实时 + if (CollectionUtils.isNotEmpty(page.getRecords())) { + // 需要按InspectId 进行分组 + Map> collect = page.getRecords().stream().collect(Collectors.groupingBy(CustomerExportInspectCargo::getExportInspectId)); + collect.entrySet().forEach(item -> { + CustomerExportInspect inspect = customerExportInspectService.getById(item.getKey()); + + GoodsStatusReq req = new GoodsStatusReq(); + req.setBusinessType("INSPECT"); + req.setImportExportType("E"); + req.setVvyId(StringUtils.equalsAnyIgnoreCase(inspect.getVoyageId(), "HT6", "HTLG", "HTTC") ? "" : inspect.getVoyageId()); + req.setVinCodeList(item.getValue().stream().map(p -> p.getVin()).collect(Collectors.toList())); + + List resp = openApi.getGoodsStatus(req); + + Map respMap = resp.stream().collect(Collectors.toMap(p -> p.getVinCode(), p -> p)); + + page.getRecords().stream().filter(p -> p.getExportInspectId() == item.getKey()).forEach(p -> { + GoodsStatusResp r = respMap.get(p.getVin()); + if (r != null) { + p.setArea(r.getPosition()); + } else { + p.setArea(""); + } + }); + }); + } + customerService.wrapperEntity(page.getRecords()); return ResultUtil.success(page); @@ -599,10 +683,11 @@ public class ExportInspectHandler implements BaseHandler { // 判断车辆是否在场 List vinStatus = yardApi.getVinStatus(vins); + List exists = vinStatus.stream().map(item -> item.getVinCode()).collect(Collectors.toList()); page.getRecords().stream().forEach(item -> { item.setInspect(collect.get(item.getExportInspectId())); - item.setInArea(vinStatus.contains(item.getVin())); + item.setInArea(exists.contains(item.getVin())); }); } @@ -638,8 +723,8 @@ public class ExportInspectHandler implements BaseHandler { log.setOperateData(record); log.setStatus(check.getCheckStatus() == AuditEnum.AUDIT_PASS ? 0 : 1); log.setOperateTime(new Date()); - log.setUserId(SecurityUtils.getUserId()); - log.setUserName(SecurityUtils.getUserName()); + log.setUserId(UserContext.getUser().getUserId()); + log.setUserName(UserContext.getUser().getUsername()); EsLogApprovalUtil.writeLog(log); } @@ -685,8 +770,8 @@ public class ExportInspectHandler implements BaseHandler { log.setOperateData(record); log.setStatus(check.getCheckStatus() == AuditEnum.AUDIT_PASS ? 0 : 1); log.setOperateTime(new Date()); - log.setUserId(SecurityUtils.getUserId()); - log.setUserName(SecurityUtils.getUserName()); + log.setUserId(UserContext.getUser().getUserId()); + log.setUserName(UserContext.getUser().getUsername()); EsLogApprovalUtil.writeLog(log); } @@ -787,6 +872,7 @@ public class ExportInspectHandler implements BaseHandler { private void write(AtomicInteger index, List headers, ExcelWriter excelWriter, WriteSheet writeSheet) { if (CollectionUtils.isEmpty(headers)) { + excelWriter.write(new ArrayList<>(), writeSheet); return; } @@ -810,6 +896,10 @@ public class ExportInspectHandler implements BaseHandler { // 备件号排序 List details = list.stream().filter(p -> ids.contains(p.getExportInspectId())) + .map(s -> { + s.setCartType(StringUtils.isBlank(s.getCartType()) ? "":s.getCartType()); + return s; + }) .sorted(Comparator.comparing(CustomerExportInspectCargo::getCartType).reversed()) .map(p -> { CustomerExportInspect head = collect.get(p.getExportInspectId()); @@ -823,4 +913,337 @@ public class ExportInspectHandler implements BaseHandler { }); } + + @ApiOperation("出口查验导入模板下载") + @GetMapping("/temp/down") + public void tempDownPlan(HttpServletResponse response) throws Exception { + // 加载模板 + ClassPathResource classPathResource = new ClassPathResource("templates/export_inspect_temp.xlsx"); + InputStream inputStream = classPathResource.getInputStream(); + + XSSFWorkbook workbook = new XSSFWorkbook(inputStream); + + OutputStream out = response.getOutputStream(); + try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + + // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman + response.setContentType("application/vnd.ms-excel"); + response.setCharacterEncoding("utf-8"); + // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 + String fileName = URLEncoder.encode("出口查验导入模板", "UTF-8"); + response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); + + workbook.write(bos); + byte[] bArray = bos.toByteArray(); + InputStream is = new ByteArrayInputStream(bArray); + IOUtils.copy(is, out); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (out != null) { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + @ApiOperation("出口查验导入") + @PostMapping("/inspect/import-to-add") + public Result> exportInPlanUpload( + @ApiParam(name = "操作方式, 0为前端,1为审核端") @RequestParam(required = false, defaultValue = "0") String type, + MultipartFile file) { + // 所有读取的数据 + List dataList = new ArrayList<>(); + + // 有错误的数据 + List errorDataList = new ArrayList<>(); + + // 验证通过的数据 + List successDataList = new ArrayList<>(); + + Map headMap = new HashMap<>(); + Map> detailMap = new HashMap<>(); + + try { + + EasyExcel.read(file.getInputStream(), InspectExcel.class, new ReadExcelListener() { + @Override + protected void saveData(List list) { // 保存数据 + dataList.addAll(list); + } + }).sheet().doRead(); + + ValidatorFactory vf = Validation.buildDefaultValidatorFactory(); + Validator validator = vf.getValidator(); + + List validData = new ArrayList<>(); + + // 需要保存的数据 + List saveData = new ArrayList<>(); + + // 数据验证 + dataList.stream().forEach(item -> { + Set> set = validator.validate(item); + if (CollectionUtils.isEmpty(set)) { // 验证通过的 + validData.add(item); + } else { // 验证失败的 + JSONObject o = JSONObject.from(item); + o.put("status", set.stream().map(p -> p.getMessage()).collect(Collectors.joining(","))); + errorDataList.add(o); + } + }); + + if (CollectionUtils.isEmpty(validData)) { // 数据完整性检验 + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + // 获取用户绑定的货代 + List userBindFreight = openApi.getUserBindFreight(); + + // 港区基础数据 + List portAreaList = dictHandler.getPortAreaList(null).getData(); + + // 航次不能为空 + validData.stream().forEach(item -> { + if (portAreaList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), item.getPortArea())).count() == 0) { + JSONObject o = JSONObject.from(item); + o.put("status", "港区不存在"); + errorDataList.add(o); + return; + } + saveData.add(item); + }); + + // 首先按对船名,般次,提单进行分组 + Map> inMap = saveData.stream() + .collect(Collectors.groupingBy(item -> StringUtils.joinWith("#$#", item.getShipName(), StringUtils.isEmpty(item.getVoyage()) ? " " : item.getVoyage(), item.getBillNo()), Collectors.toList())); + + inMap.entrySet().forEach(item -> { + String[] keys = StringUtils.split(item.getKey(), "#$#"); + String shipName = keys[0]; // 船名 + String voyageName = keys[1]; // 航次 + String billNo = keys[2]; // 提单号 + + // 判断船名是否在进港计划中 + List list = exportInService.lambdaQuery().eq(CustomerExportIn::getShipName, shipName) + .ne(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_REJECT) + .last("limit 1").list(); + + if (CollectionUtils.isEmpty(list)) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "查验申请中的船名不存在"); + return o; + }).collect(Collectors.toList())); + return; + } + // 如果航次不为空 + if (StringUtils.isNotBlank(voyageName)) { + list = exportInService.lambdaQuery().eq(CustomerExportIn::getShipName, shipName) + .eq(CustomerExportIn::getVoyage, voyageName) + .ne(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_REJECT) + .last("limit 1").list(); + + if (CollectionUtils.isEmpty(list)) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "查验申请中的航次不存在"); + return o; + }).collect(Collectors.toList())); + return; + } + } + + // 判断提单号 + list = exportInService.lambdaQuery().eq(CustomerExportIn::getShipName, shipName) + .eq(StringUtils.isNotEmpty(voyageName), CustomerExportIn::getVoyage, voyageName) + .eq(CustomerExportIn::getBillNum, billNo) + .ne(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_REJECT) + .last("limit 1").list(); + + if (CollectionUtils.isEmpty(list)) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", StringUtils.isNotEmpty(voyageName) ? "该船名航次下的提单号不存在" : "该船名下的提单号不存在"); + return o; + }).collect(Collectors.toList())); + return; + } + + CustomerExportIn in = list.get(0); + + // 提单对应的货代与登录账号是否一致 + Long id = in.getId(); + String freightId = in.getFreightId(); + if (CollectionUtils.isEmpty(userBindFreight) || userBindFreight.stream().filter(s -> StringUtils.equals(freightId, s.getCueId())).count() == 0) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "提单号的货代与登录账号不一致"); + return o; + }).collect(Collectors.toList())); + return; + } + + // 车架号是否在该提单下 + Map vins = item.getValue().stream().collect(Collectors.toMap(InspectExcel::getVin, s -> s)); + List exists = exportInCargoService.lambdaQuery().eq(CustomerExportInCargo::getExportInId, id) + .in(CustomerExportInCargo::getVin, vins.keySet()).list(); + List existsVins = exists.stream().map(s -> s.getVin()).collect(Collectors.toList()); + List collect = vins.keySet().stream().filter(s -> !existsVins.contains(s)).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(collect)) { + collect.stream().forEach(s -> { + JSONObject o = JSONObject.from(vins.get(s)); + o.put("status", "提单号不存在此车架号"); + errorDataList.add(o); + }); + return; + } + + // 港区是否一致 + long count = item.getValue().stream().map(s -> s.getPortArea()).collect(Collectors.toList()) + .stream().filter(s -> !StringUtils.equals(s, in.getPortArea())).count(); + if (count > 0) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "港区不一致"); + return o; + }).collect(Collectors.toList())); + return; + } + + CustomerExportInspect head = PoMapper.instance.excel2Entity(item.getValue().get(0)); + + String batchNo = customerService.getSequenceNo("inspect_in_batch_no", "出口查验", "CI"); + head.setInspectStatus(InspectStatusEnum.NO_INSPECT); + head.setBatchNo(batchNo); + head.setApplicantId(UserContext.getUser().getUserId()); + head.setTradType("E"); + head.setPortAreaId(in.getPortAreaId()); + head.setCheckStatus(StringUtils.equals(type, "1") ? AuditEnum.AUDIT : AuditEnum.SUBMIT); + head.setTermcd(head.getPortAreaId()); + head.setApplyTime(new Date()); + head.setShipId(in.getShipId()); + head.setShipEnName(in.getShipEnName()); + if (StringUtils.isNotEmpty(head.getVoyage())) { + head.setVoyageId(in.getVoyageId()); + } + head.setApplyObjId(in.getFreightId()); + head.setApplyObj(in.getFreight()); + if (StringUtils.isEmpty(head.getCompany())) { + head.setCompany(head.getApplyObj()); + } + + List detail = item.getValue().stream().map(s -> { + CustomerExportInspectCargo c = new CustomerExportInspectCargo(); + c.setCargoType(StringUtils.startsWith(s.getVin(), "BJ") ? 1 : 0); + c.setBrand(in.getBrand()); + c.setBrandId(in.getBrandId()); + c.setCartTypeId(in.getCartTypeId()); + c.setCartType(in.getCartType()); + c.setModels(in.getModels()); + c.setVin(s.getVin()); + return c; + }).collect(Collectors.toList()); + + head.setPlannedCargoQuantity((int)detail.stream().filter( s -> s.getCargoType() == 0).count()); + head.setPlannedSpareQuantity(detail.size() - head.getPlannedCargoQuantity()); + + headMap.put(item.getKey(), head); + detailMap.put(item.getKey(), detail); + + }); + + if (CollectionUtils.isNotEmpty(errorDataList)) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + // 判断车辆是否在场 + List vinStatus = yardApi.getVinStatus(dataList.stream().map(s -> s.getVin()).collect(Collectors.toList())); + if (CollectionUtils.isEmpty(vinStatus)) { + errorDataList.addAll(dataList.stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "所有查验的车架号均不在场"); + return o; + }).collect(Collectors.toList())); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + Map vinStatusMap = vinStatus.stream().collect(Collectors.toMap(VinStatus::getVinCode, s -> s)); + + // 保存对象 + headMap.keySet().stream().forEach(s -> customerService.saveExportInspect(headMap.get(s), detailMap.get(s))); + + successDataList.addAll(dataList.stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "成攻"); + o.put("yardPos", vinStatusMap.containsKey(p.getVin()) ? vinStatusMap.get(p.getVin()).getYardPos() : "未进港"); + return o; + }).collect(Collectors.toList())); + + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:"+e.getRowIndex()+" 列:" + e.getColumnIndex()); + } catch (Exception e) { + log.error("上传错误", e); + return ResultUtil.failure(ErrorType.PROGRAM_ERROR.id(), e.getMessage()); + } + + List rst = new ArrayList<>(); + rst.addAll(successDataList.stream().filter(s -> StringUtils.isNotBlank(s.getString("yardPos"))).collect(Collectors.toList())); + rst.addAll(successDataList.stream().filter(s -> StringUtils.isBlank(s.getString("yardPos"))).collect(Collectors.toList())); + + return ResultUtil.success(rst); + } + + @ApiOperation("验证航次是否在进港计划中") + @PostMapping("/valid/voyage") + public Result validVoyage(@RequestParam @NotBlank(message = "船ID不能为空") String shipId, @RequestParam @NotBlank(message = "航次ID不能为空") String voyageId) { + Long count = exportInService.lambdaQuery().eq(CustomerExportIn::getVoyageId, voyageId) + .eq(CustomerExportIn::getShipId, shipId).count(); + + return ResultUtil.success(count > 0); + } + + @ApiOperation("提单号,货代,车架号验证") + @PostMapping("/valid/billno") + public Result validBillno(@RequestBody InspectValidVo form) { + List list = exportInService.lambdaQuery().eq(CustomerExportIn::getShipId, form.getShipId()) + .eq(CustomerExportIn::getBillNum, form.getBillNo()) + .ne(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_REJECT) + .list(); + + if(CollectionUtil.isEmpty(list)) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(),"该船名下提单号不存在"); + } + + // 获取用户绑定的货代 + List userBindFreight = openApi.getUserBindFreight(); + if (CollectionUtils.isEmpty(userBindFreight) || userBindFreight.stream().filter(s -> StringUtils.equals(list.get(0).getFreightId(), s.getCueId())).count() == 0) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(),"提单号的货代与登录账号不一致"); + } + + if (CollectionUtils.isNotEmpty(form.getVins())) { + List cargos = exportInCargoService.lambdaQuery().in(CustomerExportInCargo::getExportInId, list.stream().map(s -> s.getId()).collect(Collectors.toList())) + .in(CustomerExportInCargo::getVin, form.getVins()).list(); + List collect = cargos.stream().map(s -> s.getVin()).collect(Collectors.toList()); + List strings = form.getVins().stream().filter(s -> !collect.contains(s)).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(strings)) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(),"提单号不存在此车架号," + StringUtils.join(strings, ",")); + } + } + + JSONObject rst = new JSONObject(); + rst.put("portAreaId", list.get(0).getPortAreaId()); + rst.put("portArea", list.get(0).getPortArea()); + + + return ResultUtil.success(rst); + } } diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ExportLoadHandler.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ExportLoadHandler.java index c05b985..f271be8 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ExportLoadHandler.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ExportLoadHandler.java @@ -1,7 +1,10 @@ package com.haitonggauto.rtosc.handler; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.exception.ExcelDataConvertException; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.Wrapper; @@ -19,13 +22,16 @@ import com.haitonggauto.rtosc.common.dto.DictDTO; import com.haitonggauto.rtosc.common.dto.Result; import com.haitonggauto.rtosc.common.enums.ErrorType; import com.haitonggauto.rtosc.common.handler.BaseHandler; +import com.haitonggauto.rtosc.common.utils.DateUtils; import com.haitonggauto.rtosc.common.utils.ResultUtil; import com.haitonggauto.rtosc.common.utils.ValidationGroup; import com.haitonggauto.rtosc.common.utils.WrapperKit; import com.haitonggauto.rtosc.dto.*; import com.haitonggauto.rtosc.excel.*; import com.haitonggauto.rtosc.handler.excel.CustomCellWriteHandler; +import com.haitonggauto.rtosc.handler.excel.ExcelMergeUtil; import com.haitonggauto.rtosc.query.CargoQuery; +import com.haitonggauto.rtosc.query.ExportInQuery; import com.haitonggauto.rtosc.query.ExportLoadCheckQuery; import com.haitonggauto.rtosc.query.ExportLoadQuery; import com.haitonggauto.rtosc.repository.entity.*; @@ -34,11 +40,11 @@ import com.haitonggauto.rtosc.handler.mapper.PoMapper; import com.haitonggauto.rtosc.repository.enums.AuditEnum; import com.haitonggauto.rtosc.repository.service.*; import com.haitonggauto.rtosc.service.CustomerService; -import com.nuzar.common.security5.common.util.SecurityUtils; import com.nuzar.rtops.log.dto.LogRecordDTO; import com.nuzar.rtops.log.service.EsLogApprovalUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; @@ -61,6 +67,7 @@ import java.io.IOException; import java.io.OutputStream; import java.net.URLEncoder; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @RestController @@ -230,18 +237,20 @@ public class ExportLoadHandler implements BaseHandler { @ApiOperation("提单号模糊匹配") @PostMapping("/billNo/query") public Result> getExportInBillNoList( + @ApiParam(name = "操作方式, 0为前端,1为审核端") @RequestParam(required = false, defaultValue = "0") String type, @RequestParam(required = false, defaultValue = "W") String tradType, @RequestParam(required = false, defaultValue = "1") Integer current, @RequestParam(required = false, defaultValue = "10") Integer size, @RequestParam(required = false) String shipName, @RequestParam(required = false) String voyage, @RequestParam(required = false) String q) { - LambdaQueryWrapper query = new LambdaQueryWrapper<>(); - query.eq(CustomerExportLoad::getCreateBy, UserContext.getUser().getUserId()); - query.eq(StringUtils.isNotEmpty(shipName), CustomerExportLoad::getShipName, shipName); - query.eq(StringUtils.isNotEmpty(voyage), CustomerExportLoad::getVoyage, voyage); - query.like(StringUtils.isNotEmpty(q), CustomerExportLoad::getBillNo, q); // 提单号 - query.like(CustomerExportLoad::getTradType, tradType); + QueryWrapper query = new QueryWrapper<>(); + query.select("distinct bill_no"); + query.eq(StringUtils.equals(type, "0"), "create_by", UserContext.getUser().getUserId()); + query.eq(StringUtils.isNotEmpty(shipName), "ship_name", shipName); + query.eq(StringUtils.isNotEmpty(voyage), "voyage", voyage); + query.like(StringUtils.isNotEmpty(q), "bill_no", q); // 提单号 + query.eq("trad_type", tradType); Page page = customerExportLoadService.page(new Page<>(current, size), query); List list = page.getRecords(); @@ -327,7 +336,7 @@ public class ExportLoadHandler implements BaseHandler { // 数据拼装 list.stream().forEach(item -> { - List cs = collect.get(item.getId()); + List cs = collect.get(item.getId()); item.setVins(cs); }); } @@ -356,13 +365,36 @@ public class ExportLoadHandler implements BaseHandler { @ApiOperation("根据航次ID查询审核通过出口装船记录") @PostMapping("/query-list/voyage") - public Result> checkQuery(@RequestParam(required = false) @NotBlank(message = "航次ID不能为空") String voyageId, - @RequestParam(required = false) AuditEnum status) { + public Result> checkQuery( + @RequestParam(required = false) @NotBlank(message = "航次ID不能为空") String voyageId, + @RequestParam(required = false) @ApiParam("提单号列表") List billNos, + @RequestParam(required = false) AuditEnum status) { + ExportLoadCheckQuery query = new ExportLoadCheckQuery(); if (status == null) { status = AuditEnum.AUDIT_PASS; } + query.setCheckStatus(status); + query.setVoyageId(voyageId); + query.setBillNos(billNos); - List list = customerExportLoadService.getListByVoyageId(voyageId, status); + Wrapper queryWrapper = new WrapperKit() { + }.changeBaseQueryToWrapper(CustomerExportLoad.class, query); + List list = customerExportLoadService.list(queryWrapper); + customerService.wrapperEntity(list); + + if (CollectionUtils.isNotEmpty(list)) { + List cargos = customerExportLoadCargoService.lambdaQuery() + .in(CustomerExportLoadCargo::getExportLoadId, list.stream().map(item -> item.getId()).collect(Collectors.toList())).list(); + + // 按进港ID进行分组 + Map> collect = cargos.stream().collect(Collectors.groupingBy(CustomerExportLoadCargo::getExportLoadId)); + + // 数据拼装 + list.stream().forEach(item -> { + List cs = collect.get(item.getId()); + item.setVins(cs); + }); + } // 判断是否换船,找出车架号重复,且航次不一样的记录 List vins = customerExportLoadCargoService.getChangeShipVin(voyageId); @@ -436,7 +468,7 @@ public class ExportLoadHandler implements BaseHandler { } } - Long id = customerService.saveExportLoad(exportLoad, cargos); + Long id = customerService.saveExportLoad(exportLoad, null, cargos); return ResultUtil.success(String.valueOf(id)); } @@ -482,8 +514,8 @@ public class ExportLoadHandler implements BaseHandler { @ApiOperation("撤销提交审核") @PostMapping("/submit-check/reverse") public Result submitCheckReverse(@RequestBody - @NotNull(message = "请传入要审核的出口装船ID") - @Size(min = 1, message = "ID列表不能为空") List ids) { + @NotNull(message = "请传入要审核的出口装船ID") + @Size(min = 1, message = "ID列表不能为空") List ids) { // 是否除提交审核的其它状态 Long count = customerExportLoadService.lambdaQuery().in(CustomerExportLoad::getId, ids).ne(CustomerExportLoad::getCheckStatus, AuditEnum.AUDIT).count(); if (count > 0) { @@ -504,8 +536,14 @@ public class ExportLoadHandler implements BaseHandler { @ApiOperation("删除") @PostMapping("/del") public Result delete(@RequestBody - @NotNull(message = "请传入要删除的ID") - @Size(min = 1, message = "请传入要删除的ID") List ids) { + @NotNull(message = "请传入要删除的ID") + @Size(min = 1, message = "请传入要删除的ID") List ids) { + // 只能删除待审核,待提交,已驳回的数据 + Long count = customerExportLoadService.lambdaQuery().in(CustomerExportLoad::getId, ids) + .notIn(CustomerExportLoad::getCheckStatus, AuditEnum.AUDIT, AuditEnum.SUBMIT, AuditEnum.AUDIT_REJECT).count(); + if (count > 0) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "只能删除待审核,待提交,已驳回的数据"); + } for (Long id : ids) { customerService.delExportLoad(id); } @@ -601,6 +639,7 @@ public class ExportLoadHandler implements BaseHandler { public Result edit(@RequestBody @Validated(ValidationGroup.update.class) ExportLoadVo form) { return this.edit(true, form); } + /** * 编辑 * @@ -610,7 +649,7 @@ public class ExportLoadHandler implements BaseHandler { @ApiOperation("编辑") @PostMapping("/edit") // 使用LambdaUpdateWrapper只在特定需求下做处理(推荐) 将字段修改为空值的处理方法 - public Result edit(@RequestParam(required = false, defaultValue = "false")Boolean flag, + public Result edit(@RequestParam(required = false, defaultValue = "false") Boolean flag, @RequestBody @Validated(ValidationGroup.update.class) ExportLoadVo form) { if (CollectionUtils.isNotEmpty(form.getCargos())) { List repeat = form.getCargos().stream().collect(Collectors.groupingBy(ExportLoadCargoVo::getVin, Collectors.counting())) @@ -707,43 +746,53 @@ public class ExportLoadHandler implements BaseHandler { @PostMapping("/cargos/page") public Result> cargoList(@RequestBody @Validated(ValidationGroup.update.class) CargoQuery query) { // 查询内外贸 - CustomerExportLoad exportLoad = customerExportLoadService.getById(query.getId()); +// CustomerExportLoad exportLoad = customerExportLoadService.getById(query.getId()); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); queryWrapper.eq(query.getId() != null, CustomerExportLoadCargo::getExportLoadId, query.getId()); if (query.getCargoType() != null) { queryWrapper.eq(query.getCargoType() != null, CustomerExportLoadCargo::getCargoType, query.getCargoType()); } + queryWrapper.eq(StringUtils.isNotEmpty(query.getBrandId()), CustomerExportLoadCargo::getBrandId, query.getBrandId()); + queryWrapper.like(StringUtils.isNotEmpty(query.getVin()), CustomerExportLoadCargo::getVin, query.getVin()); + queryWrapper.exists(StringUtils.isNotEmpty(query.getBillNum()), "select id from customer_export_load where export_load_id=customer_export_load.id and bill_no like {0}", query.getBillNum()); Page page = customerExportLoadCargoService.page(new Page<>(query.getPage(), query.getRows()), queryWrapper); customerService.wrapperEntity(page.getRecords()); - // 获取作业状态 - Map collect = null; - List vins = page.getRecords().stream().map(item -> item.getVin()).collect(Collectors.toList()); - if (CollectionUtils.isNotEmpty(vins)) { - VinStatusRequest req = new VinStatusRequest(); - req.setBusinessType("LOAD"); - req.setImportExportType("E"); - req.setVinCodeList(vins); - req.setVvyId(exportLoad.getVoyageId()); - List status = openApi.getVinStatus(req); - collect = status.stream().collect(Collectors.toMap(WorkStatusDTO::getVinCode, WorkStatusDTO::getWorkStatus)); - } - for (CustomerExportLoadCargo cargo : page.getRecords()) { - cargo.setDestPortId(exportLoad.getDestPortId()); - cargo.setDestPort(exportLoad.getDestPort()); - cargo.setNatureFlag(exportLoad.getNatureFlag()); - cargo.setNatureFlagName(exportLoad.getNatureFlagName()); - cargo.setTransferShipId(exportLoad.getTransferShipId()); - cargo.setTransferShipName(exportLoad.getTransferShipName()); - cargo.setTransferVoyageId(exportLoad.getTransferVoyageId()); - cargo.setTransferVoyage(exportLoad.getTransferVoyage()); - } - if (MapUtils.isNotEmpty(collect)) { - for (CustomerExportLoadCargo cargo : page.getRecords()) { - cargo.setWorkStatus(collect.get(cargo.getVin())); + Map> listMap = page.getRecords().stream().collect(Collectors.groupingBy(CustomerExportLoadCargo::getExportLoadId)); + listMap.entrySet().stream().forEach(s -> { + CustomerExportLoad exportLoad = customerExportLoadService.getById(s.getKey()); + + // 获取作业状态 + Map collect = null; + List vins = s.getValue().stream().map(item -> item.getVin()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(vins)) { + VinStatusRequest req = new VinStatusRequest(); + req.setBusinessType("LOAD"); + req.setImportExportType("E"); + req.setVinCodeList(vins); + req.setVvyId(exportLoad.getVoyageId()); + List status = openApi.getVinStatus(req); + collect = status.stream().collect(Collectors.toMap(WorkStatusDTO::getVinCode, WorkStatusDTO::getWorkStatus)); } - } + for (CustomerExportLoadCargo cargo : page.getRecords()) { + cargo.setDestPortId(exportLoad.getDestPortId()); + cargo.setDestPort(exportLoad.getDestPort()); + cargo.setNatureFlag(exportLoad.getNatureFlag()); + cargo.setNatureFlagName(exportLoad.getNatureFlagName()); + cargo.setTransferShipId(exportLoad.getTransferShipId()); + cargo.setTransferShipName(exportLoad.getTransferShipName()); + cargo.setTransferVoyageId(exportLoad.getTransferVoyageId()); + cargo.setTransferVoyage(exportLoad.getTransferVoyage()); + } + if (MapUtils.isNotEmpty(collect)) { + for (CustomerExportLoadCargo cargo : page.getRecords()) { + cargo.setWorkStatus(collect.get(cargo.getVin())); + } + } + }); + + /* if (CollectionUtils.isNotEmpty(page.getRecords()) && StringUtils.equalsIgnoreCase("N", exportLoad.getTradType())) { @@ -766,12 +815,23 @@ public class ExportLoadHandler implements BaseHandler { public Result check(@RequestBody @Validated(ValidationGroup.insert.class) ExportLoadCheckVo check) throws Exception { List spares = null; - if (check.getCheckStatus() == AuditEnum.AUDIT_PASS) { // 先找到需要同步的备件 + // 记录日志 + List logList = customerExportLoadService.lambdaQuery() + .eq(CustomerExportLoad::getShipId, check.getShipId()) + .eq(CustomerExportLoad::getVoyageId, check.getVoyageId()) + .gt(check.getSpare(), CustomerExportLoad::getSpareQuantity, 0) + .eq(!check.getSpare(), CustomerExportLoad::getSpareQuantity, 0) + .in(CollectionUtils.isNotEmpty(check.getBillNos()), CustomerExportLoad::getBillNo, check.getBillNos()) + .eq(CustomerExportLoad::getCheckStatus, AuditEnum.AUDIT) + .list(); + + if (check.getCheckStatus() == AuditEnum.AUDIT_PASS && check.getSpare()) { // 先找到需要同步的备件 // 如果审核通过,且是备件,则需要从出口进港计划中匹配到相同的数量,添加到装船申请中 LambdaQueryWrapper lQuery = new LambdaQueryWrapper<>(); lQuery.eq(CustomerExportLoad::getShipId, check.getShipId()); lQuery.eq(CustomerExportLoad::getVoyageId, check.getVoyageId()); lQuery.gt(CustomerExportLoad::getSpareQuantity, 0); + lQuery.in(CollectionUtils.isNotEmpty(check.getBillNos()), CustomerExportLoad::getBillNo, check.getBillNos()); lQuery.eq(CustomerExportLoad::getCheckStatus, AuditEnum.AUDIT); spares = customerExportLoadService.list(lQuery); @@ -786,6 +846,9 @@ public class ExportLoadHandler implements BaseHandler { update.set(CustomerExportLoad::getCheckTime, new Date()); update.eq(CustomerExportLoad::getShipId, check.getShipId()); update.eq(CustomerExportLoad::getVoyageId, check.getVoyageId()); + update.gt(check.getSpare(), CustomerExportLoad::getSpareQuantity, 0); + update.eq(!check.getSpare(), CustomerExportLoad::getSpareQuantity, 0); + update.in(CollectionUtils.isNotEmpty(check.getBillNos()), CustomerExportLoad::getBillNo, check.getBillNos()); update.eq(CustomerExportLoad::getCheckStatus, AuditEnum.AUDIT); boolean flag = customerExportLoadService.update(update); @@ -810,6 +873,9 @@ public class ExportLoadHandler implements BaseHandler { update.set(CustomerExportLoad::getCheckTime, new Date()); update.eq(CustomerExportLoad::getShipId, check.getShipId()); update.eq(CustomerExportLoad::getVoyageId, check.getVoyageId()); + update.gt(check.getSpare(), CustomerExportLoad::getSpareQuantity, 0); + update.eq(!check.getSpare(), CustomerExportLoad::getSpareQuantity, 0); + update.in(CollectionUtils.isNotEmpty(check.getBillNos()), CustomerExportLoad::getBillNo, check.getBillNos()); update.eq(CustomerExportLoad::getCheckStatus, AuditEnum.AUDIT); // update.in(CustomerExportLoad::getCreateBy, userIds); @@ -849,26 +915,61 @@ public class ExportLoadHandler implements BaseHandler { } // 记录日志 - List list = customerExportLoadService.lambdaQuery() - .eq(CustomerExportLoad::getShipId, check.getShipId()) - .eq(CustomerExportLoad::getVoyageId, check.getVoyageId()) - .eq(CustomerExportLoad::getCheckStatus, AuditEnum.AUDIT) - .list(); - - // 记录日志 - for (CustomerExportLoad record : list) { + for (CustomerExportLoad record : logList) { LogRecordDTO log = new LogRecordDTO(); log.setOperateData(record); log.setStatus(check.getCheckStatus() == AuditEnum.AUDIT_PASS ? 0 : 1); log.setOperateTime(new Date()); - log.setUserId(SecurityUtils.getUserId()); - log.setUserName(SecurityUtils.getUserName()); + log.setUserId(UserContext.getUser().getUserId()); + log.setUserName(UserContext.getUser().getUsername()); EsLogApprovalUtil.writeLog(log); } return ResultUtil.success("success"); } + @ApiOperation("其它取消审核") + @PostMapping("/cancel-check/other") + @Transactional(rollbackFor = {Exception.class}) + public Result cancelCheckOther(@RequestBody @Validated(ValidationGroup.update.class) ExportLoadCheckVo check) { + LambdaUpdateWrapper update = new LambdaUpdateWrapper<>(); + update.set(CustomerExportLoad::getCheckManId, UserContext.getUser().getUserId()); + update.set(CustomerExportLoad::getCheckMan, check.getCheckMan()); + update.set(CustomerExportLoad::getCheckStatus, AuditEnum.AUDIT); + update.set(CustomerExportLoad::getCheckResult, ""); + update.set(CustomerExportLoad::getCheckTime, new Date()); + update.eq(CustomerExportLoad::getShipId, check.getShipId()); + update.eq(CustomerExportLoad::getVoyageId, check.getVoyageId()); + update.gt(check.getSpare() != null && check.getSpare(), CustomerExportLoad::getSpareQuantity, 0); + update.eq(check.getSpare() != null && !check.getSpare(), CustomerExportLoad::getSpareQuantity, 0); + update.in(CollectionUtils.isNotEmpty(check.getBillNos()), CustomerExportLoad::getBillNo, check.getBillNos()); + update.and((wrapper) -> { + wrapper.eq(CustomerExportLoad::getCheckStatus, AuditEnum.AUDIT_PASS) + .or() + .eq(CustomerExportLoad::getCheckStatus, AuditEnum.AUDIT_REJECT); + }); + boolean flag = customerExportLoadService.update(update); + + if (!flag) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "船名,航次不存在"); + } + + // 如果审核通过,且是备件,则需要从出口进港计划中匹配到相同的数量,添加到装船申请中 + LambdaQueryWrapper lQuery = new LambdaQueryWrapper<>(); + lQuery.eq(CustomerExportLoad::getShipId, check.getShipId()); + lQuery.eq(CustomerExportLoad::getVoyageId, check.getVoyageId()); + lQuery.in(CollectionUtils.isNotEmpty(check.getBillNos()), CustomerExportLoad::getBillNo, check.getBillNos()); + lQuery.gt(CustomerExportLoad::getSpareQuantity, 0); + + List spares = customerExportLoadService.list(lQuery); + for (CustomerExportLoad load : spares) { // 找到审核通过的进港计划 + //删除 + customerExportLoadCargoService.lambdaUpdate().eq(CustomerExportLoadCargo::getExportLoadId, load.getId()).remove(); + } + + return ResultUtil.success("success"); + } + /** * 取消审核 * @@ -887,6 +988,9 @@ public class ExportLoadHandler implements BaseHandler { update.set(CustomerExportLoad::getCheckTime, new Date()); update.eq(CustomerExportLoad::getShipId, check.getShipId()); update.eq(CustomerExportLoad::getVoyageId, check.getVoyageId()); + update.gt(check.getSpare(), CustomerExportLoad::getSpareQuantity, 0); + update.eq(!check.getSpare(), CustomerExportLoad::getSpareQuantity, 0); + update.in(CollectionUtils.isNotEmpty(check.getBillNos()), CustomerExportLoad::getBillNo, check.getBillNos()); update.and((wrapper) -> { wrapper.eq(CustomerExportLoad::getCheckStatus, AuditEnum.AUDIT_PASS) .or() @@ -902,6 +1006,7 @@ public class ExportLoadHandler implements BaseHandler { LambdaQueryWrapper lQuery = new LambdaQueryWrapper<>(); lQuery.eq(CustomerExportLoad::getShipId, check.getShipId()); lQuery.eq(CustomerExportLoad::getVoyageId, check.getVoyageId()); + lQuery.in(CollectionUtils.isNotEmpty(check.getBillNos()), CustomerExportLoad::getBillNo, check.getBillNos()); lQuery.gt(CustomerExportLoad::getSpareQuantity, 0); List spares = customerExportLoadService.list(lQuery); @@ -1025,6 +1130,557 @@ public class ExportLoadHandler implements BaseHandler { } } + @ApiOperation("外贸整船车辆导入(按提单)") + @PostMapping("/outside/import-to-add/billno") + public Result> outsideUploadBillno(@RequestParam(required = false) String type, MultipartFile file) { + // 所有读取的数据 + List dataList = new ArrayList<>(); + + // 有错误的数据 + List errorDataList = new ArrayList<>(); + + // 验证通过的数据 + List successDataList = new ArrayList<>(); + + // 要保存的表头 + Map heads = new LinkedHashMap<>(); + + // 要保存的明细 + Map> details = new HashMap<>(); + + // 要删除的清单 + Map> removeIds = new HashMap<>(); + + try { + + // 港口基础数据 + List portList = dictHandler.getPortList(null).getData(); + + // 品牌基础数据 + List brandList = dictHandler.getBrandList(null).getData(); + + EasyExcel.read(file.getInputStream(), ExportLoadExcel.class, new ReadExcelListener() { + @Override + protected void saveData(List list) { // 保存数据 + dataList.addAll(list); + } + }).sheet().doRead(); + + ValidatorFactory vf = Validation.buildDefaultValidatorFactory(); + Validator validator = vf.getValidator(); + + List validData = new ArrayList<>(); + + // 数据验证 + dataList.stream().forEach(item -> { + Set> set = validator.validate(item); + if (CollectionUtils.isEmpty(set)) { // 验证通过的 + validData.add(item); + } else { // 验证失败的 + JSONObject o = JSONObject.from(item); + o.put("status", set.stream().map(p -> p.getMessage()).collect(Collectors.joining(","))); + errorDataList.add(o); + } + }); + + if (CollectionUtils.isEmpty(validData)) { + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + // 是否有重复的车架号 + List repeat = validData.stream().collect(Collectors.groupingBy(ExportLoadExcel::getVin, Collectors.counting())) + .entrySet().stream().filter(entry -> entry.getValue() > 1).map(entry -> entry.getKey()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(repeat)) { + errorDataList.addAll(validData.stream().filter(p -> repeat.contains(p.getVin())).map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "车架号重复"); + return o; + }).collect(Collectors.toList())); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + // 首先按对船名,般次,提单进行分组 + Map> collect = validData.stream() + .collect(Collectors.groupingBy(item -> StringUtils.joinWith("#$#", item.getShipName(), item.getVoyage(), item.getBillNo(), item.getBrand(), item.getDestPort()), Collectors.toList())); + collect.entrySet().forEach(item -> { + String[] keys = StringUtils.split(item.getKey(), "#$#"); + // 首先判断,船名,航次,提单号在出口进港申请中是否已经通过 + LambdaQueryWrapper iQuery = new LambdaQueryWrapper<>(); + iQuery.eq(CustomerExportIn::getShipName, keys[0]); + iQuery.eq(CustomerExportIn::getVoyage, keys[1]); + iQuery.eq(CustomerExportIn::getBillNum, keys[2]); + iQuery.eq(CustomerExportIn::getBrand, keys[3]); + iQuery.ne(CustomerExportIn::getCartType, "备件"); + iQuery.isNotNull(CustomerExportIn::getVoyageId); + iQuery.eq(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_PASS); + + List exportInList = customerExportInService.list(iQuery); + if (CollectionUtils.isEmpty(exportInList)) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "本船名航次下未找到审核通过的出口进港申请"); + return o; + }).collect(Collectors.toList())); + return; + } + + CustomerExportIn exportIn = exportInList.get(0); + + if (portList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), keys[4])).count() == 0) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "目的港信息错误"); + return o; + }).collect(Collectors.toList())); + return; + } + + if (brandList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), keys[3])).count() == 0) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "品牌不存在"); + return o; + }).collect(Collectors.toList())); + return; + } + + List cargos = item.getValue().stream().map(p -> { + CustomerExportLoadCargo cargo = new CustomerExportLoadCargo(); + cargo.setCargoType(0); + cargo.setVinStatus(1); + cargo.setBrandId(brandList.stream().filter(s -> StringUtils.equalsIgnoreCase(s.getText(), keys[3])).findFirst().get().getId()); + cargo.setBrand(keys[3]); + cargo.setVin(p.getVin()); + cargo.setTermcd(exportIn.getPortAreaId()); + return cargo; + }).collect(Collectors.toList()); + + List vins = cargos.stream().map(p -> p.getVin()).collect(Collectors.toList()); + + // 查询出是否已经有了装船导入记录 + List list = customerExportLoadService.lambdaQuery() + .eq(CustomerExportLoad::getShipName, keys[0]) + .eq(CustomerExportLoad::getVoyage, keys[1]) + .eq(CustomerExportLoad::getBillNo, keys[2]) + .eq(CustomerExportLoad::getBrand, keys[3]) + .gt(CustomerExportLoad::getQuantity, 0).list(); + + Optional first = list.stream().filter(s -> s.getCheckStatus() == AuditEnum.AUDIT_PASS).findFirst(); + if (first.isPresent()) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "提单号"+first.get().getBillNo()+"已审核通过,请先取消后再次导入装船清单"); + return o; + }).collect(Collectors.toList())); + } + + // 导入时校验待提交、待审核、已通过状态中是否有重复的车架号,重复导入失败,提示”车架号已存在,请勿重复申请“ + List existCargos = customerExportLoadCargoService.list(new LambdaQueryWrapper() + .in(CustomerExportLoadCargo::getVin, vins) + .notIn(CollectionUtils.isNotEmpty(list), CustomerExportLoadCargo::getExportLoadId, list.stream().map(s -> s.getId()).collect(Collectors.toList())) + .exists("select id from customer_export_load where customer_export_load.id = customer_export_load_cargo.export_load_id and customer_export_load.check_status <> 3")); + List existVins = existCargos.stream().map(p -> p.getVin()).collect(Collectors.toList()); + Map id2bill = new HashMap<>(); + Map vin2id = new HashMap<>(); + + // 查询出对应的港区 + if (CollectionUtils.isNotEmpty(existCargos)) { + List els = customerExportLoadService.lambdaQuery().in(CustomerExportLoad::getId, existCargos.stream().map(s -> s.getExportLoadId()).distinct().collect(Collectors.toList())).list(); + // 转成MAP + id2bill.putAll(els.stream().collect(Collectors.toMap(CustomerExportLoad::getId, CustomerExportLoad::getBillNo))); + vin2id.putAll(existCargos.stream().collect(Collectors.toMap(CustomerExportLoadCargo::getVin, CustomerExportLoadCargo::getExportLoadId))); + + List sList = customerExportLoadService.lambdaQuery().in(CustomerExportLoad::getId, existCargos.stream().map(ss -> ss.getExportLoadId()).collect(Collectors.toList())).list(); + Map portAreaMap = sList.stream().collect(Collectors.toMap(CustomerExportLoad::getId, CustomerExportLoad::getPortAreaId)); + // 通过接口再次验证 + List req = existCargos.stream().map(ss -> { + CheckVinReq v = new CheckVinReq(); + v.setIsRepetition(true); + v.setPamId(portAreaMap.get(ss.getExportLoadId())); + v.setVinCode(ss.getVin()); + return v; + }).collect(Collectors.toList()); + List rst = shpApi.checkVinRepeat(req); + existVins.clear(); + if (CollectionUtils.isNotEmpty(rst)) { + // 再次过滤出重复的 + List sCollect = rst.stream().filter(ss -> ss.getIsRepetition()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(sCollect)) { + existVins.addAll(sCollect.stream().map(ss -> ss.getVinCode()).collect(Collectors.toList())); + } + } + } + + List existData = item.getValue().stream().filter(p -> existVins.contains(p.getVin())).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(existData)) { + errorDataList.addAll(existData.stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "当前车架号已存在,关联提单号为:" + id2bill.get(vin2id.get(p.getVin()))); + return o; + }).collect(Collectors.toList())); + successDataList.addAll(item.getValue().stream().filter(p -> !existVins.contains(p.getVin())) + .map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "数据验证成功"); + return o; + }).collect(Collectors.toList())); + return; + } else { + successDataList.addAll(item.getValue().stream().filter(p -> !existVins.contains(p.getVin())) + .map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "数据验证成功"); + return o; + }).collect(Collectors.toList())); + } + + // 生成新的装船记录 + List saveCargos = cargos.stream().filter(s -> !existVins.contains(s.getVin())).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(saveCargos)) { + + if (CollectionUtils.isNotEmpty(list)) { + removeIds.put(item.getKey(), list.stream().map(s -> s.getId()).collect(Collectors.toList())); + } + + CustomerExportLoad exportLoad = new CustomerExportLoad(); + exportLoad.setTradType("W"); + exportLoad.setShipName(keys[0]); + exportLoad.setVoyage(keys[1]); + exportLoad.setBillNo(keys[2]); + exportLoad.setShipId(exportIn.getShipId()); + exportLoad.setShipEnName(exportIn.getShipEnName()); + exportLoad.setVoyageId(exportIn.getVoyageId()); + exportLoad.setBrandId(brandList.stream().filter(s -> StringUtils.equalsIgnoreCase(s.getText(), keys[3])).findFirst().get().getId()); + exportLoad.setBrand(keys[3]); + exportLoad.setDestPortId(portList.stream().filter(s -> StringUtils.equalsIgnoreCase(s.getText(), keys[4])).findFirst().get().getId()); + exportLoad.setDestPort(keys[4]); + exportLoad.setQuantity(saveCargos.size()); + exportLoad.setSpareQuantity(0); + exportLoad.setPortArea(exportIn.getPortArea()); + exportLoad.setPortAreaId(exportIn.getPortAreaId()); + exportLoad.setTermcd(exportIn.getPortAreaId()); + if (StringUtils.equals("1", type)) { + exportLoad.setCheckStatus(AuditEnum.AUDIT); + } else { + exportLoad.setCheckStatus(AuditEnum.SUBMIT); + } + exportLoad.setApplyTime(new Date()); + exportLoad.setApplicantId(UserContext.getUser().getUserId()); + + heads.put(item.getKey(), exportLoad); + details.put(item.getKey(), saveCargos); + } + + }); + + if (CollectionUtils.isNotEmpty(errorDataList)) { +// errorDataList.addAll(successDataList); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + if (MapUtils.isNotEmpty(heads)) { + heads.entrySet().forEach(item -> { + CustomerExportLoad exportLoad = item.getValue(); + String batchNo = customerService.getSequenceNo("export_load_batch_no", "出口装船", "EL"); + exportLoad.setBatchNo(batchNo); + + customerService.saveExportLoad(exportLoad, removeIds.get(item.getKey()), details.get(item.getKey())); + }); + } + + return ResultUtil.success(errorDataList); + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:" + e.getRowIndex() + " 列:" + e.getColumnIndex()); + } catch (Exception e) { + log.error("错误信息", e); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), e.getMessage()); + } + } + + @ApiOperation("外贸整船车辆导入(按船)") + @PostMapping("/outside/import-to-add/ship") + public Result> outsideUploadShip(@RequestParam(required = false) String type, MultipartFile file) { + // 所有读取的数据 + List dataList = new ArrayList<>(); + + // 有错误的数据 + List errorDataList = new ArrayList<>(); + + // 验证通过的数据 + List successDataList = new ArrayList<>(); + + // 要保存的表头 + Map heads = new LinkedHashMap<>(); + + // 要保存的明细 + Map> details = new HashMap<>(); + + // 要删除的清单 + Map> removeIds = new HashMap<>(); + + try { + + // 港口基础数据 + List portList = dictHandler.getPortList(null).getData(); + + // 品牌基础数据 + List brandList = dictHandler.getBrandList(null).getData(); + + EasyExcel.read(file.getInputStream(), ExportLoadExcel.class, new ReadExcelListener() { + @Override + protected void saveData(List list) { // 保存数据 + dataList.addAll(list); + } + }).sheet().doRead(); + + ValidatorFactory vf = Validation.buildDefaultValidatorFactory(); + Validator validator = vf.getValidator(); + + List validData = new ArrayList<>(); + + // 数据验证 + dataList.stream().forEach(item -> { + Set> set = validator.validate(item); + if (CollectionUtils.isEmpty(set)) { // 验证通过的 + validData.add(item); + } else { // 验证失败的 + JSONObject o = JSONObject.from(item); + o.put("status", set.stream().map(p -> p.getMessage()).collect(Collectors.joining(","))); + errorDataList.add(o); + } + }); + + if (CollectionUtils.isEmpty(validData)) { + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + // 是否有重复的车架号 + List repeat = validData.stream().collect(Collectors.groupingBy(ExportLoadExcel::getVin, Collectors.counting())) + .entrySet().stream().filter(entry -> entry.getValue() > 1).map(entry -> entry.getKey()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(repeat)) { + errorDataList.addAll(validData.stream().filter(p -> repeat.contains(p.getVin())).map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "车架号重复"); + return o; + }).collect(Collectors.toList())); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + // 首先按对船名,般次,判断是否有审核通过的装船计划 + Map> collect = validData.stream() + .collect(Collectors.groupingBy(item -> StringUtils.joinWith("#$#", item.getShipName(), item.getVoyage()), Collectors.toList())); + collect.entrySet().forEach(item -> { + String[] keys = StringUtils.split(item.getKey(), "#$#"); + List list = customerExportLoadService.lambdaQuery() + .eq(CustomerExportLoad::getShipName, keys[0]) + .eq(CustomerExportLoad::getVoyage, keys[1]) + .eq(CustomerExportLoad::getSpareQuantity, 0) + .eq(CustomerExportLoad::getCheckStatus, AuditEnum.AUDIT_PASS).list(); + if (CollectionUtils.isNotEmpty(list)) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "当前航次有审核通过的装船清单"); + return o; + }).collect(Collectors.toList())); + return; + } + }); + + if (CollectionUtils.isNotEmpty(errorDataList)) { +// errorDataList.addAll(successDataList); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + // 首先按对船名,般次,提单进行分组 + collect = validData.stream() + .collect(Collectors.groupingBy(item -> StringUtils.joinWith("#$#", item.getShipName(), item.getVoyage(), item.getBillNo(), item.getBrand(), item.getDestPort()), Collectors.toList())); + collect.entrySet().forEach(item -> { + String[] keys = StringUtils.split(item.getKey(), "#$#"); + // 首先判断,船名,航次,提单号在出口进港申请中是否已经通过 + LambdaQueryWrapper iQuery = new LambdaQueryWrapper<>(); + iQuery.eq(CustomerExportIn::getShipName, keys[0]); + iQuery.eq(CustomerExportIn::getVoyage, keys[1]); + iQuery.eq(CustomerExportIn::getBillNum, keys[2]); + iQuery.eq(CustomerExportIn::getBrand, keys[3]); + iQuery.ne(CustomerExportIn::getCartType, "备件"); + iQuery.isNotNull(CustomerExportIn::getVoyageId); + iQuery.eq(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_PASS); + + List exportInList = customerExportInService.list(iQuery); + if (CollectionUtils.isEmpty(exportInList)) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "本船名航次下未找到审核通过的出口进港申请"); + return o; + }).collect(Collectors.toList())); + return; + } + + CustomerExportIn exportIn = exportInList.get(0); + + if (portList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), keys[4])).count() == 0) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "目的港信息错误"); + return o; + }).collect(Collectors.toList())); + return; + } + + if (brandList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), keys[3])).count() == 0) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "品牌不存在"); + return o; + }).collect(Collectors.toList())); + return; + } + + List cargos = item.getValue().stream().map(p -> { + CustomerExportLoadCargo cargo = new CustomerExportLoadCargo(); + cargo.setCargoType(0); + cargo.setVinStatus(1); + cargo.setBrandId(brandList.stream().filter(s -> StringUtils.equalsIgnoreCase(s.getText(), keys[3])).findFirst().get().getId()); + cargo.setBrand(keys[3]); + cargo.setVin(p.getVin()); + cargo.setTermcd(exportIn.getPortAreaId()); + return cargo; + }).collect(Collectors.toList()); + + List vins = cargos.stream().map(p -> p.getVin()).collect(Collectors.toList()); + + // 查询出是否已经有了装船导入记录 + List list = customerExportLoadService.lambdaQuery() + .eq(CustomerExportLoad::getShipName, keys[0]) + .eq(CustomerExportLoad::getVoyage, keys[1]) + .eq(CustomerExportLoad::getBillNo, keys[2]) + .eq(CustomerExportLoad::getBrand, keys[3]) + .gt(CustomerExportLoad::getQuantity, 0).list(); + + // 导入时校验待提交、待审核、已通过状态中是否有重复的车架号,重复导入失败,提示”车架号已存在,请勿重复申请“ + List existCargos = customerExportLoadCargoService.list(new LambdaQueryWrapper() + .in(CustomerExportLoadCargo::getVin, vins) + .notIn(CollectionUtils.isNotEmpty(list), CustomerExportLoadCargo::getExportLoadId, list.stream().map(s -> s.getId()).collect(Collectors.toList())) + .exists("select id from customer_export_load where customer_export_load.id = customer_export_load_cargo.export_load_id and customer_export_load.check_status <> 3")); + List existVins = existCargos.stream().map(p -> p.getVin()).collect(Collectors.toList()); + + // 查询出对应的港区 + if (CollectionUtils.isNotEmpty(existCargos)) { + List sList = customerExportLoadService.lambdaQuery().in(CustomerExportLoad::getId, existCargos.stream().map(ss -> ss.getExportLoadId()).collect(Collectors.toList())).list(); + Map portAreaMap = sList.stream().collect(Collectors.toMap(CustomerExportLoad::getId, CustomerExportLoad::getPortAreaId)); + // 通过接口再次验证 + List req = existCargos.stream().map(ss -> { + CheckVinReq v = new CheckVinReq(); + v.setIsRepetition(true); + v.setPamId(portAreaMap.get(ss.getExportLoadId())); + v.setVinCode(ss.getVin()); + return v; + }).collect(Collectors.toList()); + List rst = shpApi.checkVinRepeat(req); + existVins.clear(); + if (CollectionUtils.isNotEmpty(rst)) { + // 再次过滤出重复的 + List sCollect = rst.stream().filter(ss -> ss.getIsRepetition()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(sCollect)) { + existVins.addAll(sCollect.stream().map(ss -> ss.getVinCode()).collect(Collectors.toList())); + } + } + } + + List existData = item.getValue().stream().filter(p -> existVins.contains(p.getVin())).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(existData)) { + errorDataList.addAll(existData.stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "车架号已存在,请勿重复申请"); + return o; + }).collect(Collectors.toList())); + successDataList.addAll(item.getValue().stream().filter(p -> !existVins.contains(p.getVin())) + .map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "数据验证成功"); + return o; + }).collect(Collectors.toList())); + return; + } else { + successDataList.addAll(item.getValue().stream().filter(p -> !existVins.contains(p.getVin())) + .map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "数据验证成功"); + return o; + }).collect(Collectors.toList())); + } + + // 生成新的装船记录 + List saveCargos = cargos.stream().filter(s -> !existVins.contains(s.getVin())).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(saveCargos)) { + if (CollectionUtils.isNotEmpty(list)) { + removeIds.put(item.getKey(), list.stream().map(s -> s.getId()).collect(Collectors.toList())); + } + CustomerExportLoad exportLoad = new CustomerExportLoad(); + exportLoad.setTradType("W"); + exportLoad.setShipName(keys[0]); + exportLoad.setVoyage(keys[1]); + exportLoad.setBillNo(keys[2]); + exportLoad.setShipId(exportIn.getShipId()); + exportLoad.setShipEnName(exportIn.getShipEnName()); + exportLoad.setVoyageId(exportIn.getVoyageId()); + exportLoad.setBrandId(brandList.stream().filter(s -> StringUtils.equalsIgnoreCase(s.getText(), keys[3])).findFirst().get().getId()); + exportLoad.setBrand(keys[3]); + exportLoad.setDestPortId(portList.stream().filter(s -> StringUtils.equalsIgnoreCase(s.getText(), keys[4])).findFirst().get().getId()); + exportLoad.setDestPort(keys[4]); + exportLoad.setQuantity(saveCargos.size()); + exportLoad.setSpareQuantity(0); + exportLoad.setPortArea(exportIn.getPortArea()); + exportLoad.setPortAreaId(exportIn.getPortAreaId()); + exportLoad.setTermcd(exportIn.getPortAreaId()); + if (StringUtils.equals("1", type)) { + exportLoad.setCheckStatus(AuditEnum.AUDIT); + } else { + exportLoad.setCheckStatus(AuditEnum.SUBMIT); + } + exportLoad.setApplyTime(new Date()); + exportLoad.setApplicantId(UserContext.getUser().getUserId()); + + heads.put(item.getKey(), exportLoad); + details.put(item.getKey(), saveCargos); + } + + }); + + if (CollectionUtils.isNotEmpty(errorDataList)) { +// errorDataList.addAll(successDataList); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + if (MapUtils.isNotEmpty(heads)) { + heads.entrySet().forEach(item -> { + CustomerExportLoad exportLoad = item.getValue(); + String batchNo = customerService.getSequenceNo("export_load_batch_no", "出口装船", "EL"); + exportLoad.setBatchNo(batchNo); + + customerService.saveExportLoad(exportLoad, removeIds.get(item.getKey()), details.get(item.getKey())); + }); + } + + return ResultUtil.success(errorDataList); + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:" + e.getRowIndex() + " 列:" + e.getColumnIndex()); + } catch (Exception e) { + log.error("错误信息", e); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), e.getMessage()); + } + } + @ApiOperation("外贸整船车辆导入") @PostMapping("/outside/import-to-add") public Result> outsideUpload(@RequestParam(required = false) String type, MultipartFile file) { @@ -1076,6 +1732,11 @@ public class ExportLoadHandler implements BaseHandler { }); if (CollectionUtils.isEmpty(validData)) { + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } @@ -1102,11 +1763,12 @@ public class ExportLoadHandler implements BaseHandler { iQuery.eq(CustomerExportIn::getVoyage, keys[1]); iQuery.eq(CustomerExportIn::getBillNum, keys[2]); iQuery.eq(CustomerExportIn::getBrand, keys[3]); + iQuery.ne(CustomerExportIn::getCartType, "备件"); iQuery.isNotNull(CustomerExportIn::getVoyageId); iQuery.eq(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_PASS); - CustomerExportIn exportIn = customerExportInService.getOne(iQuery, false); - if (exportIn == null || exportIn.getCheckStatus() != AuditEnum.AUDIT_PASS) { + List exportInList = customerExportInService.list(iQuery); + if (CollectionUtils.isEmpty(exportInList)) { errorDataList.addAll(item.getValue().stream().map(p -> { JSONObject o = JSONObject.from(p); o.put("status", "本船名航次下未找到审核通过的出口进港申请"); @@ -1115,17 +1777,23 @@ public class ExportLoadHandler implements BaseHandler { return; } + CustomerExportIn exportIn = exportInList.get(0); + if (portList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), keys[4])).count() == 0) { - JSONObject o = JSONObject.from(item); - o.put("status", "目的港信息错误"); - errorDataList.add(o); + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "目的港信息错误"); + return o; + }).collect(Collectors.toList())); return; } if (brandList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), keys[3])).count() == 0) { - JSONObject o = JSONObject.from(item); - o.put("status", "品牌不存在"); - errorDataList.add(o); + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "品牌不存在"); + return o; + }).collect(Collectors.toList())); return; } @@ -1226,13 +1894,12 @@ public class ExportLoadHandler implements BaseHandler { heads.put(item.getKey(), exportLoad); details.put(item.getKey(), saveCargos); - } }); if (CollectionUtils.isNotEmpty(errorDataList)) { - errorDataList.addAll(successDataList); +// errorDataList.addAll(successDataList); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } @@ -1241,11 +1908,214 @@ public class ExportLoadHandler implements BaseHandler { CustomerExportLoad exportLoad = item.getValue(); String batchNo = customerService.getSequenceNo("export_load_batch_no", "出口装船", "EL"); exportLoad.setBatchNo(batchNo); - customerService.saveExportLoad(exportLoad, details.get(item.getKey())); + customerService.saveExportLoad(exportLoad, null, details.get(item.getKey())); }); } return ResultUtil.success(errorDataList); + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:" + e.getRowIndex() + " 列:" + e.getColumnIndex()); + } catch (Exception e) { + log.error("错误信息", e); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), e.getMessage()); + } + } + + @ApiOperation("外贸整船车辆导入覆盖") + @PostMapping("/outside/import-to-over") + public Result> outsideUploadOver(MultipartFile file) { + // 所有读取的数据 + List dataList = new ArrayList<>(); + + // 有错误的数据 + List errorDataList = new ArrayList<>(); + + // 验证通过的数据 + List successDataList = new ArrayList<>(); + + List inUpdate = new ArrayList<>(); + + try { + EasyExcel.read(file.getInputStream(), ExportLoadExcel.class, new ReadExcelListener() { + @Override + protected void saveData(List list) { // 保存数据 + dataList.addAll(list); + } + }).sheet().doRead(); + + ValidatorFactory vf = Validation.buildDefaultValidatorFactory(); + Validator validator = vf.getValidator(); + + List validData = new ArrayList<>(); + + // 数据验证 + dataList.stream().forEach(item -> { + Set> set = validator.validate(item); + if (CollectionUtils.isEmpty(set)) { // 验证通过的 + validData.add(item); + } else { // 验证失败的 + JSONObject o = JSONObject.from(item); + o.put("status", set.stream().map(p -> p.getMessage()).collect(Collectors.joining(","))); + errorDataList.add(o); + } + }); + + if (CollectionUtils.isEmpty(validData)) { + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + // 是否有重复的车架号 + List repeat = validData.stream().collect(Collectors.groupingBy(ExportLoadExcel::getVin, Collectors.counting())) + .entrySet().stream().filter(entry -> entry.getValue() > 1).map(entry -> entry.getKey()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(repeat)) { + errorDataList.addAll(validData.stream().filter(p -> repeat.contains(p.getVin())).map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "车架号重复"); + return o; + }).collect(Collectors.toList())); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + // 首先按对船名,般次,提单进行分组 + Map> collect = validData.stream() + .collect(Collectors.groupingBy(item -> StringUtils.joinWith("#$#", item.getShipName(), item.getVoyage(), item.getBillNo(), item.getBrand(), item.getDestPort()), Collectors.toList())); + collect.entrySet().forEach(item -> { + String[] keys = StringUtils.split(item.getKey(), "#$#"); + // 首先判断,船名,航次,提单号在出口进港申请中是否已经通过 + LambdaQueryWrapper iQuery = new LambdaQueryWrapper<>(); + iQuery.eq(CustomerExportIn::getShipName, keys[0]); + iQuery.eq(CustomerExportIn::getVoyage, keys[1]); + iQuery.eq(CustomerExportIn::getBillNum, keys[2]); + iQuery.eq(CustomerExportIn::getBrand, keys[3]); + iQuery.ne(CustomerExportIn::getCartType, "备件"); + iQuery.isNotNull(CustomerExportIn::getVoyageId); + iQuery.eq(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_PASS); + + List exportInList = customerExportInService.list(iQuery); + if (CollectionUtils.isEmpty(exportInList)) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "本船名航次下未找到审核通过的出口进港申请"); + return o; + }).collect(Collectors.toList())); + return; + } + + // 这个品牌的总数 + int sum = exportInList.stream().mapToInt(s -> s.getQuantity()).sum(); + if (item.getValue().size() != sum) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "此品牌的车架号数量与进港计划的数量不一致"); + return o; + }).collect(Collectors.toList())); + return; + } + + CustomerExportIn exportIn = exportInList.get(0); + // 是否已经导入了装船计划 + List exportLoadList = customerExportLoadService.lambdaQuery() + .eq(CustomerExportLoad::getShipId, exportIn.getShipId()) + .eq(CustomerExportLoad::getVoyageId, exportIn.getVoyageId()) + .eq(CustomerExportLoad::getBillNo, exportIn.getBillNum()) + .eq(CustomerExportLoad::getBrandId, exportIn.getBrandId()) + .ne(CustomerExportLoad::getCheckStatus, AuditEnum.AUDIT_REJECT) + .list(); + if (CollectionUtils.isEmpty(exportLoadList)) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "本船名航次下未找到装船计划申请"); + return o; + }).collect(Collectors.toList())); + return; + } + sum = exportLoadList.stream().mapToInt(s -> s.getQuantity()).sum(); + if (item.getValue().size() != sum) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "此品牌的车架号数量与装船计划已导入的数量不一致"); + return o; + }).collect(Collectors.toList())); + return; + } + + List cargos = item.getValue().stream().map(p -> { + CustomerExportLoadCargo cargo = new CustomerExportLoadCargo(); + cargo.setCargoType(0); + cargo.setVinStatus(1); + cargo.setBrand(keys[3]); + cargo.setVin(p.getVin()); + cargo.setTermcd(exportIn.getPortAreaId()); + return cargo; + }).collect(Collectors.toList()); + + // 需要与装船计划的车架号一致 + List loadCargos = customerExportLoadCargoService.lambdaQuery().in(CustomerExportLoadCargo::getExportLoadId, exportLoadList.stream().map(s -> s.getId()).collect(Collectors.toList())).list(); + List vins = loadCargos.stream().map(p -> p.getVin()).collect(Collectors.toList()); + + // 找到不存在的 + List noExists = item.getValue().stream().filter(s -> !vins.contains(s.getVin())).map(s -> s.getVin()).collect(Collectors.toList()); + + if (CollectionUtils.isNotEmpty(noExists)) { + errorDataList.addAll(item.getValue().stream().filter(s -> noExists.contains(s.getVin())).map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "此提单号不存在此车架号"); + return o; + }).collect(Collectors.toList())); + successDataList.addAll(item.getValue().stream().filter(p -> !noExists.contains(p.getVin())) + .map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "数据验证成功"); + return o; + }).collect(Collectors.toList())); + return; + } else { + successDataList.addAll(item.getValue().stream().filter(p -> !noExists.contains(p.getVin())) + .map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "数据验证成功"); + return o; + }).collect(Collectors.toList())); + } + + + // 生成新的装船记录 + if (CollectionUtils.isNotEmpty(cargos)) { + // 进港计划需要覆盖的 + List nVins = cargos.stream().map(s -> s.getVin()).collect(Collectors.toList()); + // 进港计划,需要调整的车架号 + List list = customerExportInCargoService.lambdaQuery().in(CustomerExportInCargo::getExportInId, exportInList.stream().map(s -> s.getId()).collect(Collectors.toList())).list(); + List oVins = list.stream().map(s -> s.getVin()).collect(Collectors.toList()); + // 找到不存在的 + List update = list.stream().filter(s -> !nVins.contains(s.getVin())).collect(Collectors.toList()); + List uVins = nVins.stream().filter(s -> !oVins.contains(s)).collect(Collectors.toList()); + + for (int i = 0; i < update.size(); i++) { + update.get(i).setVin(uVins.get(i)); + } + + inUpdate.addAll(update); + } + + }); + + if (CollectionUtils.isNotEmpty(errorDataList)) { +// errorDataList.addAll(successDataList); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + if (CollectionUtils.isNotEmpty(inUpdate)) { + customerExportInCargoService.updateBatchById(inUpdate); + } + + return ResultUtil.success(errorDataList); + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:" + e.getRowIndex() + " 列:" + e.getColumnIndex()); } catch (Exception e) { log.error("错误信息", e); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), e.getMessage()); @@ -1340,6 +2210,11 @@ public class ExportLoadHandler implements BaseHandler { }); if (CollectionUtils.isEmpty(validData)) { + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } @@ -1368,16 +2243,20 @@ public class ExportLoadHandler implements BaseHandler { } if (portList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), keys[4])).count() == 0) { - JSONObject o = JSONObject.from(item); - o.put("status", "目的港信息错误"); - errorDataList.add(o); + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "目的港信息错误"); + return o; + }).collect(Collectors.toList())); return; } if (brandList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), keys[3])).count() == 0) { - JSONObject o = JSONObject.from(item); - o.put("status", "品牌不存在"); - errorDataList.add(o); + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "品牌不存在"); + return o; + }).collect(Collectors.toList())); return; } @@ -1421,7 +2300,7 @@ public class ExportLoadHandler implements BaseHandler { }); if (CollectionUtils.isNotEmpty(errorDataList)) { - errorDataList.addAll(successDataList); +// errorDataList.addAll(successDataList); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } @@ -1434,6 +2313,390 @@ public class ExportLoadHandler implements BaseHandler { } return ResultUtil.success(errorDataList); + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:" + e.getRowIndex() + " 列:" + e.getColumnIndex()); + } catch (Exception e) { + log.error("错误信息", e); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), e.getMessage()); + } + } + + @ApiOperation("外贸整船备件导入(按船)") + @PostMapping("/outside/spare/import-to-add/ship") + public Result> outsideSpareUploadShip(@RequestParam(required = false) String type, MultipartFile file) { + // 所有读取的数据 + List dataList = new ArrayList<>(); + + // 有错误的数据 + List errorDataList = new ArrayList<>(); + + // 验证成功的数据 + List successDataList = new ArrayList<>(); + + // 要保存的数据 + Map heads = new LinkedHashMap<>(); + Map> removeIds = new HashMap<>(); + + try { + + // 港口基础数据 + List portList = dictHandler.getPortList(null).getData(); + + // 品牌基础数据 + List brandList = dictHandler.getBrandList(null).getData(); + + EasyExcel.read(file.getInputStream(), ExportLoadSpareExcel.class, new ReadExcelListener() { + @Override + protected void saveData(List list) { // 保存数据 + dataList.addAll(list); + } + }).sheet().doRead(); + + ValidatorFactory vf = Validation.buildDefaultValidatorFactory(); + Validator validator = vf.getValidator(); + + List validData = new ArrayList<>(); + + // 数据验证 + dataList.stream().forEach(item -> { + Set> set = validator.validate(item); + if (CollectionUtils.isEmpty(set)) { // 验证通过的 + validData.add(item); + } else { // 验证失败的 + JSONObject o = JSONObject.from(item); + o.put("status", set.stream().map(p -> p.getMessage()).collect(Collectors.joining(","))); + errorDataList.add(o); + } + }); + + if (CollectionUtils.isEmpty(validData)) { + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + // 首先按对船名,般次,判断是否有审核通过的装船计划 + Map> collect = validData.stream() + .collect(Collectors.groupingBy(item -> StringUtils.joinWith("#$#", item.getShipName(), item.getVoyage()), Collectors.toList())); + collect.entrySet().forEach(item -> { + String[] keys = StringUtils.split(item.getKey(), "#$#"); + List list = customerExportLoadService.lambdaQuery() + .eq(CustomerExportLoad::getShipName, keys[0]) + .eq(CustomerExportLoad::getVoyage, keys[1]) + .gt(CustomerExportLoad::getSpareQuantity, 0) + .eq(CustomerExportLoad::getCheckStatus, AuditEnum.AUDIT_PASS).list(); + if (CollectionUtils.isNotEmpty(list)) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "当前航次有审核通过的装船清单"); + return o; + }).collect(Collectors.toList())); + return; + } + }); + + if (CollectionUtils.isNotEmpty(errorDataList)) { +// errorDataList.addAll(successDataList); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + // 首先按对船名,般次,提单进行分组 + collect = validData.stream().collect(Collectors.groupingBy(item -> StringUtils.joinWith("#$#", item.getShipName(), item.getVoyage(), item.getBillNo(), item.getBrand(), item.getDestPort()), Collectors.toList())); + collect.entrySet().forEach(item -> { + String[] keys = StringUtils.split(item.getKey(), "#$#"); + + // 首先判断,船名,航次,提单号在出口进港申请中是否已经通过 + LambdaQueryWrapper iQuery = new LambdaQueryWrapper<>(); + iQuery.eq(CustomerExportIn::getShipName, keys[0]); + iQuery.eq(CustomerExportIn::getVoyage, keys[1]); + iQuery.eq(CustomerExportIn::getBillNum, keys[2]); + iQuery.eq(CustomerExportIn::getBrand, keys[3]); + iQuery.isNotNull(CustomerExportIn::getVoyageId); + iQuery.eq(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_PASS); + + CustomerExportIn exportIn = customerExportInService.getOne(iQuery, false); + if (exportIn == null || exportIn.getCheckStatus() != AuditEnum.AUDIT_PASS) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "本船名航次下未找到审核通过的出口进港申请"); + return o; + }).collect(Collectors.toList())); + return; + } + + if (portList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), keys[4])).count() == 0) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "目的港信息错误"); + return o; + }).collect(Collectors.toList())); + return; + } + + if (brandList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), keys[3])).count() == 0) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "品牌不存在"); + return o; + }).collect(Collectors.toList())); + return; + } + + int num = item.getValue().stream().mapToInt(ExportLoadSpareExcel::getNum).sum(); + + // 查询出是否已经有了装船导入记录 + List list = customerExportLoadService.lambdaQuery() + .eq(CustomerExportLoad::getShipName, keys[0]) + .eq(CustomerExportLoad::getVoyage, keys[1]) + .eq(CustomerExportLoad::getBillNo, keys[2]) + .eq(CustomerExportLoad::getBrand, keys[3]) + .gt(CustomerExportLoad::getSpareQuantity, 0).list(); + + successDataList.addAll(item.getValue().stream() + .map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "数据验证成功"); + return o; + }).collect(Collectors.toList())); + + if (CollectionUtils.isNotEmpty(list)) { + removeIds.put(item.getKey(), list.stream().map(s -> s.getId()).collect(Collectors.toList())); + } + + CustomerExportLoad exportLoad = new CustomerExportLoad(); + + exportLoad.setTradType("W"); + exportLoad.setShipId(exportIn.getShipId()); + exportLoad.setShipName(keys[0]); + exportLoad.setShipEnName(exportIn.getShipEnName()); + exportLoad.setVoyage(keys[1]); + exportLoad.setVoyageId(exportIn.getVoyageId()); + exportLoad.setBillNo(keys[2]); + exportLoad.setBrandId(brandList.stream().filter(s -> StringUtils.equalsIgnoreCase(s.getText(), keys[3])).findFirst().get().getId()); + exportLoad.setBrand(keys[3]); + exportLoad.setDestPortId(portList.stream().filter(s -> StringUtils.equalsIgnoreCase(s.getText(), keys[4])).findFirst().get().getId()); + exportLoad.setDestPort(keys[4]); + exportLoad.setQuantity(0); + exportLoad.setSpareQuantity(num); + exportLoad.setPortArea(exportIn.getPortArea()); + exportLoad.setPortAreaId(exportIn.getPortAreaId()); + exportLoad.setTermcd(exportIn.getTermcd()); + if (StringUtils.equals("1", type)) { + exportLoad.setCheckStatus(AuditEnum.AUDIT); + } else { + exportLoad.setCheckStatus(AuditEnum.SUBMIT); + } + exportLoad.setApplyTime(new Date()); + exportLoad.setApplicantId(UserContext.getUser().getUserId()); + + heads.put(item.getKey(), exportLoad); + + }); + + if (CollectionUtils.isNotEmpty(errorDataList)) { +// errorDataList.addAll(successDataList); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + if (MapUtils.isNotEmpty(heads)) { + heads.entrySet().forEach(item -> { + CustomerExportLoad exportLoad = item.getValue(); + String batchNo = customerService.getSequenceNo("export_load_batch_no", "出口装船", "EL"); + exportLoad.setBatchNo(batchNo); + + customerService.saveExportLoad(exportLoad, removeIds.get(item.getKey()), null); + }); + } + + return ResultUtil.success(errorDataList); + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:" + e.getRowIndex() + " 列:" + e.getColumnIndex()); + } catch (Exception e) { + log.error("错误信息", e); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), e.getMessage()); + } + } + + @ApiOperation("外贸整船备件导入(按提单)") + @PostMapping("/outside/spare/import-to-add/billno") + public Result> outsideSpareUploadBill(@RequestParam(required = false) String type, MultipartFile file) { + // 所有读取的数据 + List dataList = new ArrayList<>(); + + // 有错误的数据 + List errorDataList = new ArrayList<>(); + + // 验证成功的数据 + List successDataList = new ArrayList<>(); + + // 要保存的数据 + Map heads = new LinkedHashMap<>(); + Map> removeIds = new HashMap<>(); + + try { + + // 港口基础数据 + List portList = dictHandler.getPortList(null).getData(); + + // 品牌基础数据 + List brandList = dictHandler.getBrandList(null).getData(); + + EasyExcel.read(file.getInputStream(), ExportLoadSpareExcel.class, new ReadExcelListener() { + @Override + protected void saveData(List list) { // 保存数据 + dataList.addAll(list); + } + }).sheet().doRead(); + + ValidatorFactory vf = Validation.buildDefaultValidatorFactory(); + Validator validator = vf.getValidator(); + + List validData = new ArrayList<>(); + + // 数据验证 + dataList.stream().forEach(item -> { + Set> set = validator.validate(item); + if (CollectionUtils.isEmpty(set)) { // 验证通过的 + validData.add(item); + } else { // 验证失败的 + JSONObject o = JSONObject.from(item); + o.put("status", set.stream().map(p -> p.getMessage()).collect(Collectors.joining(","))); + errorDataList.add(o); + } + }); + + if (CollectionUtils.isEmpty(validData)) { + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + // 首先按对船名,般次,提单进行分组 + Map> collect = validData.stream().collect(Collectors.groupingBy(item -> StringUtils.joinWith("#$#", item.getShipName(), item.getVoyage(), item.getBillNo(), item.getBrand(), item.getDestPort()), Collectors.toList())); + collect.entrySet().forEach(item -> { + String[] keys = StringUtils.split(item.getKey(), "#$#"); + + // 首先判断,船名,航次,提单号在出口进港申请中是否已经通过 + LambdaQueryWrapper iQuery = new LambdaQueryWrapper<>(); + iQuery.eq(CustomerExportIn::getShipName, keys[0]); + iQuery.eq(CustomerExportIn::getVoyage, keys[1]); + iQuery.eq(CustomerExportIn::getBillNum, keys[2]); + iQuery.eq(CustomerExportIn::getBrand, keys[3]); + iQuery.isNotNull(CustomerExportIn::getVoyageId); + iQuery.eq(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_PASS); + + CustomerExportIn exportIn = customerExportInService.getOne(iQuery, false); + if (exportIn == null || exportIn.getCheckStatus() != AuditEnum.AUDIT_PASS) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "本船名航次下未找到审核通过的出口进港申请"); + return o; + }).collect(Collectors.toList())); + return; + } + + if (portList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), keys[4])).count() == 0) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "目的港信息错误"); + return o; + }).collect(Collectors.toList())); + return; + } + + if (brandList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), keys[3])).count() == 0) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "品牌不存在"); + return o; + }).collect(Collectors.toList())); + return; + } + + int num = item.getValue().stream().mapToInt(ExportLoadSpareExcel::getNum).sum(); + + // 查询出是否已经有了装船导入记录 + List list = customerExportLoadService.lambdaQuery() + .eq(CustomerExportLoad::getShipName, keys[0]) + .eq(CustomerExportLoad::getVoyage, keys[1]) + .eq(CustomerExportLoad::getBillNo, keys[2]) + .eq(CustomerExportLoad::getBrand, keys[3]) + .gt(CustomerExportLoad::getSpareQuantity, 0).list(); + + Optional first = list.stream().filter(s -> s.getCheckStatus() == AuditEnum.AUDIT_PASS).findFirst(); + if (first.isPresent()) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "提单号"+first.get().getBillNo()+"已审核通过,请先取消后再次导入装船清单"); + return o; + }).collect(Collectors.toList())); + } + + successDataList.addAll(item.getValue().stream() + .map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "数据验证成功"); + return o; + }).collect(Collectors.toList())); + + if (CollectionUtils.isNotEmpty(list)) { + removeIds.put(item.getKey(), list.stream().map(s -> s.getId()).collect(Collectors.toList())); + } + + CustomerExportLoad exportLoad = new CustomerExportLoad(); + + exportLoad.setTradType("W"); + exportLoad.setShipId(exportIn.getShipId()); + exportLoad.setShipName(keys[0]); + exportLoad.setShipEnName(exportIn.getShipEnName()); + exportLoad.setVoyage(keys[1]); + exportLoad.setVoyageId(exportIn.getVoyageId()); + exportLoad.setBillNo(keys[2]); + exportLoad.setBrandId(brandList.stream().filter(s -> StringUtils.equalsIgnoreCase(s.getText(), keys[3])).findFirst().get().getId()); + exportLoad.setBrand(keys[3]); + exportLoad.setDestPortId(portList.stream().filter(s -> StringUtils.equalsIgnoreCase(s.getText(), keys[4])).findFirst().get().getId()); + exportLoad.setDestPort(keys[4]); + exportLoad.setQuantity(0); + exportLoad.setSpareQuantity(num); + exportLoad.setPortArea(exportIn.getPortArea()); + exportLoad.setPortAreaId(exportIn.getPortAreaId()); + exportLoad.setTermcd(exportIn.getTermcd()); + if (StringUtils.equals("1", type)) { + exportLoad.setCheckStatus(AuditEnum.AUDIT); + } else { + exportLoad.setCheckStatus(AuditEnum.SUBMIT); + } + exportLoad.setApplyTime(new Date()); + exportLoad.setApplicantId(UserContext.getUser().getUserId()); + + heads.put(item.getKey(), exportLoad); + + }); + + if (CollectionUtils.isNotEmpty(errorDataList)) { +// errorDataList.addAll(successDataList); + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + if (MapUtils.isNotEmpty(heads)) { + heads.entrySet().forEach(item -> { + CustomerExportLoad exportLoad = item.getValue(); + String batchNo = customerService.getSequenceNo("export_load_batch_no", "出口装船", "EL"); + exportLoad.setBatchNo(batchNo); + + customerService.saveExportLoad(exportLoad, removeIds.get(item.getKey()), null); + }); + } + + return ResultUtil.success(errorDataList); + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:" + e.getRowIndex() + " 列:" + e.getColumnIndex()); } catch (Exception e) { log.error("错误信息", e); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), e.getMessage()); @@ -1465,7 +2728,7 @@ public class ExportLoadHandler implements BaseHandler { //普通下拉数据 Map map = new HashMap<>(); - String[] isZgArray = {"正常", "国内中转", "外进转内出", "长江","沿海"}; + String[] isZgArray = {"正常", "国内中转", "外进转内出", "长江", "沿海"}; map.put(2, isZgArray); //检查类型-子类 Map> inspNameMap = new HashMap<>(); @@ -1520,7 +2783,6 @@ public class ExportLoadHandler implements BaseHandler { // 结算单位 Map companyMap = new HashMap<>(); -// List companyList = pubApi.getCompanyList(Arrays.asList("7")); // 品牌基础数据 List brandList = dictHandler.getBrandList(null).getData(); // 港口基础数据 @@ -1529,10 +2791,12 @@ public class ExportLoadHandler implements BaseHandler { List shipList = dictHandler.getAllShip(null).getData(); // 港区基础数据 List portAreaList = dictHandler.getPortAreaList(null).getData(); + Map portMap = portAreaList.stream().collect(Collectors.toMap(DictDTO::getId, DictDTO::getText)); // 货物性质 List goodsNature = dictHandler.getGoodsNature().getData(); // 缓存航次信息 Map voyageMap = new HashMap<>(); + Map voyageToPortMap = new HashMap<>(); // 缓存中转航次信息 Map> transferVoyageMap = new HashMap<>(); @@ -1562,6 +2826,11 @@ public class ExportLoadHandler implements BaseHandler { }); if (CollectionUtils.isEmpty(validData)) { + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } @@ -1588,12 +2857,6 @@ public class ExportLoadHandler implements BaseHandler { errorDataList.add(o); return; } - if (portAreaList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), item.getPortArea())).count() == 0) { - JSONObject o = JSONObject.from(item); - o.put("status", "港区不存在"); - errorDataList.add(o); - return; - } if (shipList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), item.getShipName())).count() == 0) { JSONObject o = JSONObject.from(item); o.put("status", "船名不存在"); @@ -1605,11 +2868,12 @@ public class ExportLoadHandler implements BaseHandler { req.setSpmName(item.getShipName()); req.setVvyName(item.getVoyage()); List resp = shpApi.queryVvyListByVvNameAndSpmName(Arrays.asList(req)); -// VoyageDTO v = shpApi.getVoyageNameByVvyName(item.getVoyage()); if (CollectionUtils.isEmpty(resp)) { voyageMap.put(StringUtils.join(item.getShipName(), item.getVoyage()), ""); + voyageToPortMap.put(StringUtils.join(item.getShipName(), item.getVoyage()), ""); } else { voyageMap.put(StringUtils.join(item.getShipName(), item.getVoyage()), StringUtils.trim(resp.get(0).getVvyId())); + voyageToPortMap.put(StringUtils.join(item.getShipName(), item.getVoyage()), StringUtils.trim(resp.get(0).getPamId())); } } if (StringUtils.isEmpty(voyageMap.get(StringUtils.join(item.getShipName(), item.getVoyage())))) { @@ -1618,13 +2882,26 @@ public class ExportLoadHandler implements BaseHandler { errorDataList.add(o); return; } + if (StringUtils.isEmpty(voyageToPortMap.get(StringUtils.join(item.getShipName(), item.getVoyage())))) { + JSONObject o = JSONObject.from(item); + o.put("status", "港区不存在"); + errorDataList.add(o); + return; + } + // 匹配港区字典 + if (!portMap.containsKey(voyageToPortMap.get(StringUtils.join(item.getShipName(), item.getVoyage())))) { + JSONObject o = JSONObject.from(item); + o.put("status", "港区不存在"); + errorDataList.add(o); + return; + } if (goodsNature.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getPtrDesc(), item.getNatureFlagName())).count() == 0) { JSONObject o = JSONObject.from(item); o.put("status", "货物性质不存在"); errorDataList.add(o); return; } - if (!StringUtils.equals(item.getNatureFlagName(), "正常")) { + if (StringUtils.equalsAny(item.getNatureFlagName(), "内进转外出", "外进转内出", "国际中转", "国内中转")) { if (shipList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), item.getTransferShipName())).count() == 0) { JSONObject o = JSONObject.from(item); o.put("status", "中转进口船名不存在"); @@ -1682,6 +2959,8 @@ public class ExportLoadHandler implements BaseHandler { // 相同的提单号,必须是相同的结算单位 LambdaQueryWrapper lQuery = new LambdaQueryWrapper<>(); + lQuery.eq(CustomerExportLoad::getShipName, keys[0]); + lQuery.eq(CustomerExportLoad::getVoyage, keys[1]); lQuery.eq(CustomerExportLoad::getBillNo, keys[2]); lQuery.ne(CustomerExportLoad::getSettleCompId, companyMap.get(item.getValue().get(0).getSettleCompName())); @@ -1738,7 +3017,7 @@ public class ExportLoadHandler implements BaseHandler { List existData = item.getValue().stream().filter(p -> existVins.contains(p.getVin())).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(existData)) { - errorDataList.addAll(item.getValue().stream().map(p -> { + errorDataList.addAll(existData.stream().map(p -> { JSONObject o = JSONObject.from(p); o.put("status", "车架号已存在,请勿重复申请"); return o; @@ -1782,15 +3061,15 @@ public class ExportLoadHandler implements BaseHandler { exportLoad.setSpareQuantity(0); exportLoad.setSettleCompId(companyMap.get(item.getValue().get(0).getSettleCompName())); exportLoad.setSettleCompName(item.getValue().get(0).getSettleCompName()); - exportLoad.setPortAreaId(portAreaList.stream().filter(s -> StringUtils.equals(s.getText(), item.getValue().get(0).getPortArea())).findFirst().get().getId()); - exportLoad.setPortArea(item.getValue().get(0).getPortArea()); + exportLoad.setPortAreaId(voyageToPortMap.get(StringUtils.join(keys[0], keys[1]))); + exportLoad.setPortArea(portMap.get(exportLoad.getPortAreaId())); exportLoad.setContact(item.getValue().get(0).getContact()); exportLoad.setContactPhone(item.getValue().get(0).getContactPhone()); exportLoad.setNatureFlagName(item.getValue().get(0).getNatureFlagName()); exportLoad.setNatureFlag(goodsNature.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getPtrDesc(), item.getValue().get(0).getNatureFlagName())).findFirst().get().getPtrCode()); exportLoad.setTransferVoyage(item.getValue().get(0).getTransferVoyage()); exportLoad.setTransferShipName(item.getValue().get(0).getTransferShipName()); - if (!StringUtils.equals(item.getValue().get(0).getNatureFlagName(), "正常")) { + if (StringUtils.equalsAny(item.getValue().get(0).getNatureFlagName(), "内进转外出", "外进转内出", "国际中转", "国内中转")) { exportLoad.setTransferShipId(shipList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), item.getValue().get(0).getTransferShipName())).findFirst().get().getId()); exportLoad.setTransferVoyageId(transferVoyageMap.get(exportLoad.getTransferShipName()).stream().filter(p -> StringUtils.equalsIgnoreCase(p.getVvyName(), item.getValue().get(0).getTransferVoyage())).findFirst().get().getVvyId()); } @@ -1813,7 +3092,7 @@ public class ExportLoadHandler implements BaseHandler { }); if (CollectionUtils.isNotEmpty(errorDataList)) { - errorDataList.addAll(successDataList); +// errorDataList.addAll(successDataList); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } @@ -1822,129 +3101,105 @@ public class ExportLoadHandler implements BaseHandler { CustomerExportLoad exportLoad = item.getValue(); String batchNo = customerService.getSequenceNo("export_load_batch_no", "出口装船", "EL"); exportLoad.setBatchNo(batchNo); - customerService.saveExportLoad(exportLoad, details.get(item.getKey())); + customerService.saveExportLoad(exportLoad, null, details.get(item.getKey())); }); } return ResultUtil.success(errorDataList); + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:" + e.getRowIndex() + " 列:" + e.getColumnIndex()); } catch (Exception e) { log.error("错误信息", e); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), e.getMessage()); } } - /* - @ApiOperation("内贸整船备件导入") - @PostMapping("/inside/spare/import-to-add") - public Result> insideSpareUpload(@RequestParam(required = false) String type, MultipartFile file) throws IOException { - // 所有读取的数据 - List dataList = new ArrayList<>(); + @ApiOperation("出口装船导出") + @GetMapping("/exportExecl") + public void exportExecl( + @ApiParam(name = "操作方式, 0为前端,1为审核端") @RequestParam(required = false, defaultValue = "0") String type, + ExportLoadCheckQuery query, HttpServletResponse response) { + if (StringUtils.equals(type, "0")) { + query.setCreateBy(UserContext.getUser().getUserId()); + } + query.setPage(1); + query.setRows(100); + query.setSorts(null); +// query.setSorts(Arrays.asList(new BaseQuery.SortField("shipId", "asc"), new BaseQuery.SortField("voyageId", "asc"), new BaseQuery.SortField("billNum", "asc"))); + QueryWrapper queryWrapper = (QueryWrapper) new WrapperKit() { + }.changeBaseQueryToWrapper(CustomerExportLoad.class, query); - // 有错误的数据 - List errorDataList = new ArrayList<>(); + queryWrapper.orderByAsc(Arrays.asList("voyage_id", "bill_no")); - // 公司信息 - List companyList = pubApi.getCompanyList(Arrays.asList("7")); + ExcelWriter excelWriter = null; + OutputStream out = null; + try { + out = response.getOutputStream(); - EasyExcel.read(file.getInputStream(), ExportLoadInsideSpareExcel.class, new ReadExcelListener() { - @Override - protected void saveData(List list) { // 保存数据 - dataList.addAll(list); + // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman + response.setContentType("application/vnd.ms-excel"); + response.setCharacterEncoding("utf-8"); + // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 + String fileName = URLEncoder.encode(DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN) + "出口装船清单", "UTF-8"); + response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); + + + excelWriter = EasyExcel.write(out).build(); + + WriteSheet writeSheet = EasyExcel.writerSheet(0, "出口装船计划").head(ExportLoadExportExcel.class).build(); + + // 查询数据 + Page page = customerExportLoadService.page(new Page<>(query.getPage(), query.getRows()), queryWrapper); + + AtomicInteger index = new AtomicInteger(1); + + write(index, page.getRecords(), excelWriter, writeSheet); + + for (int i = 2; i <= page.getPages(); i++) { + query.setPage(i); + page = customerExportLoadService.page(new Page<>(query.getPage(), query.getRows()), queryWrapper); + + write(index, page.getRecords(), excelWriter, writeSheet); } - }).sheet().doRead(); - - ValidatorFactory vf = Validation.buildDefaultValidatorFactory(); - Validator validator = vf.getValidator(); - - List validData = new ArrayList<>(); - - // 数据验证 - dataList.stream().forEach(item -> { - Set> set = validator.validate(item); - if (CollectionUtils.isEmpty(set)) { // 验证通过的 - validData.add(item); - } else { // 验证失败的 - JSONObject o = JSONObject.from(item); - o.put("status", set.stream().map(p -> p.getMessage()).collect(Collectors.joining(","))); - errorDataList.add(o); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (excelWriter != null) { + excelWriter.finish(); + } + if (out != null) { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } } - }); - - if (CollectionUtils.isEmpty(validData)) { - return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } - validData.stream().forEach(item -> { - if (companyList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getCueCnname(), item.getSettleCompName())).count() == 0) { - JSONObject o = JSONObject.from(item); - o.put("status", "结算单位不存在"); - errorDataList.add(o); - return; - } - }); + } - // 首先按对船名,般次,提单进行分组 - Map> collect = validData.stream().collect(Collectors.groupingBy(item -> StringUtils.joinWith("#$#", item.getShipName(), item.getVoyage(), item.getBillNo(), item.getBrand()), Collectors.toList())); - collect.entrySet().forEach(item -> { - String[] keys = StringUtils.split(item.getKey(), "#$#"); + private void write(AtomicInteger index, List headers, ExcelWriter excelWriter, WriteSheet writeSheet) { + if (CollectionUtils.isEmpty(headers)) { + excelWriter.write(Collections.emptyList(), writeSheet); + return; + } - // 首先判断,船名,航次,提单号在出口进港申请中是否已经通过 - LambdaQueryWrapper iQuery = new LambdaQueryWrapper<>(); - iQuery.eq(CustomerExportIn::getShipName, keys[0]); - iQuery.eq(CustomerExportIn::getVoyage, keys[1]); - iQuery.eq(CustomerExportIn::getBillNum, keys[2]); - iQuery.eq(CustomerExportIn::getBrand, keys[3]); - iQuery.isNotNull(CustomerExportIn::getVoyageId); - iQuery.eq(CustomerExportIn::getCheckStatus, AuditEnum.AUDIT_PASS); + Map loadMap = headers.stream().collect(Collectors.toMap(CustomerExportLoad::getId, s -> s)); - CustomerExportIn exportIn = customerExportInService.getOne(iQuery); - if (exportIn == null || exportIn.getCheckStatus() != AuditEnum.AUDIT_PASS) { - errorDataList.addAll(item.getValue().stream().map(p -> { - JSONObject o = JSONObject.from(p); - o.put("status", "本船名航次下未找到审核通过的出口进港申请"); - return o; - }).collect(Collectors.toList())); - return; - } + List cargos = customerExportLoadCargoService.lambdaQuery() + .in(CustomerExportLoadCargo::getExportLoadId, headers.stream().map(s -> s.getId()).collect(Collectors.toList())).list(); - int num = item.getValue().stream().mapToInt(ExportLoadInsideSpareExcel::getNum).sum(); + if (CollectionUtils.isEmpty(cargos)) { + excelWriter.write(Collections.emptyList(), writeSheet); + return; + } - errorDataList.addAll(item.getValue().stream() - .map(p -> { - JSONObject o = JSONObject.from(p); - o.put("status", "导入成功"); - return o; - }).collect(Collectors.toList())); + List rows = cargos.stream().map(item -> { + ExportLoadExportExcel e = PoMapper.instance.entity2Excel(loadMap.get(item.getExportLoadId())); + e.setVin(item.getVin()); + return e; + }).collect(Collectors.toList()); - String batchNo = customerService.getSequenceNo("export_load_batch_no", "出口装船", "EL"); - - CustomerExportLoad exportLoad = new CustomerExportLoad(); - - exportLoad.setTradType("N"); - exportLoad.setShipId(exportIn.getShipId()); - exportLoad.setShipName(keys[0]); - exportLoad.setShipEnName(exportIn.getShipEnName()); - exportLoad.setVoyageId(exportIn.getVoyageId()); - exportLoad.setVoyage(keys[1]); - exportLoad.setBillNo(keys[2]); - exportLoad.setBrandId(exportIn.getBrandId()); - exportLoad.setBrand(exportIn.getBrand()); - exportLoad.setBatchNo(batchNo); - exportLoad.setQuantity(0); - exportLoad.setSpareQuantity(num); - if (StringUtils.equals("1", type)) { - exportLoad.setCheckStatus(AuditEnum.AUDIT); - } else { - exportLoad.setCheckStatus(AuditEnum.SUBMIT); - } - exportLoad.setApplyTime(new Date()); - -// exportLoad.setQuantity(exportLoad.getQuantity() + saveCargos.size()); - - customerService.saveExportLoad(exportLoad, Collections.emptyList()); - - }); - - return ResultUtil.success(errorDataList); - }*/ + excelWriter.write(rows, writeSheet); + } } diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/FreeTradeHandler.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/FreeTradeHandler.java index a80390c..ef1fa00 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/FreeTradeHandler.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/FreeTradeHandler.java @@ -4,6 +4,7 @@ import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.exception.ExcelDataConvertException; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.Wrapper; @@ -12,13 +13,18 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.haitonggauto.rtosc.api.NuzarMiniApi; +import com.haitonggauto.rtosc.api.NuzarShpApi; +import com.haitonggauto.rtosc.api.dto.VoyageReq; +import com.haitonggauto.rtosc.api.dto.VoyageResp; import com.haitonggauto.rtosc.common.context.UserContext; +import com.haitonggauto.rtosc.common.dto.DictDTO; import com.haitonggauto.rtosc.common.dto.Result; import com.haitonggauto.rtosc.common.enums.ErrorType; import com.haitonggauto.rtosc.common.handler.BaseHandler; import com.haitonggauto.rtosc.common.utils.*; import com.haitonggauto.rtosc.dto.FreeTradeCheckVo; import com.haitonggauto.rtosc.dto.FreeTradeVo; +import com.haitonggauto.rtosc.dto.ValidVinActivateVo; import com.haitonggauto.rtosc.dto.VoyageSubmitVo; import com.haitonggauto.rtosc.excel.*; import com.haitonggauto.rtosc.handler.excel.ReadExcelListener; @@ -74,6 +80,12 @@ public class FreeTradeHandler implements BaseHandler { @Resource private NuzarMiniApi miniApi; + @Resource + private NuzarShpApi shpApi; + + @Resource + private DictHandler dictHandler; + /** * 分页查询 * @@ -267,19 +279,37 @@ public class FreeTradeHandler implements BaseHandler { return ResultUtil.success("success"); } + @ApiOperation("返回车架号详情, IsActivate 为 1 代表已激活") + @PostMapping("/valid-vins-all") + public Result> validAllVins(@RequestBody @Validated ValidVinActivateVo vo) { + List list = customerFreeTradeService.lambdaQuery() + .eq(StringUtils.isNotEmpty(vo.getShipId()), CustomerFreeTrade::getShipId, vo.getShipId()) + .eq(StringUtils.isNotEmpty(vo.getVoyageId()), CustomerFreeTrade::getVoyageId, vo.getVoyageId()) + .in(CustomerFreeTrade::getVin, vo.getVins()).list(); + // 返回的车架号信息 +// List collect = list.stream().map(item -> item.getVin()).collect(Collectors.toList()); + // 待激活的车架号信息 +// List noActivate = list.stream().filter(item -> item.getIsActivate() == ActiveEnum.NO).map(item -> item.getVin()).collect(Collectors.toList()); +// List noValid = vins.stream().filter(item -> !collect.contains(item) || noActivate.contains(item)).collect(Collectors.toList()); +// if (CollectionUtils.isNotEmpty(noValid)) { +// return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), StringUtils.join(noValid, ",")); +// } + return ResultUtil.success(list); + } + /** * 验证车架号状态是否激活 - * @param vins + * @param vo * @return */ @ApiOperation("验证车架号激活状态, 返回已激活车架号详情") @PostMapping("/valid-vins") - public Result> validVins(@RequestBody - @NotNull(message = "请传入车架号列表") - @Size(min = 1, message = "车架号列表不能为空") List vins) { + public Result> validVins(@RequestBody @Validated ValidVinActivateVo vo) { List list = customerFreeTradeService.lambdaQuery() + .eq(StringUtils.isNotEmpty(vo.getShipId()), CustomerFreeTrade::getShipId, vo.getShipId()) + .eq(StringUtils.isNotEmpty(vo.getVoyageId()), CustomerFreeTrade::getVoyageId, vo.getVoyageId()) .eq(CustomerFreeTrade::getIsActivate, ActiveEnum.YES) - .in(CustomerFreeTrade::getVin, vins).list(); + .in(CustomerFreeTrade::getVin, vo.getVins()).list(); // 返回的车架号信息 // List collect = list.stream().map(item -> item.getVin()).collect(Collectors.toList()); // 待激活的车架号信息 @@ -333,8 +363,8 @@ public class FreeTradeHandler implements BaseHandler { log.setOperateData(record); log.setStatus(check.getCheckStatus() == AuditEnum.AUDIT_PASS ? 0 : 1); log.setOperateTime(new Date()); - log.setUserId(SecurityUtils.getUserId()); - log.setUserName(SecurityUtils.getUserName()); + log.setUserId(UserContext.getUser().getUserId()); + log.setUserName(UserContext.getUser().getUsername()); EsLogApprovalUtil.writeLog(log); } @@ -422,6 +452,12 @@ public class FreeTradeHandler implements BaseHandler { // 验证成功的数据 List successDataList = new ArrayList<>(); + // 船名基础数据 + List shipList = dictHandler.getAllShip(null).getData(); + + // 航次缴存 + Map voyageMap = new HashMap<>(); + try { EasyExcel.read(file.getInputStream(), FreeTradeExcel.class, new ReadExcelListener() { @@ -450,6 +486,41 @@ public class FreeTradeHandler implements BaseHandler { // 所有数据验证都不通过 if (CollectionUtils.isEmpty(validData)) { + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + validData.stream().forEach(item -> { + if (shipList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), item.getShipName())).count() == 0) { + JSONObject o = JSONObject.from(item); + o.put("status", "船名不存在"); + errorDataList.add(o); + return; + } + if (!voyageMap.containsKey(StringUtils.join(item.getShipName(), item.getVoyage()))) { + VoyageReq req = new VoyageReq(); + req.setSpmName(item.getShipName()); + req.setVvyName(item.getVoyage()); + List resp = shpApi.queryVvyListByVvNameAndSpmName(Arrays.asList(req)); + if (CollectionUtils.isEmpty(resp)) { + voyageMap.put(StringUtils.join(item.getShipName(), item.getVoyage()), ""); + } else { + voyageMap.put(StringUtils.join(item.getShipName(), item.getVoyage()), StringUtils.trim(resp.get(0).getVvyId())); + } + } + if (StringUtils.isEmpty(voyageMap.get(StringUtils.join(item.getShipName(), item.getVoyage())))) { + JSONObject o = JSONObject.from(item); + o.put("status", "航次不存在"); + errorDataList.add(o); + return; + } + }); + + if (CollectionUtils.isNotEmpty(errorDataList)) { return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } @@ -467,6 +538,11 @@ public class FreeTradeHandler implements BaseHandler { List collect = validData.stream().map(item -> { CustomerFreeTrade freeTrade = PoMapper.instance.excel2Entity(item); + + freeTrade.setShipId(shipList.stream().filter(s -> StringUtils.equalsIgnoreCase(s.getText(), item.getShipName())).findFirst().get().getId()); + freeTrade.setShipEnName(shipList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), item.getShipName())).findFirst().get().getExtra1()); + freeTrade.setVoyageId(voyageMap.get(StringUtils.join(item.getShipName(), item.getVoyage()))); + freeTrade.setApplicantId(UserContext.getUser().getUserId()); freeTrade.setIsActivate(ActiveEnum.NO); freeTrade.setApplyTime(new Date()); @@ -514,6 +590,8 @@ public class FreeTradeHandler implements BaseHandler { customerFreeTradeService.saveBatch(save); return ResultUtil.success(errorDataList); + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:"+e.getRowIndex()+" 列:" + e.getColumnIndex()); } catch (Exception e) { log.error("错误信息", e); return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), e.getMessage()); diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/HeathCheckHandler.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/HeathCheckHandler.java new file mode 100644 index 0000000..70362bf --- /dev/null +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/HeathCheckHandler.java @@ -0,0 +1,14 @@ +package com.haitonggauto.rtosc.handler; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/health") +public class HeathCheckHandler { + @GetMapping("/ping") + public String ping() { + return "pong"; + } +} diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ImportInspectHandler.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ImportInspectHandler.java index 9ca898c..c55519a 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ImportInspectHandler.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ImportInspectHandler.java @@ -2,15 +2,20 @@ package com.haitonggauto.rtosc.handler; import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.exception.ExcelDataConvertException; import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.haitonggauto.rtosc.api.NuzarOpenApi; +import com.haitonggauto.rtosc.api.NuzarShpApi; import com.haitonggauto.rtosc.api.NuzarYardApi; import com.haitonggauto.rtosc.api.dto.*; import com.haitonggauto.rtosc.api.dto.log.ImportInspectLog; @@ -19,12 +24,16 @@ import com.haitonggauto.rtosc.common.dto.DictDTO; import com.haitonggauto.rtosc.common.dto.Result; import com.haitonggauto.rtosc.common.enums.ErrorType; import com.haitonggauto.rtosc.common.handler.BaseHandler; +import com.haitonggauto.rtosc.common.utils.DateUtils; import com.haitonggauto.rtosc.common.utils.ResultUtil; import com.haitonggauto.rtosc.common.utils.ValidationGroup; import com.haitonggauto.rtosc.common.utils.WrapperKit; import com.haitonggauto.rtosc.dto.*; +import com.haitonggauto.rtosc.excel.ExportInPlanExcel; import com.haitonggauto.rtosc.excel.ExportInspectExportExcel; import com.haitonggauto.rtosc.excel.ImportInspectExportExcel; +import com.haitonggauto.rtosc.excel.InspectExcel; +import com.haitonggauto.rtosc.handler.excel.ReadExcelListener; import com.haitonggauto.rtosc.handler.mapper.PoMapper; import com.haitonggauto.rtosc.query.CargoQuery; import com.haitonggauto.rtosc.query.ExportInspectCheckQuery; @@ -41,18 +50,32 @@ import com.nuzar.rtops.log.service.EsLogApprovalUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.core.io.ClassPathResource; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; -import java.io.IOException; -import java.io.OutputStream; +import java.io.*; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.net.URLEncoder; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; @@ -62,6 +85,7 @@ import java.util.stream.Collectors; @RequestMapping("/iis") @Api(tags = "进口海关查验") @Validated +@Slf4j public class ImportInspectHandler implements BaseHandler { @Resource @@ -79,6 +103,12 @@ public class ImportInspectHandler implements BaseHandler { @Resource private NuzarYardApi yardApi; + @Resource + private NuzarShpApi shpApi; + + @Resource + private DictHandler dictHandler; + @ApiOperation("船名航次模糊匹配") @PostMapping("/shipVoyage") public Result> getExportInShipNameList( @@ -178,17 +208,19 @@ public class ImportInspectHandler implements BaseHandler { @ApiOperation("提单号模糊匹配") @PostMapping("/billNo/query") public Result> getExportInBillNoList( + @ApiParam(name = "操作方式, 0为前端,1为审核端") @RequestParam(required = false, defaultValue = "0") String type, @RequestParam(required = false, defaultValue = "1") Integer current, @RequestParam(required = false, defaultValue = "10") Integer size, @RequestParam(required = false) String shipName, @RequestParam(required = false) String voyage, @RequestParam(required = false) String q) { - LambdaQueryWrapper query = new LambdaQueryWrapper<>(); - query.eq(CustomerExportInspect::getTradType, "I"); - query.eq(StringUtils.isNotEmpty(shipName), CustomerExportInspect::getShipName, shipName); - query.eq(StringUtils.isNotEmpty(voyage), CustomerExportInspect::getVoyage, voyage); - query.like(StringUtils.isNotEmpty(q), CustomerExportInspect::getBillNo, q); // 提单号 - + QueryWrapper query = new QueryWrapper<>(); + query.select("distinct bill_no"); + query.eq("trad_type", "I"); + query.eq(StringUtils.equals(type, "0"), "create_by", UserContext.getUser().getUserId()); + query.eq(StringUtils.isNotEmpty(shipName), "ship_name", shipName); + query.eq(StringUtils.isNotEmpty(voyage), "voyage", voyage); + query.like(StringUtils.isNotEmpty(q), "bill_no", q); // 提单号 Page page = customerExportInspectService.page(new Page<>(current, size), query); List list = page.getRecords(); @@ -346,6 +378,9 @@ public class ImportInspectHandler implements BaseHandler { exportInspect.setCheckStatus(form.getFlag() ? AuditEnum.AUDIT : AuditEnum.SUBMIT); exportInspect.setTermcd(exportInspect.getPortAreaId()); exportInspect.setApplyTime(new Date()); + if (StringUtils.isEmpty(exportInspect.getCompany())) { // 公司为空,则填充申请对象 + exportInspect.setCompany(exportInspect.getApplyObj()); + } List cargos = form.getCargos().stream().map(item -> { CustomerExportInspectCargo entity = PoMapper.instance.exportInspectCargoVo2Entity(item); @@ -474,6 +509,28 @@ public class ImportInspectHandler implements BaseHandler { customerService.wrapperEntity(exportInspect); List cargos = customerExportInspectCargoService.list(new LambdaQueryWrapper().eq(CustomerExportInspectCargo::getExportInspectId, id)); + // 获取实时 + if (CollectionUtils.isNotEmpty(cargos)) { + GoodsStatusReq req = new GoodsStatusReq(); + req.setBusinessType("INSPECT"); + req.setImportExportType("I"); + req.setVvyId(StringUtils.equalsAnyIgnoreCase(exportInspect.getVoyageId(), "HT6", "HTLG", "HTTC") ? "" : exportInspect.getVoyageId()); + req.setVinCodeList(cargos.stream().map(p -> p.getVin()).collect(Collectors.toList())); + + List resp = openApi.getGoodsStatus(req); + + Map respMap = resp.stream().collect(Collectors.toMap(p -> p.getVinCode(), p -> p)); + + cargos.stream().forEach(p -> { + GoodsStatusResp r = respMap.get(p.getVin()); + if (r != null) { + p.setArea(r.getPosition()); + } else { + p.setArea(""); + } + }); + } + customerService.wrapperEntity(cargos); exportInspect.setCargos(cargos); @@ -516,6 +573,35 @@ public class ImportInspectHandler implements BaseHandler { queryWrapper.eq(query.getCargoType() != null, CustomerExportInspectCargo::getCargoType, query.getCargoType()); } Page page = customerExportInspectCargoService.page(new Page<>(query.getPage(), query.getRows()), queryWrapper); + + // 获取实时 + if (CollectionUtils.isNotEmpty(page.getRecords())) { + // 需要按InspectId 进行分组 + Map> collect = page.getRecords().stream().collect(Collectors.groupingBy(CustomerExportInspectCargo::getExportInspectId)); + collect.entrySet().forEach(item -> { + CustomerExportInspect inspect = customerExportInspectService.getById(item.getKey()); + + GoodsStatusReq req = new GoodsStatusReq(); + req.setBusinessType("INSPECT"); + req.setImportExportType("I"); + req.setVvyId(StringUtils.equalsAnyIgnoreCase(inspect.getVoyageId(), "HT6", "HTLG", "HTTC") ? "" : inspect.getVoyageId()); + req.setVinCodeList(item.getValue().stream().map(p -> p.getVin()).collect(Collectors.toList())); + + List resp = openApi.getGoodsStatus(req); + + Map respMap = resp.stream().collect(Collectors.toMap(p -> p.getVinCode(), p -> p)); + + page.getRecords().stream().filter(p -> p.getExportInspectId() == item.getKey()).forEach(p -> { + GoodsStatusResp r = respMap.get(p.getVin()); + if (r != null) { + p.setArea(r.getPosition()); + } else { + p.setArea(""); + } + }); + }); + } + customerService.wrapperEntity(page.getRecords()); return ResultUtil.success(page); } @@ -565,10 +651,11 @@ public class ImportInspectHandler implements BaseHandler { // 判断车辆是否在场 List vinStatus = yardApi.getVinStatus(vins); + List exists = vinStatus.stream().map(item -> item.getVinCode()).collect(Collectors.toList()); page.getRecords().stream().forEach(item -> { item.setInspect(collect.get(item.getExportInspectId())); - item.setInArea(vinStatus.contains(item.getVin())); + item.setInArea(exists.contains(item.getVin())); }); } @@ -607,8 +694,8 @@ public class ImportInspectHandler implements BaseHandler { log.setOperateData(importInspectLog); log.setStatus(check.getCheckStatus() == AuditEnum.AUDIT_PASS ? 0 : 1); log.setOperateTime(new Date()); - log.setUserId(SecurityUtils.getUserId()); - log.setUserName(SecurityUtils.getUserName()); + log.setUserId(UserContext.getUser().getUserId()); + log.setUserName(UserContext.getUser().getUsername()); EsLogApprovalUtil.writeLog(log); } @@ -655,8 +742,8 @@ public class ImportInspectHandler implements BaseHandler { log.setOperateData(record); log.setStatus(check.getCheckStatus() == AuditEnum.AUDIT_PASS ? 0 : 1); log.setOperateTime(new Date()); - log.setUserId(SecurityUtils.getUserId()); - log.setUserName(SecurityUtils.getUserName()); + log.setUserId(UserContext.getUser().getUserId()); + log.setUserName(UserContext.getUser().getUsername()); EsLogApprovalUtil.writeLog(log); } @@ -756,6 +843,7 @@ public class ImportInspectHandler implements BaseHandler { private void write(AtomicInteger index, List headers, ExcelWriter excelWriter, WriteSheet writeSheet) { if (CollectionUtils.isEmpty(headers)) { + excelWriter.write(new ArrayList<>(), writeSheet); return; } @@ -779,6 +867,10 @@ public class ImportInspectHandler implements BaseHandler { // 备件号排序 List details = list.stream().filter(p -> ids.contains(p.getExportInspectId())) + .map(s -> { + s.setCartType(StringUtils.isBlank(s.getCartType()) ? "":s.getCartType()); + return s; + }) .sorted(Comparator.comparing(CustomerExportInspectCargo::getCartType).reversed()) .map(p -> { CustomerExportInspect head = collect.get(p.getExportInspectId()); @@ -791,4 +883,279 @@ public class ImportInspectHandler implements BaseHandler { excelWriter.write(details, writeSheet); }); } + + @ApiOperation("进口查验导入模板下载") + @GetMapping("/temp/down") + public void tempDownPlan(HttpServletResponse response) throws Exception { + // 加载模板 + ClassPathResource classPathResource = new ClassPathResource("templates/import_inspect_temp.xlsx"); + InputStream inputStream = classPathResource.getInputStream(); + + XSSFWorkbook workbook = new XSSFWorkbook(inputStream); + + OutputStream out = response.getOutputStream(); + try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + + // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman + response.setContentType("application/vnd.ms-excel"); + response.setCharacterEncoding("utf-8"); + // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 + String fileName = URLEncoder.encode("进口查验导入模板", "UTF-8"); + response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); + + workbook.write(bos); + byte[] bArray = bos.toByteArray(); + InputStream is = new ByteArrayInputStream(bArray); + IOUtils.copy(is, out); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (out != null) { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + @ApiOperation("进口查验导入") + @PostMapping("/inspect/import-to-add") + public Result> exportInPlanUpload( + @ApiParam(name = "操作方式, 0为前端,1为审核端") @RequestParam(required = false, defaultValue = "0") String type, + MultipartFile file) { + // 所有读取的数据 + List dataList = new ArrayList<>(); + + // 有错误的数据 + List errorDataList = new ArrayList<>(); + + // 验证通过的数据 + List successDataList = new ArrayList<>(); + + Map headMap = new HashMap<>(); + Map> detailMap = new HashMap<>(); + + try { + + EasyExcel.read(file.getInputStream(), InspectExcel.class, new ReadExcelListener() { + @Override + protected void saveData(List list) { // 保存数据 + dataList.addAll(list); + } + }).sheet().doRead(); + + ValidatorFactory vf = Validation.buildDefaultValidatorFactory(); + Validator validator = vf.getValidator(); + + List validData = new ArrayList<>(); + + // 需要保存的数据 + List saveData = new ArrayList<>(); + + // 数据验证 + dataList.stream().forEach(item -> { + Set> set = validator.validate(item); + if (CollectionUtils.isEmpty(set)) { // 验证通过的 + validData.add(item); + } else { // 验证失败的 + JSONObject o = JSONObject.from(item); + o.put("status", set.stream().map(p -> p.getMessage()).collect(Collectors.joining(","))); + errorDataList.add(o); + } + }); + + if (CollectionUtils.isEmpty(validData)) { // 数据完整性检验 + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + // 获取用户绑定的货代 + List userBindFreight = openApi.getUserBindFreight(); + + // 港区基础数据 + List portAreaList = dictHandler.getPortAreaList(null).getData(); + + // 航次不能为空 + validData.stream().forEach(item -> { + if (StringUtils.isEmpty(item.getVoyage())) { + JSONObject o = JSONObject.from(item); + o.put("status", "般次不能为空"); + errorDataList.add(o); + return; + } + if (portAreaList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), item.getPortArea())).count() == 0) { + JSONObject o = JSONObject.from(item); + o.put("status", "港区不存在"); + errorDataList.add(o); + return; + } + saveData.add(item); + }); + + // 首先按对船名,般次,提单进行分组 + Map> inMap = saveData.stream() + .collect(Collectors.groupingBy(item -> StringUtils.joinWith("#$#", item.getShipName(), item.getVoyage(), item.getBillNo()), Collectors.toList())); + + inMap.entrySet().forEach(item -> { + String[] keys = StringUtils.split(item.getKey(), "#$#"); + String shipName = keys[0]; // 船名 + String voyageName = keys[1]; // 航次 + String billNo = keys[2]; // 提单号 + + List req = item.getValue().stream().map(s -> { + ImportInspectReq r = new ImportInspectReq(); + r.setSpmName(shipName); + r.setMnfBl(billNo); + r.setVinCode(s.getVin()); + r.setVvyName(voyageName); + return r; + }).collect(Collectors.toList()); + + System.err.println(JSON.toJSONString(req)); + + // 调用接口进行验证 + List resp = shpApi.unloadInfoVerify(req); + + Map stringMap = resp.stream().filter(s -> StringUtils.isNotBlank(s.getErrorMsg())).collect(Collectors.toMap(s -> s.getVinCode(), s -> s.getErrorMsg())); + if (MapUtils.isNotEmpty(stringMap)) { + errorDataList.addAll(item.getValue().stream().filter(p -> stringMap.keySet().contains(p.getVin())).map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", stringMap.get(p.getVin())); + return o; + }).collect(Collectors.toList())); + return; + } + + long count1 = resp.stream().filter(s -> s.getYardGoodsDTO() == null).count(); + if (count1 > 0) { + errorDataList.addAll(item.getValue().stream().filter(p -> stringMap.keySet().contains(p.getVin())).map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "接口未返回货物详细信息,参数为:" + JSONObject.toJSONString(req)); + return o; + }).collect(Collectors.toList())); + return; + } + + ImportInspectResp.YardGoodsDTO in = resp.get(0).getYardGoodsDTO(); + + // 港区是否一致 + long count = item.getValue().stream().map(s -> s.getPortArea()).collect(Collectors.toList()) + .stream().filter(s -> !StringUtils.equals(s, in.getPamName())).count(); + if (count > 0) { + errorDataList.addAll(item.getValue().stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "港区不一致"); + return o; + }).collect(Collectors.toList())); + return; + } + + Map respMap = resp.stream().collect(Collectors.toMap(ImportInspectResp::getVinCode, s -> s)); + List tList = new ArrayList<>(); + item.getValue().forEach(s -> { + String errorMsg = respMap.get(s.getVin()).getErrorMsg(); + if (StringUtils.isNotEmpty(errorMsg)) { + JSONObject o = JSONObject.from(item); + o.put("status", errorMsg); + tList.add(o); + } + }); + + if (CollectionUtils.isNotEmpty(tList)) { + errorDataList.addAll(tList); + return; + } + + CustomerExportInspect head = PoMapper.instance.excel2Entity(item.getValue().get(0)); + + String batchNo = customerService.getSequenceNo("inspect_in_batch_no", "出口查验", "CI"); + head.setInspectStatus(InspectStatusEnum.NO_INSPECT); + head.setBatchNo(batchNo); + head.setApplicantId(UserContext.getUser().getUserId()); + head.setTradType("I"); + head.setPortAreaId(portAreaList.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getText(), head.getPortArea())).findFirst().get().getId()); + head.setCheckStatus(StringUtils.equals(type, "1") ? AuditEnum.AUDIT : AuditEnum.SUBMIT); + head.setTermcd(head.getPortAreaId()); + head.setApplyTime(new Date()); + head.setShipId(in.getSpmId()); +// head.setShipEnName(in.getShipEnName()); + if (StringUtils.isNotEmpty(head.getVoyage())) { + head.setVoyageId(in.getVvyId()); + } +// head.setApplyObjId(in.getFreightId()); +// head.setApplyObj(in.getFreight()); + if (StringUtils.isEmpty(head.getCompany())) { + head.setCompany(head.getApplyObj()); + } + + List detail = item.getValue().stream().map(s -> { + CustomerExportInspectCargo c = new CustomerExportInspectCargo(); + c.setCargoType(StringUtils.startsWith(s.getVin(), "BJ") ? 1 : 0); + + ImportInspectResp.YardGoodsDTO ss = respMap.get(s.getVin()).getYardGoodsDTO(); + + c.setBrand(ss.getBrdName()); + c.setBrandId(ss.getBrdId()); + c.setCartTypeId(ss.getGoodsType()); + c.setCartType(ss.getBvmName()); + c.setModels(in.getModel()); + c.setVin(s.getVin()); + return c; + }).collect(Collectors.toList()); + + head.setPlannedCargoQuantity((int)detail.stream().filter( s -> s.getCargoType() == 0).count()); + head.setPlannedSpareQuantity(detail.size() - head.getPlannedCargoQuantity()); + + headMap.put(item.getKey(), head); + detailMap.put(item.getKey(), detail); + + }); + + if (CollectionUtils.isNotEmpty(errorDataList)) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); + } + + // 判断车辆是否在场 + List vinStatus = yardApi.getVinStatus(dataList.stream().map(s -> s.getVin()).collect(Collectors.toList())); +// if (CollectionUtils.isEmpty(vinStatus)) { +// errorDataList.addAll(dataList.stream().map(p -> { +// JSONObject o = JSONObject.from(p); +// o.put("status", "所有查验的车架号均不在场"); +// return o; +// }).collect(Collectors.toList())); +// return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); +// } + + Map vinStatusMap = vinStatus.stream().collect(Collectors.toMap(VinStatus::getVinCode, s -> s)); + + // 保存对象 + headMap.keySet().stream().forEach(s -> customerService.saveExportInspect(headMap.get(s), detailMap.get(s))); + + successDataList.addAll(dataList.stream().map(p -> { + JSONObject o = JSONObject.from(p); + o.put("status", "成功"); + o.put("yardPos", vinStatusMap.containsKey(p.getVin()) ? vinStatusMap.get(p.getVin()).getYardPos() : "未进港"); + return o; + }).collect(Collectors.toList())); + } catch (ExcelDataConvertException e) { + return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入数据错误,请确认导入数据模板是否正确, 行:"+e.getRowIndex()+" 列:" + e.getColumnIndex()); + } catch (Exception e) { + log.error("上传错误", e); + return ResultUtil.failure(ErrorType.PROGRAM_ERROR.id(), e.getMessage()); + } + + List rst = new ArrayList<>(); + rst.addAll(successDataList.stream().filter(s -> StringUtils.isNotBlank(s.getString("yardPos"))).collect(Collectors.toList())); + rst.addAll(successDataList.stream().filter(s -> StringUtils.isBlank(s.getString("yardPos"))).collect(Collectors.toList())); + + return ResultUtil.success(rst); + } } + + diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ImportUnloadHandler.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ImportUnloadHandler.java index c0b1141..a15bb08 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ImportUnloadHandler.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/ImportUnloadHandler.java @@ -441,6 +441,11 @@ public class ImportUnloadHandler implements BaseHandler { }); if (CollectionUtils.isEmpty(validData)) { + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } @@ -632,6 +637,11 @@ public class ImportUnloadHandler implements BaseHandler { }); if (CollectionUtils.isEmpty(validData)) { + if (CollectionUtils.isEmpty(errorDataList)) { // 代表没有读取到数据 + JSONObject o = new JSONObject(); + o.put("status", "未读取到数据"); + errorDataList.add(o); + } return ResultUtil.failure(ErrorType.PARAMS_ERROR.id(), "导入失败", errorDataList); } diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/excel/ExcelMergeUtil.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/excel/ExcelMergeUtil.java index ff2e9b0..373a7b4 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/excel/ExcelMergeUtil.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/excel/ExcelMergeUtil.java @@ -74,7 +74,7 @@ public class ExcelMergeUtil implements CellWriteHandler { // 将当前单元格数据与上一个单元格数据比较 Boolean dataBool = preData.equals(curData); //此处需要注意,获取每一行第二列数据和上一行第一列数据进行比较,如果相等合并,getCell里面的值,是名称所在列的下标 - System.err.println(cell.getRow().getCell(baseColIndex).getStringCellValue()); +// System.err.println(cell.getRow().getCell(baseColIndex).getStringCellValue()); Boolean bool = cell.getRow().getCell(baseColIndex).getStringCellValue().equals(cell.getSheet().getRow(curRowIndex - 1).getCell(baseColIndex).getStringCellValue()); if (dataBool && bool) { Sheet sheet = writeSheetHolder.getSheet(); diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/excel/ReadExcelListener.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/excel/ReadExcelListener.java index 35071f9..e2460de 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/excel/ReadExcelListener.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/excel/ReadExcelListener.java @@ -5,6 +5,8 @@ import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.util.ListUtils; import com.alibaba.fastjson2.JSON; import lombok.extern.slf4j.Slf4j; +import org.springframework.util.ReflectionUtils; +import org.thymeleaf.util.StringUtils; import java.util.List; @@ -37,10 +39,23 @@ public abstract class ReadExcelListener implements ReadListener { @Override public void invoke(T data, AnalysisContext context) { log.info("解析到一条数据:{}", JSON.toJSONString(data)); + // 去除空格的处理 + ReflectionUtils.doWithFields(data.getClass(), (field) -> { + field.setAccessible(true); + // 只处理字符串类型 + if (String.class.isAssignableFrom(field.getType())) { + // 属性值 + String str = (String)field.get(data); + + field.set(data, StringUtils.trim(str)); + } + + }); cachedDataList.add(data); // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM if (cachedDataList.size() >= BATCH_COUNT) { + saveData(cachedDataList); // 存储完成清理 list cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/mapper/PoMapper.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/mapper/PoMapper.java index e70c1de..ba32f9a 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/mapper/PoMapper.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/handler/mapper/PoMapper.java @@ -116,4 +116,8 @@ public interface PoMapper { @Mapping(source = "endEnterTime", target = "inEndTm", dateFormat = "yyyy-MM-dd") @Mapping(source = "contactPhone", target = "personTel") OldExportInAddReq exportIn2OldExportInAddReq(CustomerExportIn exportIn); + + CustomerExportInspect excel2Entity(InspectExcel excel); + + ExportLoadExportExcel entity2Excel(CustomerExportLoad entity); } diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/job/SyncToOldHandler.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/job/SyncToOldHandler.java index a9786d0..52baf09 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/job/SyncToOldHandler.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/job/SyncToOldHandler.java @@ -40,13 +40,6 @@ public class SyncToOldHandler { XxlJobHelper.log("需要同步的数据:" + JSONObject.toJSONString(collect)); - // 异步时,变量会丢失 -// LoginUser tmpUser = new LoginUser(); -// tmpUser.setUserId(SecurityUtils.getUserId()); -// tmpUser.setRoleId(0L); -// tmpUser.setAdmin(true); -// -// UserContext.setUser(tmpUser); for (CustomerExportInSyncLog item : page.getRecords()) { try { diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/service/CustomerService.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/service/CustomerService.java index 5dde021..64dde4a 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/service/CustomerService.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/service/CustomerService.java @@ -49,7 +49,7 @@ public interface CustomerService { * @param cargos * @return */ - Long saveExportLoad(CustomerExportLoad exportLoad, List cargos); + Long saveExportLoad(CustomerExportLoad exportLoad, List removeIds, List cargos); /** * 删除出口装船 diff --git a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/service/impl/CustomerServiceImpl.java b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/service/impl/CustomerServiceImpl.java index 263eab9..307cd1b 100644 --- a/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/service/impl/CustomerServiceImpl.java +++ b/nuzar-customer-controller/src/main/java/com/haitonggauto/rtosc/service/impl/CustomerServiceImpl.java @@ -3,6 +3,8 @@ package com.haitonggauto.rtosc.service.impl; import cn.hutool.core.date.DateUtil; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.haitonggauto.rtosc.api.NuzarOpenApi; +import com.haitonggauto.rtosc.api.dto.UserInfoDto; import com.haitonggauto.rtosc.common.context.UserContext; import com.haitonggauto.rtosc.common.dto.LoginUser; import com.haitonggauto.rtosc.common.utils.OkHttpUtils; @@ -20,10 +22,12 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.client.utils.DateUtils; +import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.support.WebApplicationContextUtils; import javax.annotation.Resource; import java.math.RoundingMode; @@ -94,6 +98,9 @@ public class CustomerServiceImpl implements CustomerService { @Resource private SyncConfig syncConfig; + @Resource + private NuzarOpenApi openApi; + @Override @EchoResult public T wrapperEntity(T entity) { @@ -190,6 +197,8 @@ public class CustomerServiceImpl implements CustomerService { @Override @Transactional(rollbackFor = {Exception.class}) public Long saveExportIn(CustomerExportIn exportIn, List cargos, List times, List spares) { + // 去除空格 + exportIn.setBillNum(StringUtils.trim(exportIn.getBillNum())); // 保存表头 exportInService.save(exportIn); @@ -341,7 +350,12 @@ public class CustomerServiceImpl implements CustomerService { @Override @Transactional(rollbackFor = {Exception.class}) - public Long saveExportLoad(CustomerExportLoad exportLoad, List cargos) { + public Long saveExportLoad(CustomerExportLoad exportLoad, List removeIds, List cargos) { + + if (CollectionUtils.isNotEmpty(removeIds)) { + exportLoadCargoService.lambdaUpdate().in(CustomerExportLoadCargo::getExportLoadId, removeIds).remove(); + exportLoadService.lambdaUpdate().in(CustomerExportLoad::getId, removeIds).remove(); + } // 保存表头 exportLoadService.save(exportLoad); @@ -794,9 +808,12 @@ public class CustomerServiceImpl implements CustomerService { if (!syncConfig.getSync() || CollectionUtils.isEmpty(list)) { // 没有打开同步或,列表为空真直接返回 return; } + + UserInfoDto info = openApi.getUserInfo(); // 异步时,变量会丢失 LoginUser tmpUser = new LoginUser(); - tmpUser.setUserId(SecurityUtils.getUserId()); + tmpUser.setUserId(info.getId()); + tmpUser.setUsername(info.getName()); tmpUser.setRoleId(0L); tmpUser.setAdmin(true); @@ -861,9 +878,13 @@ public class CustomerServiceImpl implements CustomerService { if (!syncConfig.getSync() || CollectionUtils.isEmpty(list)) { // 没有打开同步或,列表为空真直接返回 return; } + + UserInfoDto info = openApi.getUserInfo(); + // 异步时,变量会丢失 LoginUser tmpUser = new LoginUser(); - tmpUser.setUserId(SecurityUtils.getUserId()); + tmpUser.setUserId(info.getId()); + tmpUser.setUsername(info.getName()); tmpUser.setRoleId(0L); tmpUser.setAdmin(true); diff --git a/nuzar-customer-controller/src/main/resources/application-pre.yml b/nuzar-customer-controller/src/main/resources/application-pre.yml index 3be0c01..44b93b7 100644 --- a/nuzar-customer-controller/src/main/resources/application-pre.yml +++ b/nuzar-customer-controller/src/main/resources/application-pre.yml @@ -16,7 +16,7 @@ # import: # - optional:nacos:${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} -server: - port: 18086 +#server: +# port: 18086 # servlet: # context-path: /move diff --git a/nuzar-customer-controller/src/main/resources/logback-spring.xml b/nuzar-customer-controller/src/main/resources/logback-spring.xml index 06beff5..8e93a79 100644 --- a/nuzar-customer-controller/src/main/resources/logback-spring.xml +++ b/nuzar-customer-controller/src/main/resources/logback-spring.xml @@ -43,8 +43,8 @@ 100MB - 1 - true + 7 + diff --git a/nuzar-customer-controller/src/main/resources/templates/departure_temp.xlsx b/nuzar-customer-controller/src/main/resources/templates/departure_temp.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..2e55d830e29c870e3aedb4e1ef49ffbffdc8cc79 GIT binary patch literal 8766 zcmeHMg;$hY_a3@y7#gL!TUxr5MrovD7&@gxKte)NX;A5sM!G>-B!&3XV!YpyVksW&pYSrXFvNqTT=}M6$C&BU;+RDI)DW%%gz)D07yUu0EhvY z$VPI`P9D}y9%j0}F4pcQ+&&OT+I&=G)?5HG;`#rL|Kb%WOCDD5<|R}(Rlbs2S>jp}RB#*GOX z=+HBz65;9X-(hMeqeyZyG=S%Vs2=iBn3=`dyalAYHgszX%CE?%mQmV~kV*yr$eQne zLbTl1gj-@*Bsu`?{HFe7iRi&l@f6{Y3F0pf_H2Hphd;PfP-E!*7D&BJ-)Yk6>#$j9 zH@RJ;skOPYHVRBXvqWCvjYw$4UmRUVZ)p>`|5%W+ra1bj#IP>`%+c;|?Ek!-^;OJ~ z=0&qGiJcjjQTD?Sy3om4fF?Mmmb9GTX)K^enxx>-@Lm_~;w94xF?G)}l~r?ge1era zIX#5)+q?d3c@0q!_Rzo&1A~nZIy81Isr{YaPhhN~DxBSdPKY*}4?AQD2RrB(10r|7 z4Qz`0?ToJ(g~9eyH-q?Z&;fwkTNHri-(Xp%$IEbph_y!u)ZrjtY363_=+49a+x35N z{4d7fU;cVo(qoNoUfc+{@>S%(>GWa(p{$y>jB*Q|ZeXy=0zq9|0VCC7I}0_TE@c>s zQc!E))ev-1B5rGd?&P~*Squ;)&QR}N9+7t8>WRV5?3SwNTDHdWfY z8qZ$ZSd^zWxXhq9wJ%>yIL7^y5{vj9bp)woMu=hGV}m7&vkIhXS)JYTh^hvW+^yGR zZ-Zu1-*4hcM~Ob#nam&=aJR6XtMDIiq&q&R)YGvOwXd?sb`zubHM4T;IFx_ePJHdp zrJgyUO)m&M;~!J%XUaVeGOQKcAI|da5y9#%9oQQTjiD)8LNL@nL9#|Wj`kG+kZJ^k z2oNjd;|@Qb_V~(TV;AC&Tn}^0Xem|!B^^?;R&cIx+=Mbg-+2I=fGmO4lGlE z093HJ1M)#aNX?l8&p!x%_5g@&$jUkqSHfQq6v%C{?8FBs;;Ga|)b zNUtEvZ#oW;)OpDrvD}{J+^EmEr@IRJR4n$l)H_~4yrqV1wFfiM~&X7MJJP4i9m2YB_JuKq5lB?+3XEJB|3Q8bf3;QM}8aDBx>i=W<}BJ zTn0|4xl(X5DaNIsNMu({&sPb4&bvzWJRP8y&)!cmOuKa?@gcr!Woc9Z38m% zdUe!`cp9_krsSTPu49?<3}YVR72sFR_`>%Z)_r~uDrF1!pz(DbTB@_Bz*LL#P*!CZ z)n%mz>*Jn5EA`!S_buSuI;ZeA!Y3tY+j8646LAtC6N0#16b@h;R>I4Bgvb683tu`h zQj0*w0#zpZlb^419aE4k7k0N*cpGd;a~TxPyElN`IwDH3Wg^L2KZuH^TeZHVwoNE8 zN4V>sdM0&twJpg#A~q(g4&Y=qkRXnLZM{gaT$te4cw(ZWclwMA{iq5Y|NNvwXt!ue zXz`|l@6xHCkHu+2e$f=9_@kmCUTW$3)^%VS{}c+3u*m@CIibCr*{f@MKg^f-tVoe? z4^6thto)>S#S9VP|Aat@RC3xO;+tj!3@8DZNC*i0P8ELz!hdK32~ou%fb`!z%CsM= z_3#q5;@m{?dcXA|A)52xq2JNlCcqr5WrH%)2?QQ3Q?WOj=zmq?L2-`og^%=moeJT9 zM;qCO{fgo~p&j~tGmU|Q^!-w#znBL?nlZI|xi;Jf4%e;*Uxe%Il!w+fG|;|bvst@sl7pV0=Y;yw zOdL{RsYu}Y0wy-T&~cn~Dx6>*e7drE>^lnXEV#g3qb^muUm_&wAK^h8IiN%n#Fpf~ zmY>n02Ve1!y&Pg|haPYaAHi)_2m7a&5j*|Qkg1I;Y{WnT0J;%blN|BHA6e7g&f40; zo#)rY_gnhRO#YQVBj7B%()w)#eT?>`AnnJcC3?`_+A(lHbtp+}#;(8pe9&?=iv2q~ zh%Rb9-={IZR{_sl{l@X;LOh3R(biN{v1%uiOH9a)`cE$>#8orNAZ(OVvNG}CHg*qo z-}Wxe#+4#T$jEME8~QD;#fln)k#h6ht34~^e}WU=;5A}wE0e5MNR|3-6K_hk?nr)M zR|r=}Pqiy6(Fm_xT82}w%krw?Nfwozp=sDums9sL3Uq@dW_!+YSjr29Ms=lR_{DquGj1|RG7@Yjt#6*1pM@LD7FUJD7wve` z?QdqJNOtvAhA(ECn>RVO=~>I%7GCppWk)gxI7Zk8ZMtc(FRUbxRBMtPNsdXo4yDHE zOG}gNEWYO3w>ZY5Ot?QDrUM*uxBkrh=`2`>4QS#|NBH8%0fQ#j9{a*Kn&d|O`8Ptm z*}0WXAD5PRwCmm^AbU0B>gmT@Oa~Lc+AKzjE(?{_wSD}|9!do`BaX2>W%x6-+Ae22 zGW{4i8CS?j$&t|3he4kRK$GXvhS{|hkK{|{R?JIN!62a z8u=fqFTOpvk;vB}$1R!rC`{e3#fati)mGv%o+yUn3_+i_x4**0cpQq|#fyvn?I}e7 zpk>sT(!SGROhe0|vy@G3?r1lT_KnZXks9qeQYD);jhoB(a$kPKP!TdbPwu%;M08}a zoFlhJ4)1$zBRzHYHQF}6nbo5(U4jZ!$p_>6mRuqXknZxNpG}Y7L7Ju~y%uaHPZoYo z;#-WhGrXcEbKC2Iub?f4?Am!HP5f>FWl@Hj5$MvL2U%Hx3n8D!+NGU{4G$uBMbO-z1;%714^Z!VP=MHLjkI~W;ipLQ+6RS%1wWneP0dL(k4h`cyXj>)*?7f-Y7 zcX1{+<1C?Gyy@ok7t^STUp%#w zgQ4OdDKehfGMY4Bg4a>78;ZZxn9F`7-lU`=#TJ(=S3xz~kFpu1$iGK+kx_F<6v$~D zNzeUFrvLa$j?rSfse<1NA`)>&p_aT0jvefH*Sw-LSrPWXY1Ook#*jLF5x3@x92A=PRG&WrQ3{ z)V%mCi)Zz~SkHTE=m3lf^fKB?Wu!h4%$mJK`Bs@k>rtOASwEqvQbgKR!th$ruhOK= zOp2p&C1VA_gE;AX<;;WqE3acY<@;N)Oil0(TsEnBiC(Krl)72yQ|EhB7=5}phXx_a z>+{Qo98<|lZuk*>_V!s?d*Jm!ytLW+{XRqVmEO}avzwc%UV`PT<6(iAQ>TbNF@JgB z=Pc;iLQ_AG{LKsL`?k)ue9=UFoSL|8Too9E5AON+y(q$)>9)b7vC8EU{?>Vr*m=x2 zni{JAyp4nfeJ`DF-ZDc7&|qa|7_Kzz;RKg3+G_N}%$mD+rRl)vQ)L`n1$;Zq+J`>U z0(yr$;u`&eA*Wg=maD)|If`h;l7EogR$xVfQJsJYtgL9|2-3FqPzDYR4=ECALwbIm zg-ls~5#ExL5=h)Lq;;T^?)rlH1IZ9OdDi%qrtEPr4IL3wIlHXpOCKq0CN@ zyVJ*}*PT9fh0Dm0>JQiH6+q$)EH{Tk-*ED&!~ieKURDEr(bs}stIhUwShZFcth>;q zZGKYG!|4cE7c*cOs8pM6#+b0MvaRGH?kG9QNFU1YAM&D z?=ff$r*^me(Hxw-ucXA5Mxu@(VxMxCT3l{rMqmZj&&j&MHIlXgNjn-zyEkwqznK>Q zV_6difdQ{3si&pKR_hi4imZ}E9MSQOhL!H=iSOm?bg8iF-Yz&Uk@6Xn8lj+wj3v~# z@-w$F(o4OZKqfsFsyog+>^jaA$LTXKuY5DjOm4PU?u9$Nn*R7u(xIIBw4lkyg>lG> zXSTNcMs{_h$^h0P44YQ>syOKfBTt?{l4z0qE8kpQ+MJ<*agoYX4B zBUzNv(&nkG=4ta%-m1uQbdx`J)yldsAJqHVZ1Vm~E{j}sAeAcR$k)h$I#43c{6ifR zHoL7%?}aL&4&PZ+E-@JH$%RV>XRcSH@fN*UB+AE^0|#U`Cdt-`t`kZUqbL>fEKkG2 zF*8Mz8Sg#C57NOC)T7LAoZh0vq~U539vJFZ#7}Z!rWmvFp+BkxbMa4}bFunYkbM0x zbhX$ynZ!l6$g+R5KrvnZO6#3z!B5L1fJDWxbB&9C|CI@%JuHF@*zBzfVNIUS=XOeg|w5w!$P0IG=On zrrL{^Anm0js>rlf6oV1-Y+PtbMzNc6kn3JW!1WAe8niaiWeS8b9ZcJw24NG&M7=gl z2(qK-A_AF^v6u(UI@S7_zgyhE z=Ll?{DXA@}db$~@^-+39Nv2fNe@o03d&iq9kp|x|rHWL6MEZ#F`bo>=(e`o0@=iT^ z;HiCeY)InzfmRQ4SE$ zo>%)ME^s*_(ypQo?wm+<=uUp*>H~ZxZ=I*goW>UDo#kg48_QI~Xsq()`#qsELBDf) zKCk}G>1gd3fb1JkWtoXaz%qz~JxWvy%r2wD#ufFV)bzrpoQ*BckFk*kt#g1ZTxEg& zk;1+-ZRp0^k$H|}ed1x#Sb-LB6)&*&$bv0}83$i?+eH~$H!ug23P?lA99FT!Alu-nq}P>+{}4~K;4baR`7U2WpBs*`Iv5a zLEY?Fgo3AMEJ2jyyiy^2kzodz?Z(sZ@)AmBH;#|YB^+zSd@D=NJA9E4+M(CcjOCo< z4oBnHnv8aAY;Ak`{>&v%POYAZmpE(Ms9vu=M0tP3f0Lc$RVINUR1F1!YgRkK*_$(J zTgiNQC~?r&>9~W3A$Y>P?+EMd{y68Ktr5!l;Bo;fFgD9SV)z-DzFfRg72`qXsC2VM ztL6%yoOFH;vO8_k$k*Bv!$;wvLCq7PPOKKWk7vOX-)$#FIXe170_GZ@(-?;=jSFr4 zInb{&jJoy+2Cl2rG{aU1-IfmBJ5AXmxD}nF`Bf#}l~E1so2V5LN8S#^c?a}IsExU4SM0txYT)|zQ|7-PVHS3-qQylAY^hPPBf03Rq)sj?TRn) zDAwik2<28*C<5X_dWRE|9|fQ}>Ghx_IJMP}uDb`s`(BIT4y44^Rd(dpsipw2UbzL> z85~{h_`nl@5J#8Yhat6gN)Co(E#k&tIZd4T{A|7nBFp)GE4%IJXvS|UI=y+2s#v2( zO4YR{yDIiw!MjgOF*s`ja(lEOygtrxNy2AokhwD`q48xXRpN*1GLeBvg3;J-iIKvw z@XWr#;*QKl*7rRg^hf9=dEXkyhEQ$69q0$G^uMnAY=MiV8e-jz5Lt%^Axl^}TWY#FySVdMI=fl_(Np@L z8i80k|0ENQZdy6nQn^=fK>COo=5gu_}2#b!$ zGh-~_Jw`}|op!Bzg*mxVHA*jJm1;f`I?oEbnglhjd=DcFwv_#;AMztf{FV5#SzLJ! z8C5>ow_(N4gF)o%nz>oMg864H+a0Wz>mgDULVBC(aY0iG-k(#yQ{(Rza79``>$Su; zg+595I=}5-zbQ5^ZZW`mXh4rfjNVxKnE4dzK3B_x-a>O+&Otq@ulEq+2K_9JM`)03 z_LrC(S6Yx^tDbJR36)x;#9}yu5{w@+xyemx29H`>F8a^acR%HEBi{ml*eewd zXFj5!+|) zi-2~49|4QYbYhKo_(ZFaY+Re8v{-n_7jE(iglHl@ghOGxkT;rS=K^9r^ZV5f|bebOLXdkDGBKxRSGUl$t>p1 z1L*w*F>oQSR@m9(hyxj>esm0B*#x$|>iP7>#_LMn%TLqK&}d>pH&S!q1)W)+(P%zc z6sNopr5IM7Lk*QC>k%q)vd6KuNXqXuz@ZHIoOG@Z7Pp=&R~=sgmFZ2eMutz<;i=F- z6L^P$f&wM4uJ>=(ojX-%90DFV-Ru8Zka>a!q89c-N5Q~~4Ce?VoosN(qi;i!xQB9z zivkP&Scc@{E OPcVYVi+(Gy0RIQTG7Odg literal 0 HcmV?d00001 diff --git a/nuzar-customer-controller/src/main/resources/templates/export_inspect_temp.xlsx b/nuzar-customer-controller/src/main/resources/templates/export_inspect_temp.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..58090187c25e80c8934aadb2ea483fc99863b59c GIT binary patch literal 10336 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 literal 0 HcmV?d00001 diff --git a/nuzar-customer-controller/src/main/resources/templates/import_inspect_temp.xlsx b/nuzar-customer-controller/src/main/resources/templates/import_inspect_temp.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..459a87fd506a02f99bf818f3da060511f76e8c51 GIT binary patch literal 8109 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 F@c?W3*arXr literal 20109 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 Raxx4u4EDfT91C}lJ^dBp9j^3z{Gs7#JB?fuh3K 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 delta 15092 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 diff --git a/nuzar-customer-controller/src/main/resources/templates/template.xlsx b/nuzar-customer-controller/src/main/resources/templates/template.xlsx index fd2f59e46c2d0fcc048b66dad9f20421f34cc3d6..69d636d39184290f0d4f7cc417f94496d67e6411 100644 GIT binary patch delta 6538 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 Z^Z!^qbAXivgrWVx(E`-)D!l*D{SSu%R$~AF delta 6586 zcmZWubyO5e+h1B@$pz^S-IY>e>F)0C?(SFxq@w0}gqIw&Z|EjGU!ilhjwj$BE{--Ea|JcpiV%ENQ8$Y9lw_rrCl z(MG23r*p3vONxFUsLIQ@;<^XL-;Npfa)yar$gV=XP9&3** zI!MCKL-AIkK!LF$?wOx~5Ymt&ord1nCiA&R9!g9HUc(p$e>&-Xw-yY0?}iPGcE{rV zr1BdH#mq8P0gP{~qb(K&VK7WC1fJl^*;{3;vzvyc!x=<_vGvf8TgSMeBm8$;>o#t z|E2Lh^FzIeQPknNAFO{~(QVVJWb6j{PPvMBV;ztcxRhN*`IC2C8UIG;OloejD#YrJ z18bl~tl^zHYnnlrFS&}Ltd_s=;sMu*sfHtmVcyJHf_?1IPo`buuHK9M5|NhChZK%! zKUiayol-&GRn&{TRE2AVmk0Pwe0B>wBGIX6BGfl*Xpe-%DH0bqu25mTC5t)SB@Za} zlF&HY$$Nua z{~KEl6fJ5PhhcV-cBQW(Cm zzq@b0wT@czzf)0qKCyjo>Mu9zR5?hT^?oLmM@dt$=ZTTRE6DEcVu+i348fANu>l&( z^6Qe>pQrWThTB@*0H_jSzgb))?QsV>?8Uuu=g9EJre_>zkEce{-Dr+s<+louw31zx zDPzhu7SJzHWTn${bIX3oaBQP!w0^XiBdYlu8kKii?#TA*fIBWdO06pJZ|=idta zvnckjwDXUA_}0Qc(yR!G-e)WGhZYqTyU#2NGRxa8A`=hIY9RytIo=14%*uS`_-QX` z*H93T)kO!E!3>16Nm#;1cHH%KuVw?*2S!iQ0KX6_?y=;ljm0J&^u%@4|QS8Aazj?$-NWK z`dd)nkV(g*3fafy(~BMhcX4ZpaP9CB6!_)-d+8srs0~$*wkl0~bw_mv^?e&EpdnBY z7>Ig;&eHB)jplHL7cb7r==CX_hkU$Or6mCE<5d6^-3F2Tr{ydKuMHyXY2;xIu+L(b7efP#k&||0*(Jw!O3IwGxy`)ZN!-2?x+$pC$Whp>l($gfZB-4li(1LHD z=)xOt3Y@{CH_wb}%T;5__w6R5_t5{$oahIvJy)m>e#xnkXdyw_1!GCVkp~w2GqUuR zErHT+4gR1Ax7>|ptXA&v?VBb2->1HI#G~hm2uMmaL_)f2s@$}Q`NxPgu59_UZF6lX zBcv4!EY^}XRxf}1R-4C3zqI#lf(7{kMstb!WOBq;aROXm!hucmMJbXuCE6Ai|AfzJ zi&sC_3BpH%jI%A65fvI$WnN4!TyifE6=s1XyVSijVaR$>?Y2rb_ja8X2)1? zN&m^IL>kITVedHsN?01s)*6H@y;-Ha%I(r86#(gI42@KTv+hCL!+w5+t&>rY13C1&?tY7N~&NZ*YMPEl9qge#t0m4j^# zt-GC{gS|Y8#sNB<=_&IPJg3o~(ijEA8gENwr|BJue4+yr`;Kuv$loYS7qo6gQPgVH zj0_&~v}9b9OY1-WGEae7lX!tDMe?;Kv?5g06_MG_FPXk`*_twAa!S9Iqb{Cw1JAWO zvO~I6y1w&r2htIk7&ibkkAPlEe9k6#=)x_Nj`4$P~s5&g= z;KY{tvTrpKpUHG+$^*55rIZ@H*YYnwNY5=+=aEmPv0Kk*|C&?8&rUjE7h zYv=?p|Dl1DO)W9_IwIwm+VQ2xC-X2d|G1wF+#M*sTqe2L`~#R7^vtg$ezuOFliL!J zZ_y4Zzb=>7*-ZXJ^V!d>vkGdTmr|81Y%ig|xxH&5QUBdH&M{8#)aZHXlX7>gkF(L0i~!rOnav|h3>`!mP?!GtcRHN?+n zE9cQ^;2-Dkw}+nxBE*=ed}1hWHSETSPrrX(6!%d)-odDp35RE@z$C;itnGeh zG}ni~8i<8_Lu=M3vM+B|&41M25%0R~hW5Do+wA~m5VCL$CalAacs$OHND@Jir>HA1 zP#~x^HOuIE5tx&j8kP{D+G3q?_47D+>JfEbI4DJ9h=B!xqp9UU&rXW5TN(i!&&gqn zWY*S{mt~1c)dtI}6u)WEPSr1*b((RimH19I<0LQ1^4410Q(mDsY+9RAUP(qm5X>-E zUjo~XVZcWG-!56wN&^*wIwikD7WPTYZBt_Zs-zUbq(vVl#SOtYlN#6_IU*uzcnYOO zNpXt!&&#xvkcwyyV!J!kjqLJrOx*8@{;VTLpp`8u^(+Txaxw^1bh{yd>mBtyEfxc8 zt|{RN1{U3K6rnJ~%#WyKGgW*WlDWUafMjK#nz^CeWn&qxmG$VM1O=kUDzB3 z`9jTpb!TUYP8J`9@Q!87-hP+4lyh0F-V)8RUbW6%u{o{t8qk0EQs#O4jc(UZdh094^} zG|VuX#TpvxdTv5`b{uQmGw|1xN?EZ;X}1GV>-i+xZrNqtdr_5SQQ4?eYcD6S_bCeZ z4d)iK1u`c;N8D|p)Sfq%beO}PnMI-0quM_+s=%%reGoCj@#&)@vd-l4qQL}RUqZQG z$|5agH0RYz`UY6Gz2Tno(u8VmzY%|!SqBu`1wC=dP^me_ zsan(cIUbMJY?Pt>Z8EZv3!5fKR#GUSd+{O*y0kE8cJn3?zldE2J9{Y82gG*q5>Ogc z=q5D0LeBc3PAyhde%C-O|A^UxGH8dQp`t%$Tj-a-QZ3(%^Y%1xgK;H`Ro?DacrEM* z9?O2-*w=Z;}isd2|(xVD8yis7Osc{w{Jyf#WTP_oA)* zN4k0j`=9}o9uzZDxxQBtOT-Z`X!mh+)I5r&nZj~1;0;OhRPj)a|*B6 z)7y|*TT?v|g*p)mqvP9Q08H1mJ|+V-2gqLu^5Nex7#X2$!?1f2@OXuwGM5`SJ=%Sz zrw-o`&r$Sx9Q0Aa^e{Z`?=b3;oI=OrU4im2VT^;}T9lFr0vpY3KK$MdQ zyPlFagEpN>S}i1`?5p4w-2>9RJL(6i;$ATiL4vCz)>7y2OO4|^Oq0om2-CwAckBq} z>dgX~_ZX!#kw{PT{`SI6;5n(gqxvK7Ug^oNXEJRGFWTu|MQzTuO2V>}zwWnv$Vwiz zFW*Zq9D@t2zsz=z4gZKRy0!_$keM0&UIu~{G|)}cQY{^Os@Lcv2!5sE2ToHm!0Yb_ zsU6ys&xk9;RfPje>3m;M^FLYnLHJ0p;vh$fdLN_~xm1Bna zAc(VkfViIKphc);UD4%(SEATxQ)A)WNk?m_Sm2iV$eR@_t+CX&WCC?q@Hz`K?Xkw; zqDhN497BOfK%;_@U5O-tYO5QAklm%#9r3g|G+t}{i%D$o5v)h(xjhB7w-jcpg(5-% z={`;o5iVU51yPxRb{esF`4L$rIluwhT=$oXKm!popqb7alZK?1)~03 z`@(a*&CbQ-u&Fr)lbgDU!R+wO;!GRE@hu~?3NB>ci!AdsW*jLDmtITZkHJP5sWR#x zf3=~UjnKI0OJ_tDxO}u52wNBkWSy9)&7nX|-Di%Ty4;{vr`;R*1ZUT|iZnjuOenC` z1C`A;&G)@j(Y1>cp?J2*;~0|->R~J+;_LOE z1#b=povA@{==FF?5(i-y!!8*UFL0NzbxkE$)-1>E0qPGWlpfR1VR?G&jD=Jg*sGFS zv97rj-0A0^aW_@v{pR2ap?D=e!G+YmUXQdGG8vg+(MHJjBHsJt zJZDO}f~m9#|KamgYW9!VOZ}RWH__^~@6O26gy=Kmzd8id_t$w&Qh6!K$THg7q%JwZ zSrvx5pOn$C9A1VcdU8iKR%Vb1&t+=6C9=FaHFwi2`E6 zk4F4lv`=|cMd@V;TfBG-cU2mc2-DNraCbdm%Eu=7(~2wpY1I1%b#wYEn2rJW1h$I) zPfx%ZBu!sa-)FsM;2rJM!F7KKu4M%Z!EQ`wo(+{5K-rXN2149Hm;R-?y_fxC(_&(< zhyB^yGGN)}7(o)92{aPdrRt(2ymRBFWkmHdt6XSe=WDTgPm!RfdF?+FU!9-bQ~7Pe zjwJI8A7=a>LgM5}{^GHBS%56PYJLEW2;8(<2tf~!_P*RQvCggl(XNnAt{|p++v$Cy zUwQnrOG_7+_j>%z&F^Ym_o_vE(~oI3Nm}r4V=KCcOg7!|XLr;l0US@%PI|Z2Rzr8f%4SA+BoVI&K?j91sIfWO=-w$+f-JS`dk;0@1Wrhyr` z5letV`G1Q!Uo3M_S~Z~DO!W1=$DF!B`|!2NxoxDX9ZgXlJ~LQsh(noVI-wh+6Ey#! zfga<=%G&pR$pglCol2kN?OMw5rxAfwfz#}xOoOAr{hB^$3>^}i1FIu~0Dak>4rVA&yG4nxAfpo+r*qNU&zwjUs&XF@Fk4d-j7YK_<47rN1Vbl+%Ad;;n6aKhb5fjS! zySe-*ZVKma!K=c%@|&pw`4?bCt(EJ@RArrpp?&p+y=AU#g=xZ7XIA#6wc%5k6HmJX z!f*8L(N>D9wHJ?0VKJo&&4hA3+s!dV1r|Xs&lPKTXn9@NwLqf1QrxQisJ%1f$QmEE zQopQxF`j2sHgj!|i>Ke2BLP{glpSi5&j>oIK5Eokp=1jRStwT8*WK3V$*39DxxJbn z{d&V#BSFwjv8&k5BX?dTMMMo-UJ~Fhm-DW@2>PX>h8AOm*>eN`1n9@>c_q#%y^H5^ zMyO2C-E*8pMBeXG*s!8iAXJdotTn&L=xP~mef1P{#hEY9|o z#48;+4OMBe+9jTSDmllE@z=Jm9eH1FEtH79{Rxjg&gTwjno1@{?Iucw5tNRk#tqfy zC1Svn(otFaPDZ1my0jC=sIu-NqHHrCXwyHkMEw#$RaT9x# zMS)++=$tYi#Oq0^d^A&;-+w5YFUU~(6#t4^E|xJy*xokHL$`ei&4~MQWq0ZFVoI<4 zz8@cl7-~iX2;SyxJemof3IJzizU}d%P15lz^bS5&)U_MHW+WPIq~50KQ6TLyGsa#Y z&SMm_8n??TeT*6C)q_70{C!;N2iYWWFm@p2s!H|vFQ1{n{!Ur4K14+Z;d*DPPWr|m zvyCm+;|8eSxS81H1G(DogB;qwb5JH8cL@szGZ;{7Qv|=MmHCqvVG2W?C`frbrghe4 z8tDbn|I)Z&Q_LVES7V=SV#ZQnTk!JOxtuZ%(u0{(#7^Q9+cfqa&kE9%*AgErb?dH0 z(VuOGq=wBJ2cJ;8D-Qy7*IG6bev*;Tpb=#!Y2pnAx((ygV?+{z?CrSYpFQjfat%KO z)EDo3&JU^SS9eCTIW8Ek7=EKx#>69h4OcFAIGDN z_RmMi691e3NetUU^-x^lT~Jo4|Azji008jM%k$sD1b>9mQ~&oO!v+9A{|f)K5X|s= zW->Siln_41Mu_{bY!e future = asyncHttpClient.executeRequest(r); +// +// org.asynchttpclient.Response resp = future.get(); +// +// System.err.println(responseASYN=============+resp.getResponseBody()); +// +// } catch (ExecutionException e) { +// e.printStackTrace(); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } finally { +// asyncHttpClient.close(); +// } - JSONObject params = new JSONObject(); - params.put("queryPage", page); +// Map map = new HashMap<>(); +// +// map.put(MV.ETERNAL LIGHT, ceshi); +// +// System.err.println(map.get(MV.ETERNAL LIGHT)); - DefaultAsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient(); - try { - String str = "http://192.168.61.133/tos/yard/shutout/list"; + SnowflakeGenerator generator = new SnowflakeGenerator(); - org.asynchttpclient.Request r = new RequestBuilder() - .setUrl(str) - .setBody(JSONObject.toJSONString(params)) - .addHeader("Content-Type", "application/json") - .build(); +// for (int j = 0; j < 5; j++) { +// new Runnable() { +// @Override +// public void run() { +// for (int i = 0; i < 500; i++) { +// System.err.println(generator.next()); +// } +// } +// }.run(); +// } - ListenableFuture future = asyncHttpClient.executeRequest(r); + List vins = new ArrayList<>(5); + System.err.println(vins.size()); - org.asynchttpclient.Response resp = future.get(); + System.err.println(StringUtils.isNotBlank(" ")); - System.err.println("responseASYN============="+resp.getResponseBody()); - - } catch (ExecutionException e) { - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } finally { - asyncHttpClient.close(); - } } } diff --git a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerDeparture.java b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerDeparture.java index 97a5840..37a692a 100644 --- a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerDeparture.java +++ b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerDeparture.java @@ -2,6 +2,7 @@ package com.haitonggauto.rtosc.repository.entity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; import com.haitonggauto.rtosc.common.db.entity.BaseEntity; import com.haitonggauto.rtosc.repository.enums.AuditEnum; import com.nuzar.cloud.annotation.echo.Echo; @@ -131,13 +132,29 @@ public class CustomerDeparture extends BaseEntity implements Serializable { /** * 进港日期 */ + @JsonFormat(pattern = "yyyy-MM-dd") @TableField(value = "arrival_time") @ApiModelProperty(value = "进港日期") private Date arrivalTime; + /** + * 品牌ID + */ + @TableField(value = "brand_id") + @ApiModelProperty(value = "品牌ID") + private String brandId; + + /** + * 品牌 + */ + @TableField(value = "brand") + @ApiModelProperty(value = "品牌") + private String brand; + /** * 提货日期 */ + @JsonFormat(pattern = "yyyy-MM-dd") @TableField(value = "delivery_time") @ApiModelProperty(value = "提货日期") private Date deliveryTime; @@ -145,6 +162,7 @@ public class CustomerDeparture extends BaseEntity implements Serializable { /** * 返回日期 */ + @JsonFormat(pattern = "yyyy-MM-dd") @TableField(value = "return_time") @ApiModelProperty(value = "返回日期") private Date returnTime; @@ -214,10 +232,22 @@ public class CustomerDeparture extends BaseEntity implements Serializable { @ApiModelProperty(value = "备注") private String remark; - @TableField(exist = false) - @ApiModelProperty(value = "数量(计划中,备件数和车辆数之后)") + @TableField(value = "quantity") + @ApiModelProperty(value = "数量(计划中,备件数和车辆数之和)") private Integer quantity; + @TableField(value = "car_quantity") + @ApiModelProperty(value = "车辆数") + private Integer carQuantity; + + @TableField(value = "spare_quantity") + @ApiModelProperty(value = "备件数") + private Integer spareQuantity; + + @TableField(value = "work_status") + @ApiModelProperty(value = "工作过程") + private String workStatus; + /** * 事由 */ diff --git a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerDepartureCargo.java b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerDepartureCargo.java index 6fb6f80..d37d28f 100644 --- a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerDepartureCargo.java +++ b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerDepartureCargo.java @@ -8,6 +8,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.io.Serializable; +import java.math.BigDecimal; /** * 提离港区货物表 @@ -24,13 +25,6 @@ public class CustomerDepartureCargo extends BaseEntity implements Serializable { @ApiModelProperty(hidden = true) private Long departureId; - /** - * 货物类型ID,0代表车辆,1代表备件 - */ - @TableField(value = "cargo_type") - @ApiModelProperty(hidden = true) - private String cargoType; - /** * 提单号 */ @@ -38,20 +32,6 @@ public class CustomerDepartureCargo extends BaseEntity implements Serializable { @ApiModelProperty(value = "提单号") private String billNo; - /** - * 品牌ID - */ - @TableField(value = "brand_id") - @ApiModelProperty(value = "品牌ID") - private String brandId; - - /** - * 品牌 - */ - @TableField(value = "brand") - @ApiModelProperty(value = "品牌") - private String brand; - /** * 车架号/条码 */ @@ -59,12 +39,10 @@ public class CustomerDepartureCargo extends BaseEntity implements Serializable { @TableField(value = "vin") private String vin; - /** - * 数量 - */ - @ApiModelProperty(value = "数量") - @TableField(value = "quantity") - private Integer quantity; + // 是否报关 + @ApiModelProperty(value = "是否报关") + @TableField(value = "is_customs") + private Integer isCustoms; /** * 是否退关 @@ -73,6 +51,11 @@ public class CustomerDepartureCargo extends BaseEntity implements Serializable { @TableField(value = "is_shutout") private Integer isShutout; + // 是否随车备件 + @ApiModelProperty(value = "是否随车备件") + @TableField(value = "is_spare") + private Integer isSpare; + /** * 车辆状态 */ @@ -80,6 +63,57 @@ public class CustomerDepartureCargo extends BaseEntity implements Serializable { @ApiModelProperty(value = "车辆状态") private String vinStatus; + /** + * 车型ID + */ + @TableField(value = "cart_type_id") + @ApiModelProperty(value = "车型ID") + private String cartTypeId; + + /** + * 车型 + */ + @TableField(value = "cart_type") + @ApiModelProperty(value = "车型") + private String cartType; + // 型号 + + @TableField(value = "models") + @ApiModelProperty(value = "型号") + private String models; + /** + * 长 + */ + @TableField(value = "length") + @ApiModelProperty(value = "长") + private BigDecimal length; + + /** + * 宽 + */ + @TableField(value = "width") + @ApiModelProperty(value = "宽") + private BigDecimal width; + + /** + * 高 + */ + @TableField(value = "height") + @ApiModelProperty(value = "高") + private BigDecimal height; + + /** + * 重量(吨) + */ + @TableField(value = "weight") + @ApiModelProperty(value = "重量") + private BigDecimal weight; + + @TableField(exist = false) + @ApiModelProperty(value = "进港时间") + private String carPickTime; + + @TableField(exist = false) @ApiModelProperty(hidden = true) private static final long serialVersionUID = 1L; diff --git a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerExportIn.java b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerExportIn.java index c69c371..5dec2d1 100644 --- a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerExportIn.java +++ b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerExportIn.java @@ -192,6 +192,14 @@ public class CustomerExportIn extends BaseEntity implements Serializable { @ApiModelProperty(value = "运输方式") private String transportWay; + @TableField(value = "pre_arrival_time") + @ApiModelProperty(value = "预进港时间") + private Date preArrivalTime; + + @TableField(value = "plan_arrive_port_time") + @ApiModelProperty(value = "预靠泊时间") + private Date planArrivePortTime; + /** * 进场开始时间 */ @@ -451,6 +459,10 @@ public class CustomerExportIn extends BaseEntity implements Serializable { @ApiModelProperty(value = "是否装船确认") private Integer loadShipFlag = 0; + @TableField(value = "unberth_flag") + @ApiModelProperty(value = "是否离泊确认") + private Integer unberthFlag = 0; + @TableField(exist = false) @ApiModelProperty(value = "进场日期", hidden = true) private Date tmpEnterDate; diff --git a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerExportInCargo.java b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerExportInCargo.java index c0f7662..fc6b5e2 100644 --- a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerExportInCargo.java +++ b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerExportInCargo.java @@ -8,6 +8,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.io.Serializable; +import java.math.BigDecimal; /** * 出口进场货物表 @@ -82,6 +83,14 @@ public class CustomerExportInCargo extends BaseEntity implements Serializable { @ApiModelProperty(value = "航次") private String voyage; + @TableField(exist = false) + @ApiModelProperty(value = "港口ID") + private String portId; + + @TableField(exist = false) + @ApiModelProperty(value = "港口名称") + private String portName; + @TableField(exist = false) @ApiModelProperty(value = "型号") private String models; @@ -112,6 +121,34 @@ public class CustomerExportInCargo extends BaseEntity implements Serializable { @ApiModelProperty(value = "车架号") private String vin; + /** + * 长 + */ + @TableField(exist = false) + @ApiModelProperty(value = "长") + private BigDecimal length; + + /** + * 宽 + */ + @TableField(exist = false) + @ApiModelProperty(value = "宽") + private BigDecimal width; + + /** + * 高 + */ + @TableField(exist = false) + @ApiModelProperty(value = "高") + private BigDecimal height; + + /** + * 重量(吨) + */ + @TableField(exist = false) + @ApiModelProperty(value = "重量") + private BigDecimal weight; + @TableField(exist = false) @ApiModelProperty(value = "进港记录") private CustomerExportIn exportIn; diff --git a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerExportInspect.java b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerExportInspect.java index c749369..477d856 100644 --- a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerExportInspect.java +++ b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerExportInspect.java @@ -3,7 +3,6 @@ package com.haitonggauto.rtosc.repository.entity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import com.haitonggauto.rtosc.common.db.entity.BaseEntity; -import com.haitonggauto.rtosc.common.dto.DictDTO; import com.haitonggauto.rtosc.repository.enums.AuditEnum; import com.haitonggauto.rtosc.repository.enums.InspectStatusEnum; import com.nuzar.cloud.annotation.echo.Echo; diff --git a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerFreeTrade.java b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerFreeTrade.java index 652abec..58c36a8 100644 --- a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerFreeTrade.java +++ b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/entity/CustomerFreeTrade.java @@ -47,6 +47,43 @@ public class CustomerFreeTrade extends BaseEntity implements Serializable { @ApiModelProperty(value = "港区") private String portArea; + /** + * 船名 + */ + @TableField(value = "ship_id") + @ApiModelProperty(value = "船ID") + private String shipId; + + /** + * 中文船名 + */ + @TableField(value = "ship_name") + @ApiModelProperty(value = "中文船名") + @EsLogMean(name = "船名", title = true) + private String shipName; + + /** + * 英文船名 + */ + @TableField(value = "ship_en_name") + @ApiModelProperty(value = "英文船名") + private String shipEnName; + + /** + * 航次ID + */ + @TableField(value = "voyage_id") + @ApiModelProperty(value = "航次ID") + private String voyageId; + + /** + * 航次 + */ + @TableField(value = "voyage") + @ApiModelProperty(value = "航次") + @EsLogMean(name = "航次", title = true) + private String voyage; + /** * 企业编码 */ diff --git a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/mapper/CustomerExportInMapper.java b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/mapper/CustomerExportInMapper.java index a14222e..135f362 100644 --- a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/mapper/CustomerExportInMapper.java +++ b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/mapper/CustomerExportInMapper.java @@ -19,7 +19,7 @@ public interface CustomerExportInMapper extends BaseMapper { * @param voyageId * @return */ - List getListByVoyageId(@Param("voyageId") String voyageId, @Param("status") AuditEnum status); + List getListByVoyageId(@Param("shipId") String shipId, @Param("voyageId") String voyageId, @Param("billNos") List billNos, @Param("status") AuditEnum status); List getExportList(@Param("ids")List ids, @Param("voyageId") String voyageId); } diff --git a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/mapper/CustomerExportLoadMapper.java b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/mapper/CustomerExportLoadMapper.java index f443839..d6d6464 100644 --- a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/mapper/CustomerExportLoadMapper.java +++ b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/mapper/CustomerExportLoadMapper.java @@ -17,7 +17,7 @@ import java.util.List; */ public interface CustomerExportLoadMapper extends BaseMapper { - List getListByVoyageId(@Param("voyageId") String voyageId, @Param("status") AuditEnum status); + List getListByVoyageId(@Param("voyageId") String voyageId, @Param("billNos") List billNos, @Param("status") AuditEnum status); Page getReceiveCarShipList(@Param("page") Page page, @Param("q") String q); } diff --git a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/query/PrintQuery.java b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/query/PrintQuery.java index da86a42..3c47d71 100644 --- a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/query/PrintQuery.java +++ b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/query/PrintQuery.java @@ -10,6 +10,9 @@ import java.util.List; @Data @ApiModel("打印查询") public class PrintQuery implements Serializable { + @ApiModelProperty("船ID") + private String shipId; + @ApiModelProperty("航次ID") private String voyageId; @@ -18,4 +21,7 @@ public class PrintQuery implements Serializable { @ApiModelProperty("货物ID列表") private List id; + + @ApiModelProperty("0代表车辆,1代表备件,空代表所有") + private String flag; } diff --git a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/service/CustomerExportInService.java b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/service/CustomerExportInService.java index 4fe9733..7bed576 100644 --- a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/service/CustomerExportInService.java +++ b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/service/CustomerExportInService.java @@ -18,7 +18,7 @@ public interface CustomerExportInService extends IService { * @param voyageId * @return */ - List getListByVoyageId(String voyageId, AuditEnum status); + List getListByVoyageId(String shipId, String voyageId, List billNos, AuditEnum status); /** * 数据导出 diff --git a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/service/CustomerExportLoadService.java b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/service/CustomerExportLoadService.java index d3ceda7..c9a86e4 100644 --- a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/service/CustomerExportLoadService.java +++ b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/service/CustomerExportLoadService.java @@ -18,7 +18,7 @@ public interface CustomerExportLoadService extends IService * @param voyageId * @return */ - List getListByVoyageId(String voyageId, AuditEnum status); + List getListByVoyageId(String voyageId, List billNos, AuditEnum status); /** * 收车凭证: 进港申请(审核通过)、装船申请(审核通过 diff --git a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/service/impl/CustomerExportInServiceImpl.java b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/service/impl/CustomerExportInServiceImpl.java index 0bde05b..79b4424 100644 --- a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/service/impl/CustomerExportInServiceImpl.java +++ b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/service/impl/CustomerExportInServiceImpl.java @@ -20,8 +20,8 @@ public class CustomerExportInServiceImpl extends ServiceImpl getListByVoyageId(String voyageId, AuditEnum status) { - return getBaseMapper().getListByVoyageId(voyageId, status); + public List getListByVoyageId(String shipId, String voyageId, List billNos, AuditEnum status) { + return getBaseMapper().getListByVoyageId(shipId, voyageId, billNos, status); } @Override diff --git a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/service/impl/CustomerExportLoadServiceImpl.java b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/service/impl/CustomerExportLoadServiceImpl.java index 74fef13..79988fd 100644 --- a/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/service/impl/CustomerExportLoadServiceImpl.java +++ b/nuzar-customer-repository/src/main/java/com/haitonggauto/rtosc/repository/service/impl/CustomerExportLoadServiceImpl.java @@ -20,8 +20,8 @@ public class CustomerExportLoadServiceImpl extends ServiceImpl getListByVoyageId(String voyageId, AuditEnum status) { - return getBaseMapper().getListByVoyageId(voyageId, status); + public List getListByVoyageId(String voyageId, List billNos, AuditEnum status) { + return getBaseMapper().getListByVoyageId(voyageId, billNos, status); } @Override diff --git a/nuzar-customer-repository/src/main/resources/mapper/CustomerDepartureCargoMapper.xml b/nuzar-customer-repository/src/main/resources/mapper/CustomerDepartureCargoMapper.xml index d0c7adc..23454c4 100644 --- a/nuzar-customer-repository/src/main/resources/mapper/CustomerDepartureCargoMapper.xml +++ b/nuzar-customer-repository/src/main/resources/mapper/CustomerDepartureCargoMapper.xml @@ -4,31 +4,31 @@ "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - id,departure_id,bill_no, - brand,cargo_type,vin, - quantity,is_shutout,is_del, - create_by,create_date,update_by, - update_date,version,termcd, - brand_id - + + + + + + + + diff --git a/nuzar-customer-repository/src/main/resources/mapper/CustomerExportInCargoMapper.xml b/nuzar-customer-repository/src/main/resources/mapper/CustomerExportInCargoMapper.xml index 14dd5ee..c75fee7 100644 --- a/nuzar-customer-repository/src/main/resources/mapper/CustomerExportInCargoMapper.xml +++ b/nuzar-customer-repository/src/main/resources/mapper/CustomerExportInCargoMapper.xml @@ -104,6 +104,9 @@ select customer_export_in.*, customer_export_in.id as m_id, customer_export_in_cargo.id as vin_id, export_in_id, - vin,cargo_type, work_status from customer_export_in left join customer_export_in_cargo on customer_export_in.id=customer_export_in_cargo.export_in_id where customer_export_in.is_del = 0 and (customer_export_in_cargo.is_del = 0 and customer_export_in_cargo.vin_status=1 or customer_export_in_cargo.is_del is null) and customer_export_in.voyage_id=#{voyageId} and customer_export_in.check_status=#{status} + vin,cargo_type, work_status from customer_export_in left join customer_export_in_cargo on customer_export_in.id=customer_export_in_cargo.export_in_id where customer_export_in.is_del = 0 and (customer_export_in_cargo.is_del = 0 and customer_export_in_cargo.vin_status=1 or customer_export_in_cargo.is_del is null) + and customer_export_in.ship_id=#{shipId} and customer_export_in.voyage_id=#{voyageId} and customer_export_in.check_status=#{status} + + and customer_export_in.bill_num in + #{billNo} + select customer_export_load.*, customer_export_load.id as m_id, - customer_export_load_cargo.id as vin_id, export_load_id, customer_export_load_cargo.brand as v_brand, customer_export_load_cargo.models as v_models, vin, work_status,cargo_type,customer_export_load_cargo.brand_id as v_brand_id,settle_comp_id,settle_comp_name,contact,contact_phone from customer_export_load left join customer_export_load_cargo on customer_export_load.id=customer_export_load_cargo.export_load_id where customer_export_load.is_del = 0 and (customer_export_load_cargo.is_del = 0 and customer_export_load_cargo.vin_status=1 or customer_export_load_cargo.is_del is null) and customer_export_load.voyage_id=#{voyageId} and check_status=#{status} + customer_export_load_cargo.id as vin_id, export_load_id, customer_export_load_cargo.brand as v_brand, customer_export_load_cargo.models as v_models, vin, work_status,cargo_type,customer_export_load_cargo.brand_id as v_brand_id,settle_comp_id,settle_comp_name,contact,contact_phone from customer_export_load left join customer_export_load_cargo on customer_export_load.id=customer_export_load_cargo.export_load_id where customer_export_load.is_del = 0 + and customer_export_load.voyage_id=#{voyageId} and check_status=#{status} + + and customer_export_load.bill_no in + #{billNo} +