feat(shipment): 集成CRM系统并优化发货单管理功能

- 集成CRM系统实现发货单查询功能,支持按订单号、机台编号、物料编码、客户名称搜索
- 新增CrmAccountDTO、CrmDeliveryDTO、CrmGetTokenResultDTO、CrmResultDTO等数据传输对象
- 实现CRM服务类CRMService,包含获取访问令牌和查询发货单的功能
- 添加@Accessors(chain = true)注解到DeliverAddQO类以支持链式调用
- 实现发货单Excel导出功能,包括按ID列表导出和按搜索条件导出两种方式
- 新增DeliveryExportDTO用于导出数据的Excel映射
- 新增DeliverySearchFromCRMQO用于CRM发货单查询的请求参数
- 实现PDA端卸车功能,包括根据车牌号查询箱子和删除包装箱操作
- 重构BoxSearchQO和BoxVO中的carStatus字段为boxStatus,并更新状态描述
- 修复H5控制器中的迭代器移除操作,使用iterator.remove()替代直接删除
- 新增HtmlToImageUtil工具类用于HTML转图片功能
- 添加MaterialCodeController中的依赖注入和相关业务逻辑
- 实现物料码标签打印功能,包括HTML模板和图片生成
- 更新Repository层接口返回类型,使用IPage替代PageData
This commit is contained in:
曹鹏飞 2026-02-10 21:38:01 +08:00
parent 1d0f4c0328
commit 9c690dc366
34 changed files with 994 additions and 86 deletions

View File

@ -36,9 +36,9 @@ public class BoxSearchQO extends SearchBaseQO{
private String deviceNo;
/**
* 发车状态0未发车1已发
* 状态0未装货1已装货2已装车3已发车4已卸
*/
private Integer carStatus;
private Integer boxStatus;
/**
* 客户名称

View File

@ -2,8 +2,10 @@ package com.nflg.wms.common.pojo.qo;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class DeliverAddQO {
/**

View File

@ -1,6 +1,5 @@
package com.nflg.wms.common.pojo.qo;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@ -20,9 +19,9 @@ public class DeliveryUnloadQO {
*/
private List<Long> boxIdsForAdd;
/**
* 要删除的包装箱id列表
*/
@NotEmpty
private List<Long> boxIdsForDel;
// /**
// * 要删除的包装箱id列表
// */
// @NotEmpty
// private List<Long> boxIdsForDel;
}

View File

@ -30,10 +30,10 @@ public class MaterialCodeSearchQO extends SearchBaseQO {
/**
* 下单开始日期
*/
private LocalDate orderStartDate;
private String orderStartDate;
/**
* 下单结束日期
*/
private LocalDate orderEndDate;
private String orderEndDate;
}

View File

@ -38,9 +38,9 @@ public class BoxVO {
private String driverPhone;
/**
* 发车状态0未发车1已发
* 状态0未装货1已装货2已装车3已发车4已卸
*/
private Integer carStatus;
private Integer boxStatus;
/**
* 装箱人

View File

@ -53,5 +53,10 @@ public class ShipmentPackagingCodeVO {
* 最后更新时间
*/
private LocalDateTime updateTime;
/**
* 二维码
*/
private String qrCode;
}

View File

@ -1,8 +1,11 @@
package com.nflg.wms.repository.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.nflg.wms.common.pojo.vo.ShipmentPackagingCodeVO;
import com.nflg.wms.repository.entity.WmsShipmentDelivery;
import java.util.List;
/**
* <p>
* Mapper 接口
@ -14,4 +17,6 @@ import com.nflg.wms.repository.entity.WmsShipmentDelivery;
public interface WmsShipmentDeliveryMapper extends BaseMapper<WmsShipmentDelivery> {
WmsShipmentDelivery getByPackagingCodeId(Long id);
List<ShipmentPackagingCodeVO> getBoxByPlateNumber(String plateNumber);
}

View File

@ -2,9 +2,10 @@ package com.nflg.wms.repository.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.nflg.wms.common.pojo.vo.ShipmentMaterialCodeQRVO;
import com.nflg.wms.repository.entity.WmsShipmentMaterialCodeItem;
import com.nflg.wms.repository.entity.WmsShipmentMaterialCodeItemQr;
import java.util.List;
/**
* <p>
* Mapper 接口
@ -16,4 +17,8 @@ import com.nflg.wms.repository.entity.WmsShipmentMaterialCodeItemQr;
public interface WmsShipmentMaterialCodeItemQrMapper extends BaseMapper<WmsShipmentMaterialCodeItemQr> {
ShipmentMaterialCodeQRVO getInfoByQRCode(String code);
List<ShipmentMaterialCodeQRVO> getListVOByItemIds(List<Long> ids);
List<ShipmentMaterialCodeQRVO> getListVOByCodeIds(List<Long> ids);
}

View File

@ -1,6 +1,7 @@
package com.nflg.wms.repository.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.qo.BoxSearchQO;
@ -24,11 +25,11 @@ public interface WmsShipmentPackagingCodeMapper extends BaseMapper<WmsShipmentPa
ShipmentPackagingCodeVO getVOByCode(String code,Integer status);
PageData<BoxVO> searchInCar(BoxSearchQO qo, Page<?> objectPage);
IPage<BoxVO> searchInCar(BoxSearchQO qo, Page<?> objectPage);
List<ShipmentPackagingCodeVO> searchForUnload(String code);
List<ShipmentMaterialCodeQRVO> getForInstall(Long id);
PageData<ShipmentMaterialCodeItemVO> getItemsVOById(ShipmentSiteStockItemQO qo, Page<?> objectPage);
IPage<ShipmentMaterialCodeItemVO> getItemsVOById(ShipmentSiteStockItemQO qo, Page<?> objectPage);
}

View File

@ -1,6 +1,7 @@
package com.nflg.wms.repository.service;
import com.nflg.wms.common.pojo.vo.ShipmentMaterialCodeItemVO;
import com.nflg.wms.common.pojo.vo.ShipmentPackagingCodeVO;
import com.nflg.wms.repository.entity.WmsShipmentDelivery;
import com.baomidou.mybatisplus.extension.service.IService;
@ -17,4 +18,6 @@ import java.util.List;
public interface IWmsShipmentDeliveryService extends IService<WmsShipmentDelivery> {
WmsShipmentDelivery getByPackagingCodeId(Long id);
List<ShipmentPackagingCodeVO> getBoxByPlateNumber(String plateNumber);
}

View File

@ -1,9 +1,11 @@
package com.nflg.wms.repository.service;
import com.nflg.wms.common.pojo.vo.ShipmentMaterialCodeQRVO;
import com.nflg.wms.repository.entity.WmsShipmentMaterialCodeItem;
import com.nflg.wms.repository.entity.WmsShipmentMaterialCodeItemQr;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.validation.constraints.NotEmpty;
import java.util.List;
/**
* <p>
@ -16,4 +18,8 @@ import com.baomidou.mybatisplus.extension.service.IService;
public interface IWmsShipmentMaterialCodeItemQrService extends IService<WmsShipmentMaterialCodeItemQr> {
ShipmentMaterialCodeQRVO getInfoByQRCode(String code);
List<ShipmentMaterialCodeQRVO> getListVOByItemIds(List<Long> ids);
List<ShipmentMaterialCodeQRVO> getListVOByCodeIds(List<Long> ids);
}

View File

@ -1,5 +1,6 @@
package com.nflg.wms.repository.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.qo.BoxSearchQO;
import com.nflg.wms.common.pojo.qo.ShipmentSiteStockItemQO;
@ -28,11 +29,11 @@ public interface IWmsShipmentPackagingCodeService extends IService<WmsShipmentPa
ShipmentPackagingCodeVO getVOByCode(String code,Integer status);
PageData<BoxVO> searchInCar(BoxSearchQO qo);
IPage<BoxVO> searchInCar(BoxSearchQO qo);
List<ShipmentPackagingCodeVO> searchForUnload(String code);
List<ShipmentMaterialCodeQRVO> getForInstall(Long id);
PageData<ShipmentMaterialCodeItemVO> getItemsVOById(ShipmentSiteStockItemQO qo);
IPage<ShipmentMaterialCodeItemVO> getItemsVOById(ShipmentSiteStockItemQO qo);
}

View File

@ -1,11 +1,14 @@
package com.nflg.wms.repository.service.impl;
import com.nflg.wms.common.pojo.vo.ShipmentPackagingCodeVO;
import com.nflg.wms.repository.entity.WmsShipmentDelivery;
import com.nflg.wms.repository.mapper.WmsShipmentDeliveryMapper;
import com.nflg.wms.repository.service.IWmsShipmentDeliveryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 服务实现类
@ -21,4 +24,9 @@ public class WmsShipmentDeliveryServiceImpl extends ServiceImpl<WmsShipmentDeliv
public WmsShipmentDelivery getByPackagingCodeId(Long id) {
return baseMapper.getByPackagingCodeId(id);
}
@Override
public List<ShipmentPackagingCodeVO> getBoxByPlateNumber(String plateNumber) {
return baseMapper.getBoxByPlateNumber(plateNumber);
}
}

View File

@ -7,6 +7,8 @@ import com.nflg.wms.repository.service.IWmsShipmentMaterialCodeItemQrService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 服务实现类
@ -22,4 +24,14 @@ public class WmsShipmentMaterialCodeItemQrServiceImpl extends ServiceImpl<WmsShi
public ShipmentMaterialCodeQRVO getInfoByQRCode(String code) {
return baseMapper.getInfoByQRCode(code);
}
@Override
public List<ShipmentMaterialCodeQRVO> getListVOByItemIds(List<Long> ids) {
return baseMapper.getListVOByItemIds(ids);
}
@Override
public List<ShipmentMaterialCodeQRVO> getListVOByCodeIds(List<Long> ids) {
return baseMapper.getListVOByCodeIds(ids);
}
}

View File

@ -41,7 +41,7 @@ public class WmsShipmentPackagingCodeServiceImpl extends ServiceImpl<WmsShipment
}
@Override
public PageData<BoxVO> searchInCar(BoxSearchQO qo) {
public IPage<BoxVO> searchInCar(BoxSearchQO qo) {
return baseMapper.searchInCar(qo,new Page<>(qo.getPage(), qo.getPageSize()));
}
@ -56,7 +56,7 @@ public class WmsShipmentPackagingCodeServiceImpl extends ServiceImpl<WmsShipment
}
@Override
public PageData<ShipmentMaterialCodeItemVO> getItemsVOById(ShipmentSiteStockItemQO qo) {
public IPage<ShipmentMaterialCodeItemVO> getItemsVOById(ShipmentSiteStockItemQO qo) {
return baseMapper.getItemsVOById(qo, new Page<>(qo.getPage(), qo.getPageSize()));
}
}

View File

@ -8,4 +8,13 @@
INNER JOIN wms_shipment_delivery_item di ON d."id"=di.delivery_id
WHERE di.packaging_code_id=#{id}
</select>
<select id="getBoxByPlateNumber" resultType="com.nflg.wms.common.pojo.vo.ShipmentPackagingCodeVO">
SELECT c.*,di."name" AS "type_name"
FROM wms_shipment_packaging_code c
LEFT JOIN dictionary_item di ON c."type"=di."id"
INNER JOIN wms_shipment_delivery_item sdi ON sdi.packaging_code_id=c."id"
INNER JOIN wms_shipment_delivery sd ON sdi.delivery_id=sd."id"
WHERE sd.plate_number=#{plateNumber}
</select>
</mapper>

View File

@ -3,9 +3,32 @@
<mapper namespace="com.nflg.wms.repository.mapper.WmsShipmentMaterialCodeItemQrMapper">
<select id="getInfoByQRCode" resultType="com.nflg.wms.common.pojo.vo.ShipmentMaterialCodeQRVO">
SELECT qr.id,qr.no,it.material_no,it.material_describe,qr.num,it.unit,qr.status
SELECT qr.id,qr.no,it.material_no,it.material_describe,qr.num,it.unit,qr.status,mc.device_no,mc.customer_name
FROM wms_shipment_material_code_item_qr qr
INNER JOIN wms_shipment_material_code_item it ON qr.item_id=it."id"
INNER JOIN wms_shipment_material_code mc ON mc."id"=it.material_code_id
where qr.no=#{code}
</select>
<select id="getListVOByItemIds" resultType="com.nflg.wms.common.pojo.vo.ShipmentMaterialCodeQRVO">
SELECT qr.id,qr.no,it.material_no,it.material_describe,qr.num,it.unit,qr.status,mc.device_no,mc.customer_name
FROM wms_shipment_material_code_item_qr qr
INNER JOIN wms_shipment_material_code_item it ON qr.item_id=it."id"
INNER JOIN wms_shipment_material_code mc ON mc."id"=it.material_code_id
where it.id in
<foreach item="item" collection="ids" separator="," open="(" close=")">
#{item}
</foreach>
</select>
<select id="getListVOByCodeIds" resultType="com.nflg.wms.common.pojo.vo.ShipmentMaterialCodeQRVO">
SELECT qr.id,qr.no,it.material_no,it.material_describe,qr.num,it.unit,qr.status,mc.device_no,mc.customer_name
FROM wms_shipment_material_code_item_qr qr
INNER JOIN wms_shipment_material_code_item it ON qr.item_id=it."id"
INNER JOIN wms_shipment_material_code mc ON mc."id"=it.material_code_id
where mc.id in
<foreach item="item" collection="ids" separator="," open="(" close=")">
#{item}
</foreach>
</select>
</mapper>

View File

@ -4,7 +4,7 @@
<update id="updateStatus">
UPDATE wms_shipment_packaging_code
SET status=CASE WHEN EXISTS(SELECT * FROM wms_shipment_packaging_code_item WHERE packaging_code_id=wms_shipment_packaging_code."id") THEN 1 ELSE 0 END
SET status=CASE WHEN EXISTS(SELECT id FROM wms_shipment_packaging_code_item WHERE packaging_code_id=wms_shipment_packaging_code."id") THEN 1 ELSE 0 END
where id = #{packagingCodeId}
</update>
@ -20,13 +20,13 @@
<select id="searchInCar" resultType="com.nflg.wms.common.pojo.vo.BoxVO">
SELECT pc.id,d."no" AS "delivery_no",pc."name" AS "box_name",d.plate_number,d.driver_name,d.driver_phone
,d.car_status,di.create_by as "pack_user",di.create_time as "pack_time"
,pc.status as "box_status",di.create_by as "pack_user",di.create_time as "pack_time"
FROM wms_shipment_packaging_code pc
INNER JOIN wms_shipment_delivery_item di ON di.packaging_code_id=pc."id"
INNER JOIN wms_shipment_delivery d ON di.delivery_id=d."id"
<where>
<if test="qo.carStatus != null">
AND d.car_status = #{qo.carStatus}
<if test="qo.boxStatus != null">
AND pc.status = #{qo.boxStatus}
</if>
<if test="qo.startDate != null">
AND di.create_time >= #{qo.startDate}
@ -84,6 +84,6 @@
FROM wms_shipment_packaging_code_item pci
INNER JOIN wms_shipment_material_code_item_qr mciq ON pci.material_code_item_qr_id=mciq."id"
INNER JOIN wms_shipment_material_code_item mci ON mciq.item_id=mci."id"
where mciq.status!=5 and pci.packaging_code_id=#{id}
where mciq.status!=5 and pci.packaging_code_id=#{qo.id}
</select>
</mapper>

View File

@ -6,14 +6,21 @@ import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.dto.BomMaterialDTO;
import com.nflg.wms.common.pojo.qo.*;
import com.nflg.wms.common.pojo.vo.ShipmentMaterialCodeItemVO;
import com.nflg.wms.common.pojo.vo.ShipmentPackagingCodeVO;
import com.nflg.wms.common.util.UserUtil;
import com.nflg.wms.common.util.VUtil;
import com.nflg.wms.repository.entity.*;
import com.nflg.wms.repository.service.*;
import com.nflg.wms.shipment.pojo.dto.CrmDeliveryDTO;
import com.nflg.wms.shipment.pojo.dto.DeliveryExportDTO;
import com.nflg.wms.shipment.pojo.qo.DeliverySearchFromCRMQO;
import com.nflg.wms.shipment.service.BasdeSerialNumberControllerService;
import com.nflg.wms.shipment.service.CRMService;
import com.nflg.wms.starter.BaseController;
import com.nflg.wms.starter.service.BomMaterialService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
@ -23,6 +30,8 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.ttzero.excel.entity.ListSheet;
import org.ttzero.excel.entity.TemplateSheet;
import org.ttzero.excel.entity.Workbook;
@ -30,9 +39,11 @@ import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
* 发货单
@ -53,9 +64,35 @@ public class DeliveryController extends BaseController {
@Resource
private IWmsShipmentPackagingCodeService packagingCodeService;
public ApiResult searchFromCRM() {
//TODO:从CRM查询发货单列表
return ApiResult.success();
@Resource
private CRMService crmService;
@Resource
private BomMaterialService bomMaterialService;
/**
* 从CRM查询发货单
*/
@PostMapping("searchFromCRM")
public ApiResult<List<DeliverAddQO>> searchFromCRM(@RequestBody DeliverySearchFromCRMQO qo) {
List<CrmDeliveryDTO> datas = crmService.getDeliverys(qo);
List<BomMaterialDTO> materials = bomMaterialService.getList(datas.stream().map(CrmDeliveryDTO::getProductNumber__c).collect(Collectors.toSet()));
return ApiResult.success(
datas.stream().map(d -> new DeliverAddQO()
.setSoNo(d.getOrderNumber())
.setContractNo(d.getContractCode__c())
.setCustomerName(d.getAccount().getName())
.setDeviceNo(d.getMachineNumber2__c())
.setMaterialNo(d.getProductNumber__c())
.setMaterialDrawingNo(
materials.stream()
.filter(m -> StrUtil.equals(m.getMaterialNo(), d.getProductNumber__c()))
.findFirst()
.map(BomMaterialDTO::getDrawingNo)
.orElse("")
)
).toList()
);
}
/**
@ -120,10 +157,49 @@ public class DeliveryController extends BaseController {
}
/**
* 导出清
* 根据id列表导出发货
*/
@GetMapping("exportTOExcel")
public void exportTOExcel(HttpServletResponse response, @RequestParam Long id) throws IOException {
@PostMapping("exportToExcelById")
public void exportItemToExcel(HttpServletResponse response, @RequestBody @NotEmpty List<Long> ids) throws IOException {
List<WmsShipmentDelivery> deliveries = deliveryService.listByIds(ids);
VUtil.trueThrowBusinessError(CollectionUtil.isEmpty(deliveries)).throwMessage("没有需要导出的数据");
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode("发货单.xlsx", StandardCharsets.UTF_8));
new Workbook()
.addSheet(new ListSheet<>(Convert.toList(DeliveryExportDTO.class, deliveries)))
.writeTo(response.getOutputStream());
}
/**
* 根据查询条件导出发货单
*/
@PostMapping("exportToExcelBySearch")
public void exportToExcelBySearch(HttpServletResponse response, @RequestBody DeliverySearchQO qo) throws IOException {
List<WmsShipmentDelivery> deliveries = deliveryService.lambdaQuery()
.eq(Objects.nonNull(qo.getCarStatus()), WmsShipmentDelivery::getCarStatus, qo.getCarStatus())
.like(StrUtil.isNotBlank(qo.getNo()), WmsShipmentDelivery::getNo, qo.getNo())
.like(StrUtil.isNotBlank(qo.getCustomerName()), WmsShipmentDelivery::getCustomerName, qo.getCustomerName())
.like(StrUtil.isNotBlank(qo.getContractNo()), WmsShipmentDelivery::getContractNo, qo.getContractNo())
.like(StrUtil.isNotBlank(qo.getSoNo()), WmsShipmentDelivery::getSoNo, qo.getSoNo())
.like(StrUtil.isNotBlank(qo.getMaterialDrawingNo()), WmsShipmentDelivery::getMaterialDrawingNo, qo.getMaterialDrawingNo())
.like(StrUtil.isNotBlank(qo.getMaterialNo()), WmsShipmentDelivery::getMaterialNo, qo.getMaterialNo())
.like(StrUtil.isNotBlank(qo.getDeviceNo()), WmsShipmentDelivery::getDeviceNo, qo.getDeviceNo())
.like(StrUtil.isNotBlank(qo.getCustomerName()), WmsShipmentDelivery::getCustomerName, qo.getCustomerName())
.like(StrUtil.isNotBlank(qo.getPlateNumber()), WmsShipmentDelivery::getPlateNumber, qo.getPlateNumber())
.list();
VUtil.trueThrowBusinessError(CollectionUtil.isEmpty(deliveries)).throwMessage("没有需要导出的数据");
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode("发货单.xlsx", StandardCharsets.UTF_8));
new Workbook()
.addSheet(new ListSheet<>(Convert.toList(DeliveryExportDTO.class, deliveries)))
.writeTo(response.getOutputStream());
}
/**
* 根据发货单导出子项
*/
@GetMapping("exportItemToExcel")
public void exportItemToExcel(HttpServletResponse response, @RequestParam Long id) throws IOException {
WmsShipmentDelivery delivery = deliveryService.getById(id);
VUtil.trueThrowBusinessError(Objects.isNull(delivery)).throwMessage("清单不存在");
AtomicInteger index = new AtomicInteger(1);
@ -184,7 +260,7 @@ public class DeliveryController extends BaseController {
.in(WmsShipmentDelivery::getId, deliveries)
.update();
List<Long> boxIds = deliveryItemService.lambdaQuery()
.eq(WmsShipmentDeliveryItem::getDeliveryId, deliveries)
.in(WmsShipmentDeliveryItem::getDeliveryId, deliveries)
.list()
.stream()
.map(WmsShipmentDeliveryItem::getPackagingCodeId)
@ -251,6 +327,45 @@ public class DeliveryController extends BaseController {
return ApiResult.success();
}
/**
* 根据车牌号查询已装车的箱子PDA使用
*/
@GetMapping("getBoxByPlateNumber")
public ApiResult<List<ShipmentPackagingCodeVO>> getBoxByPlateNumber(@RequestParam String plateNumber) {
return ApiResult.success(deliveryService.getBoxByPlateNumber(plateNumber));
}
/**
* 卸车-删除包装箱PDA使用
* @param id 包装箱ID
*/
@Transactional
@PostMapping("unloadDel")
public ApiResult<Void> unloadDel(@RequestBody Long id) {
WmsShipmentDelivery delivery = deliveryService.getByPackagingCodeId(id);
VUtil.trueThrowBusinessError(Objects.isNull(delivery)).throwMessage("发货单不存在");
VUtil.trueThrowBusinessError(delivery.getCarStatus() != 0).throwMessage("发货单已发车");
deliveryItemService.lambdaUpdate()
.in(WmsShipmentDeliveryItem::getPackagingCodeId, id)
.remove();
packagingCodeService.lambdaUpdate()
.set(WmsShipmentPackagingCode::getStatus, 1)
.in(WmsShipmentPackagingCode::getId, id)
.update();
if (!deliveryItemService.lambdaQuery()
.eq(WmsShipmentDeliveryItem::getDeliveryId, delivery.getId())
.exists()){
deliveryService.lambdaUpdate()
.set(WmsShipmentDelivery::getBoxStatus, 0)
.set(WmsShipmentDelivery::getUpdateBy, UserUtil.getUserName())
.set(WmsShipmentDelivery::getUpdateTime, LocalDateTime.now())
.eq(WmsShipmentDelivery::getBoxStatus, 1)
.eq(WmsShipmentDelivery::getId, delivery.getId())
.update();
}
return ApiResult.success();
}
/**
* 卸车PDA使用
*/
@ -290,16 +405,16 @@ public class DeliveryController extends BaseController {
.update();
}
}
if (CollectionUtil.isNotEmpty(qo.getBoxIdsForDel())) {
deliveryItemService.lambdaUpdate()
.eq(WmsShipmentDeliveryItem::getDeliveryId, qo.getId())
.in(WmsShipmentDeliveryItem::getPackagingCodeId, qo.getBoxIdsForDel())
.remove();
packagingCodeService.lambdaUpdate()
.set(WmsShipmentPackagingCode::getStatus, 1)
.in(WmsShipmentPackagingCode::getId, qo.getBoxIdsForDel())
.update();
}
// if (CollectionUtil.isNotEmpty(qo.getBoxIdsForDel())) {
// deliveryItemService.lambdaUpdate()
// .eq(WmsShipmentDeliveryItem::getDeliveryId, qo.getId())
// .in(WmsShipmentDeliveryItem::getPackagingCodeId, qo.getBoxIdsForDel())
// .remove();
// packagingCodeService.lambdaUpdate()
// .set(WmsShipmentPackagingCode::getStatus, 1)
// .in(WmsShipmentPackagingCode::getId, qo.getBoxIdsForDel())
// .update();
// }
return ApiResult.success();
}
}

View File

@ -200,7 +200,7 @@ public class H5Controller extends BaseController {
});
it.setUsedNum(it.getUsedNum().add(qr.getNum()));
qr.setStatus(5);
qrCodes.remove(qrCode);
iterator.remove();
records.add(new WmsShipmentSiteStockMaterialItemRecord()
.setMaterialItemId(item.getId())
.setMaterialNo(item.getMaterialNo())

View File

@ -5,6 +5,8 @@ import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nflg.wms.common.constant.STATE;
import com.nflg.wms.common.exception.NflgException;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.qo.*;
@ -17,7 +19,10 @@ import com.nflg.wms.repository.entity.*;
import com.nflg.wms.repository.service.*;
import com.nflg.wms.shipment.pojo.dto.MaterialCodeForwardImportDTO;
import com.nflg.wms.shipment.service.BasdeSerialNumberControllerService;
import com.nflg.wms.shipment.util.HtmlToImageUtil;
import com.nflg.wms.shipment.util.KeyUtil;
import com.nflg.wms.shipment.util.QRCodeUtil;
import com.nflg.wms.shipment.util.ThymeleafUtil;
import com.nflg.wms.starter.BaseController;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
@ -26,7 +31,9 @@ import jakarta.validation.constraints.NotEmpty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@ -35,6 +42,7 @@ import org.ttzero.excel.entity.TemplateSheet;
import org.ttzero.excel.entity.Workbook;
import org.ttzero.excel.reader.ExcelReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
@ -44,6 +52,8 @@ import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 物料码物料清单
@ -54,23 +64,26 @@ import java.util.stream.Collectors;
public class MaterialCodeController extends BaseController {
@Resource
private IWmsShipmentMaterialCodeService shipmentMaterialCodeService;
private IWmsShipmentMaterialCodeService materialCodeService;
@Resource
private IWmsShipmentMaterialCodeItemService shipmentMaterialCodeItemService;
private IWmsShipmentMaterialCodeItemService materialCodeItemService;
@Resource
private IWmsShipmentMaterialCodeItemQrService shipmentMaterialCodeItemQrService;
private IWmsShipmentMaterialCodeItemQrService materialCodeItemQrService;
@Resource
private IWmsShipmentMaterialCodeForwardService materialCodeForwardService;
@Resource
private IWmsShipmentPackagingCodeService shipmentPackagingCodeService;
private IWmsShipmentPackagingCodeService packagingCodeService;
@Resource
private BasdeSerialNumberControllerService serialNumberControllerService;
@Resource
private IWmsShipmentMaterialService materialService;
/**
* 清单-新增
*/
@ -80,7 +93,7 @@ public class MaterialCodeController extends BaseController {
materialCode.setNo(serialNumberControllerService.generateSerialNumber(27));
materialCode.setCreateBy(UserUtil.getUserName());
materialCode.setCreateTime(LocalDateTime.now());
shipmentMaterialCodeService.save(materialCode);
materialCodeService.save(materialCode);
return ApiResult.success();
}
@ -89,13 +102,13 @@ public class MaterialCodeController extends BaseController {
*/
@PostMapping("update")
public ApiResult<Void> update(@Valid @RequestBody ShipmentMaterialCodeUpdateQO qo) {
WmsShipmentMaterialCode old = shipmentMaterialCodeService.getById(qo.getId());
WmsShipmentMaterialCode old = materialCodeService.getById(qo.getId());
VUtil.trueThrowBusinessError(Objects.isNull(old)).throwMessage("清单不存在");
VUtil.trueThrowBusinessError(old.getStatus() >= 2).throwMessage("清单已完成,不能修改");
WmsShipmentMaterialCode materialCode = Convert.convert(WmsShipmentMaterialCode.class, qo);
materialCode.setUpdateBy(UserUtil.getUserName());
materialCode.setUpdateTime(LocalDateTime.now());
shipmentMaterialCodeService.updateById(materialCode);
materialCodeService.updateById(materialCode);
return ApiResult.success();
}
@ -104,7 +117,7 @@ public class MaterialCodeController extends BaseController {
*/
@PostMapping("delete")
public ApiResult<Void> delete(@RequestBody @NotEmpty List<Long> ids) {
shipmentMaterialCodeService.lambdaUpdate()
materialCodeService.lambdaUpdate()
.eq(WmsShipmentMaterialCode::getStatus, 0)
.in(WmsShipmentMaterialCode::getId, ids)
.remove();
@ -117,7 +130,7 @@ public class MaterialCodeController extends BaseController {
@PostMapping("search")
public ApiResult<PageData<WmsShipmentMaterialCode>> search(@Valid @RequestBody MaterialCodeSearchQO request) {
return ApiResult.success(
shipmentMaterialCodeService.lambdaQuery()
materialCodeService.lambdaQuery()
.ge(Objects.nonNull(request.getOrderStartDate()), WmsShipmentMaterialCode::getOrderDate, request.getOrderStartDate())
.le(Objects.nonNull(request.getOrderEndDate()), WmsShipmentMaterialCode::getOrderDate, request.getOrderEndDate())
.ge(Objects.nonNull(request.getStartDate()), WmsShipmentMaterialCode::getCreateTime, request.getStartDate())
@ -149,9 +162,9 @@ public class MaterialCodeController extends BaseController {
*/
@GetMapping("exportTOExcel")
public void exportTOExcel(HttpServletResponse response, @RequestParam Long id) throws IOException {
WmsShipmentMaterialCode materialCode = shipmentMaterialCodeService.getById(id);
WmsShipmentMaterialCode materialCode = materialCodeService.getById(id);
VUtil.trueThrowBusinessError(Objects.isNull(materialCode)).throwMessage("清单不存在");
List<ShipmentMaterialCodeItemVO> list = shipmentMaterialCodeItemService.getByCodeId(id);
List<ShipmentMaterialCodeItemVO> list = materialCodeItemService.getByCodeId(id);
for (int i = 0; i < list.size(); i++) {
list.get(i).setIndex(i + 1);
}
@ -231,9 +244,9 @@ public class MaterialCodeController extends BaseController {
// .collect(Collectors.toSet());
// VUtil.trueThrowBusinessError(CollectionUtil.isNotEmpty(repeats))
// .throwMessage("以下物料重复:" + StrUtil.join(",", repeats));
shipmentMaterialCodeService.save(materialCode);
shipmentMaterialCodeItemService.saveBatch(items);
shipmentMaterialCodeItemQrService.saveBatch(qrs);
materialCodeService.save(materialCode);
materialCodeItemService.saveBatch(items);
materialCodeItemQrService.saveBatch(qrs);
}
return ApiResult.success();
}
@ -244,7 +257,7 @@ public class MaterialCodeController extends BaseController {
@Transactional
@PostMapping("item/add")
public ApiResult<Void> addItem(@Valid @RequestBody MaterialCodeItemAddQO qo) {
VUtil.trueThrowBusinessError(shipmentMaterialCodeItemService.lambdaQuery()
VUtil.trueThrowBusinessError(materialCodeItemService.lambdaQuery()
.eq(WmsShipmentMaterialCodeItem::getMaterialCodeId, qo.getMaterialCodeId())
.eq(WmsShipmentMaterialCodeItem::getProductionOrderNumber, qo.getProductionOrderNumber())
.eq(WmsShipmentMaterialCodeItem::getMaterialNo, qo.getMaterialNo())
@ -266,7 +279,7 @@ public class MaterialCodeController extends BaseController {
item.setPackingLeft(item.getPackingNum());
int count = decimalValue.compareTo(BigDecimal.ZERO) > 0 ? result.intValue() + 1 : result.intValue();
for (int i = 1; i <= item.getPackingNum(); i++) {
shipmentMaterialCodeItemQrService.save(new WmsShipmentMaterialCodeItemQr()
materialCodeItemQrService.save(new WmsShipmentMaterialCodeItemQr()
.setItemId(item.getId())
.setNo(KeyUtil.next())
.setNum(i == count && decimalValue.compareTo(BigDecimal.ZERO) > 0 ? decimalValue : item.getMinPackagingNum())
@ -274,8 +287,8 @@ public class MaterialCodeController extends BaseController {
.setCreateTime(LocalDateTime.now())
);
}
shipmentMaterialCodeItemService.save(item);
shipmentMaterialCodeService.lambdaUpdate()
materialCodeItemService.save(item);
materialCodeService.lambdaUpdate()
.set(WmsShipmentMaterialCode::getStatus, 1)
.eq(WmsShipmentMaterialCode::getId, qo.getMaterialCodeId())
.eq(WmsShipmentMaterialCode::getStatus, 2)
@ -289,7 +302,7 @@ public class MaterialCodeController extends BaseController {
@Transactional
@PostMapping("item/update")
public ApiResult<Void> updateItem(@Valid @RequestBody MaterialCodeItemUpdateQO qo) {
WmsShipmentMaterialCodeItem item = shipmentMaterialCodeItemService.getById(qo.getId());
WmsShipmentMaterialCodeItem item = materialCodeItemService.getById(qo.getId());
VUtil.trueThrowBusinessError(Objects.isNull(item)).throwMessage("清单明细不存在");
if (Objects.isNull(qo.getMinPackagingNum())) {
qo.setMinPackagingNum(qo.getNum());
@ -303,8 +316,8 @@ public class MaterialCodeController extends BaseController {
item = Convert.convert(WmsShipmentMaterialCodeItem.class, qo);
item.setUpdateBy(UserUtil.getUserName());
item.setUpdateTime(LocalDateTime.now());
shipmentMaterialCodeItemService.updateById(item);
shipmentMaterialCodeItemQrService.lambdaUpdate()
materialCodeItemService.updateById(item);
materialCodeItemQrService.lambdaUpdate()
.eq(WmsShipmentMaterialCodeItemQr::getItemId, item.getId())
.remove();
BigDecimal result = item.getNum().divide(item.getMinPackagingNum(), 3, RoundingMode.HALF_UP);
@ -313,7 +326,7 @@ public class MaterialCodeController extends BaseController {
item.setPackingLeft(item.getPackingNum());
int count = decimalValue.compareTo(BigDecimal.ZERO) > 0 ? result.intValue() + 1 : result.intValue();
for (int i = 1; i <= item.getPackingNum(); i++) {
shipmentMaterialCodeItemQrService.save(new WmsShipmentMaterialCodeItemQr()
materialCodeItemQrService.save(new WmsShipmentMaterialCodeItemQr()
.setItemId(item.getId())
.setNo(KeyUtil.next())
.setNum(i == count && decimalValue.compareTo(BigDecimal.ZERO) > 0 ? decimalValue : item.getMinPackagingNum())
@ -330,7 +343,7 @@ public class MaterialCodeController extends BaseController {
@Transactional
@PostMapping("item/delete")
public ApiResult<Void> deleteItem(@RequestBody @NotEmpty List<Long> ids) {
Set<Long> deleteIds = shipmentMaterialCodeItemService.lambdaQuery()
Set<Long> deleteIds = materialCodeItemService.lambdaQuery()
.select(WmsShipmentMaterialCodeItem::getId)
.eq(WmsShipmentMaterialCodeItem::getStatus, 0)
.in(WmsShipmentMaterialCodeItem::getId, ids)
@ -339,10 +352,10 @@ public class MaterialCodeController extends BaseController {
.map(WmsShipmentMaterialCodeItem::getId)
.collect(Collectors.toSet());
if (CollectionUtil.isNotEmpty(deleteIds)) {
shipmentMaterialCodeItemService.lambdaUpdate()
materialCodeItemService.lambdaUpdate()
.in(WmsShipmentMaterialCodeItem::getId, deleteIds)
.remove();
shipmentMaterialCodeItemQrService.lambdaUpdate()
materialCodeItemQrService.lambdaUpdate()
.in(WmsShipmentMaterialCodeItemQr::getItemId, deleteIds)
.remove();
}
@ -358,9 +371,9 @@ public class MaterialCodeController extends BaseController {
@Transactional
@PostMapping("item/importFromExcel")
public ApiResult<Void> importItemFromExcel(@RequestParam Long materialCodeId, @RequestParam Boolean cover, @RequestParam("file") MultipartFile file) throws IOException {
WmsShipmentMaterialCode materialCode = shipmentMaterialCodeService.getById(materialCodeId);
WmsShipmentMaterialCode materialCode = materialCodeService.getById(materialCodeId);
VUtil.trueThrowBusinessError(Objects.isNull(materialCode)).throwMessage("清单不存在");
List<WmsShipmentMaterialCodeItem> dbItems = shipmentMaterialCodeItemService.lambdaQuery()
List<WmsShipmentMaterialCodeItem> dbItems = materialCodeItemService.lambdaQuery()
.select(WmsShipmentMaterialCodeItem::getId, WmsShipmentMaterialCodeItem::getMaterialNo, WmsShipmentMaterialCodeItem::getStatus)
.eq(WmsShipmentMaterialCodeItem::getMaterialCodeId, materialCodeId)
.list();
@ -423,11 +436,11 @@ public class MaterialCodeController extends BaseController {
item.setUpdateBy(UserUtil.getUserName());
item.setUpdateTime(LocalDateTime.now());
itemsForUpdate.add(item);
List<WmsShipmentMaterialCodeItemQr> iqrs = shipmentMaterialCodeItemQrService.lambdaQuery()
List<WmsShipmentMaterialCodeItemQr> iqrs = materialCodeItemQrService.lambdaQuery()
.eq(WmsShipmentMaterialCodeItemQr::getItemId, item.getId())
.list();
if (iqrs.size() > 1) {
shipmentMaterialCodeItemQrService.lambdaUpdate()
materialCodeItemQrService.lambdaUpdate()
.eq(WmsShipmentMaterialCodeItemQr::getItemId, item.getId())
.remove();
}
@ -456,21 +469,21 @@ public class MaterialCodeController extends BaseController {
VUtil.trueThrowBusinessError(CollectionUtil.isNotEmpty(repeats))
.throwMessage("以下物料重复:" + StrUtil.join(",", repeats));
if (CollectionUtil.isNotEmpty(itemsForAdd)) {
shipmentMaterialCodeItemService.saveBatch(itemsForAdd);
shipmentMaterialCodeService.lambdaUpdate()
materialCodeItemService.saveBatch(itemsForAdd);
materialCodeService.lambdaUpdate()
.set(WmsShipmentMaterialCode::getStatus, 1)
.eq(WmsShipmentMaterialCode::getId, materialCodeId)
.eq(WmsShipmentMaterialCode::getStatus, 2)
.update();
}
if (CollectionUtil.isNotEmpty(itemsForUpdate)) {
shipmentMaterialCodeItemService.updateBatchById(itemsForUpdate);
materialCodeItemService.updateBatchById(itemsForUpdate);
}
if (CollectionUtil.isNotEmpty(qrsForAdd)) {
shipmentMaterialCodeItemQrService.saveBatch(qrsForAdd);
materialCodeItemQrService.saveBatch(qrsForAdd);
}
if (CollectionUtil.isNotEmpty(qrsForUpdate)) {
shipmentMaterialCodeItemQrService.updateBatchById(qrsForUpdate);
materialCodeItemQrService.updateBatchById(qrsForUpdate);
}
}
return ApiResult.success();
@ -481,7 +494,7 @@ public class MaterialCodeController extends BaseController {
*/
@PostMapping("getList")
public ApiResult<PageData<WmsShipmentMaterialCodeItem>> getList(@Valid @RequestBody MaterialCodeItemQO qo) {
return ApiResult.success(shipmentMaterialCodeItemService.lambdaQuery()
return ApiResult.success(materialCodeItemService.lambdaQuery()
.eq(WmsShipmentMaterialCodeItem::getMaterialCodeId, qo.getMaterialCodeId())
.orderByAsc(WmsShipmentMaterialCodeItem::getStatus)
.orderByDesc(WmsShipmentMaterialCodeItem::getId)
@ -495,7 +508,7 @@ public class MaterialCodeController extends BaseController {
*/
@GetMapping("getInfoByQRCode")
public ApiResult<ShipmentMaterialCodeQRVO> getInfoByQRCode(@RequestParam String code) {
ShipmentMaterialCodeQRVO info = shipmentMaterialCodeItemQrService.getInfoByQRCode(code);
ShipmentMaterialCodeQRVO info = materialCodeItemQrService.getInfoByQRCode(code);
VUtil.trueThrowBusinessError(Objects.isNull(info)).throwMessage("二维码无效");
VUtil.trueThrowBusinessError(info.getStatus() != 0).throwMessage("该物料已装箱了");
return ApiResult.success(info);
@ -506,7 +519,7 @@ public class MaterialCodeController extends BaseController {
*/
@GetMapping("exportForward")
public void exportForward(HttpServletResponse response, @RequestParam Long id) throws IOException {
WmsShipmentMaterialCode materialCode = shipmentMaterialCodeService.getById(id);
WmsShipmentMaterialCode materialCode = materialCodeService.getById(id);
VUtil.trueThrowBusinessError(Objects.isNull(materialCode)).throwMessage("清单不存在");
List<WmsShipmentMaterialCodeForward> list = materialCodeForwardService.lambdaQuery()
.eq(WmsShipmentMaterialCodeForward::getMaterialCodeId, id)
@ -518,6 +531,59 @@ public class MaterialCodeController extends BaseController {
.writeTo(response.getOutputStream());
}
/**
* 根据清单导出标签图片ZIP用于直连打印机打印
* @param ids 清单id列表
*/
@PostMapping("exportItemImageZip1")
public ResponseEntity<byte[]> exportItemImageZip1(@RequestBody @NotEmpty List<Long> ids) throws Exception {
List<ShipmentMaterialCodeQRVO> datas = materialCodeItemQrService.getListVOByCodeIds(ids);
VUtil.trueThrowBusinessError(CollectionUtil.isEmpty(datas)).throwMessage("没有需要导出的数据");
return exportItemZip(datas);
}
/**
* 根据清单项导出标签图片ZIP用于直连打印机打印
* @param ids 清单明细id列表
*/
@PostMapping("exportItemImageZip")
public ResponseEntity<byte[]> exportItemImageZip(@RequestBody @NotEmpty List<Long> ids) throws Exception {
List<ShipmentMaterialCodeQRVO> datas = materialCodeItemQrService.getListVOByItemIds(ids);
VUtil.trueThrowBusinessError(CollectionUtil.isEmpty(datas)).throwMessage("没有需要导出的数据");
return exportItemZip(datas);
}
private ResponseEntity<byte[]> exportItemZip(List<ShipmentMaterialCodeQRVO> datas) throws Exception{
Map<String, String> iamges = materialService.lambdaQuery()
.select(WmsShipmentMaterial::getNo, WmsShipmentMaterial::getImage)
.in(WmsShipmentMaterial::getNo, datas.stream().map(ShipmentMaterialCodeQRVO::getMaterialNo).collect(Collectors.toSet()))
.list()
.stream()
.collect(Collectors.toMap(WmsShipmentMaterial::getNo, WmsShipmentMaterial::getImage));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
for (ShipmentMaterialCodeQRVO it : datas) {
Map<String, String> ext = new HashMap<>();
ext.put("qrCode", QRCodeUtil.generateQRCodeBase64(it.getNo(), 200, 200));
ext.put("lst", iamges.get(it.getMaterialNo()));
Map<String, Object> variables = new HashMap<>();
variables.put("ext", ext);
variables.put("info", it);
String html = ThymeleafUtil.generator("/template/label/", "material", ".html", variables);
ZipEntry entry = new ZipEntry(it.getNo() + ".png");
zos.putNextEntry(entry);
byte[] imageBytes = HtmlToImageUtil.convertToPng(html, 1200);
zos.write(imageBytes, 0, imageBytes.length);
zos.closeEntry();
}
}
byte[] zipBytes = baos.toByteArray();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/zip"));
headers.setContentLength(zipBytes.length);
return new ResponseEntity<>(zipBytes, headers, HttpStatus.OK);
}
/**
* 代发物料-导入
* @param id 清单ID
@ -606,7 +672,7 @@ public class MaterialCodeController extends BaseController {
*/
@PostMapping("packForward")
public ApiResult<Void> packForward(@Valid @RequestBody MaterialCodeForwardPackQO qo) {
WmsShipmentPackagingCode info = shipmentPackagingCodeService.getById(qo.getPackagingCodeId());
WmsShipmentPackagingCode info = packagingCodeService.getById(qo.getPackagingCodeId());
VUtil.trueThrowBusinessError(Objects.isNull(info)).throwMessage("包装箱不存在");
VUtil.trueThrowBusinessError(info.getStatus() > 1).throwMessage("包装箱已装车");
materialCodeForwardService.lambdaUpdate()

View File

@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.dto.DeliverNormalOrderItemDTO;
import com.nflg.wms.common.pojo.qo.*;
import com.nflg.wms.common.pojo.vo.ShipmentMaterialCodeQRVO;
import com.nflg.wms.common.pojo.vo.ShipmentPackagingCodeVO;
@ -18,21 +19,28 @@ import com.nflg.wms.repository.entity.WmsShipmentPackagingCode;
import com.nflg.wms.repository.entity.WmsShipmentPackagingCodeItem;
import com.nflg.wms.repository.service.*;
import com.nflg.wms.shipment.service.BasdeSerialNumberControllerService;
import com.nflg.wms.shipment.util.HtmlToImageUtil;
import com.nflg.wms.shipment.util.KeyUtil;
import com.nflg.wms.shipment.util.QRCodeUtil;
import com.nflg.wms.shipment.util.ThymeleafUtil;
import com.nflg.wms.starter.BaseController;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.io.ByteArrayOutputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 包装码
@ -215,6 +223,7 @@ public class PackagingCodeController extends BaseController {
/**
* 拆箱-删除物料PDA使用
*/
@Transactional
@PostMapping("unpackDel")
public ApiResult<Void> unpackDel(@RequestBody Long id) {
WmsShipmentPackagingCodeItem item = packagingCodeItemService.lambdaQuery()
@ -238,6 +247,7 @@ public class PackagingCodeController extends BaseController {
.in(WmsShipmentMaterialCodeItemQr::getId, item.getMaterialCodeItemQrId())
.update();
materialCodeItemService.updatePackingNum(Collections.singleton(qr.getItemId()));
packagingCodeService.updateStatus(item.getPackagingCodeId());
}
}
return ApiResult.success();
@ -313,4 +323,30 @@ public class PackagingCodeController extends BaseController {
packagingCodeService.updateStatus(qo.getPackagingCodeId());
return ApiResult.success();
}
/**
* 导出标签图片ZIP用于直连打印机打印
*/
@PostMapping("exportItemImageZip")
public ResponseEntity<byte[]> exportItemImageZip(@RequestBody @NotEmpty List<ShipmentPackagingCodeVO> list) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
for (ShipmentPackagingCodeVO it : list) {
it.setQrCode(QRCodeUtil.generateQRCodeBase64(it.getNo(), 100, 100));
Map<String, Object> variables = new HashMap<>();
variables.put("info", it);
String html = ThymeleafUtil.generator("/template/label/", "packaging", ".html", variables);
ZipEntry entry = new ZipEntry(it.getNo() + ".png");
zos.putNextEntry(entry);
byte[] imageBytes = HtmlToImageUtil.convertToPng(html, 600);
zos.write(imageBytes, 0, imageBytes.length);
zos.closeEntry();
}
}
byte[] zipBytes = baos.toByteArray();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/zip"));
headers.setContentLength(zipBytes.length);
return new ResponseEntity<>(zipBytes, headers, HttpStatus.OK);
}
}

View File

@ -0,0 +1,11 @@
package com.nflg.wms.shipment.pojo.dto;
import lombok.Data;
@Data
public class CrmAccountDTO {
public String Id;
public String Name;
}

View File

@ -0,0 +1,34 @@
package com.nflg.wms.shipment.pojo.dto;
import lombok.Data;
@Data
public class CrmDeliveryDTO
{
/**
* SAP订单号
*/
public String SAPOrder__c;
public String OrderNumber;
/**
* 物料编码
*/
public String ProductNumber__c;
/**
* 机台编号
*/
public String MachineNumber2__c;
/**
* 合同编号
*/
public String ContractCode__c;
/**
* 客户
*/
public CrmAccountDTO Account;
}

View File

@ -0,0 +1,15 @@
package com.nflg.wms.shipment.pojo.dto;
import lombok.Data;
@Data
public class CrmGetTokenResultDTO {
private String access_token;
private String token_type;
private String signature;
private String instance_url;
}

View File

@ -0,0 +1,15 @@
package com.nflg.wms.shipment.pojo.dto;
import lombok.Data;
@Data
public class CrmResultDTO<T> {
public Boolean success;
public String code;
public String errorMessage;
public T jsonData;
}

View File

@ -0,0 +1,132 @@
package com.nflg.wms.shipment.pojo.dto;
import lombok.Data;
import org.ttzero.excel.annotation.ExcelColumn;
import java.time.LocalDateTime;
@Data
public class DeliveryExportDTO {
/**
* 发货单单号
*/
@ExcelColumn("发货单单号")
private String no;
/**
* 销售订单号
*/
@ExcelColumn("销售订单号")
private String soNo;
/**
* 设备料号
*/
@ExcelColumn("设备料号")
private String materialNo;
/**
* 设备图号
*/
@ExcelColumn("设备图号")
private String materialDrawingNo;
/**
* 机台编号
*/
@ExcelColumn("机台编号")
private String deviceNo;
/**
* 客户名称
*/
@ExcelColumn("客户名称")
private String customerName;
/**
* 车牌号
*/
@ExcelColumn("车牌号")
private String plateNumber;
/**
* 司机姓名
*/
@ExcelColumn("司机姓名")
private String driverName;
/**
* 司机电话
*/
@ExcelColumn("司机电话")
private String driverPhone;
/**
* 合同编号
*/
@ExcelColumn("合同编号")
private String contractNo;
/**
* 装箱状态0未装箱1已装箱
*/
private Integer boxStatus;
@ExcelColumn("装箱状态")
private String boxStatusText;
public String getBoxStatusText() {
if (boxStatus == 0) {
return "未装箱";
} else {
return "已装箱";
}
}
/**
* 发车状态0未发车1已发车
*/
private Integer carStatus;
@ExcelColumn("发车状态")
private String carStatusText;
public String getCarStatusText() {
if (carStatus == 0) {
return "未发车";
} else {
return "已发车";
}
}
/**
* 发车时间
*/
@ExcelColumn(value = "发车时间", format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime carDate;
/**
* 创建人
*/
@ExcelColumn("创建人")
private String createBy;
/**
* 创建时间
*/
@ExcelColumn(value = "创建时间", format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
/**
* 最后更新人
*/
@ExcelColumn("最后更新人")
private String updateBy;
/**
* 最后更新时间
*/
@ExcelColumn(value = "最后更新时间", format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
}

View File

@ -0,0 +1,27 @@
package com.nflg.wms.shipment.pojo.qo;
import lombok.Data;
@Data
public class DeliverySearchFromCRMQO {
/**
* 订单号
*/
public String orderNumber;
/**
* 机台编号
*/
public String machineNumber;
/**
* 物料编码
*/
public String productNumber;
/**
* 客户名称
*/
public String accountName;
}

View File

@ -0,0 +1,93 @@
package com.nflg.wms.shipment.service;
import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.util.StrUtil;
import com.nflg.wms.common.util.VUtil;
import com.nflg.wms.shipment.pojo.dto.CrmDeliveryDTO;
import com.nflg.wms.shipment.pojo.dto.CrmGetTokenResultDTO;
import com.nflg.wms.shipment.pojo.dto.CrmResultDTO;
import com.nflg.wms.shipment.pojo.qo.DeliverySearchFromCRMQO;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
@RefreshScope
public class CRMService {
@Value("${crm.client_id}")
private String clientId;
@Value("${crm.username}")
private String username;
@Value("${crm.password}")
private String password;
@Value("${crm.client_secret}")
private String clientSecret;
@Value("${crm.token.url}")
private String tokenUrl;
@Value("${crm.delivery.url}")
private String DeliveryUrl;
@Resource
private RestTemplate restTemplate;
private static final String TOKEN_KEY = "CRM_TOKEN";
TimedCache<String, String> crmTokenCache = CacheUtil.newTimedCache(50 * 60 * 1000);
private String getToken() {
String token = crmTokenCache.get(TOKEN_KEY);
if (StrUtil.isBlank(token)) {
MultiValueMap<String, String> paramMp = new LinkedMultiValueMap<>();
paramMp.add("grant_type", "password");
paramMp.add("client_id", clientId);
paramMp.add("username", username);
paramMp.add("password", password);
paramMp.add("client_secret", clientSecret);
// HttpHeaders headers = new HttpHeaders();
// headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// HttpEntity<Map<String, String>> request = new HttpEntity<>(paramMp, headers);
CrmGetTokenResultDTO resultDTO = restTemplate.postForObject(tokenUrl, paramMp, CrmGetTokenResultDTO.class);
token = resultDTO.getAccess_token();
crmTokenCache.put(TOKEN_KEY, token);
}
return token;
}
public List<CrmDeliveryDTO> getDeliverys(DeliverySearchFromCRMQO qo) {
Map<String, String> paramMp = new HashMap<>();
paramMp.put("OrderNumber", qo.getOrderNumber());
paramMp.put("MachineNumber2", qo.getMachineNumber());
paramMp.put("ProductNumber", qo.getProductNumber());
paramMp.put("AccountName", qo.getAccountName());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("authorization", "Bearer " + getToken());
HttpEntity<Map<String, String>> request = new HttpEntity<>(paramMp, headers);
ResponseEntity<CrmResultDTO<List<CrmDeliveryDTO>>> response = restTemplate.exchange(
DeliveryUrl,
HttpMethod.POST,
request,
new ParameterizedTypeReference<>() {}
);
VUtil.trueThrowBusinessError(!response.getBody().getSuccess())
.throwMessage("CRM返回错误"+response.getBody().getErrorMessage());
return response.getBody().getJsonData();
}
}

View File

@ -0,0 +1,68 @@
package com.nflg.wms.shipment.util;
import cn.hutool.core.io.FileUtil;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Slf4j
public class HtmlToImageUtil {
/**
* 将HTML内容转换为PNG图片
* @param htmlContent HTML内容
* @param width 图片宽度
* @return PNG图片字节数组
* @throws Exception 转换异常
*/
public static byte[] convertToPng(String htmlContent, int width) throws Exception {
Path inputHtmlPath = null, outputImgPath = null;
try {
Path tempDir = Paths.get(System.getProperty("java.io.tmpdir"), "wkhtml");
if (!Files.exists(tempDir)) {
Files.createDirectories(tempDir);
}
long t = System.currentTimeMillis();
inputHtmlPath = tempDir.resolve("input_" + t + ".html");
outputImgPath = tempDir.resolve("output_" + t + ".png");
Files.write(inputHtmlPath, htmlContent.getBytes());
List<String> command = new ArrayList<>();
command.add("wkhtmltoimage");
// 可选参数设置宽度 (例如 1200px)
command.add("--width");
command.add(String.valueOf(width));
// 可选参数指定图片类型 (例如 PNG)
command.add("--format");
command.add("png");
//质量
command.add("--quality");
command.add("100");
// 输入文件路径
command.add(inputHtmlPath.toAbsolutePath().toString());
// 输出文件路径
command.add(outputImgPath.toAbsolutePath().toString());
ProcessBuilder builder = new ProcessBuilder(command);
Process process = builder.start();
int exitCode = process.waitFor();
if (exitCode != 0) {
// 读取错误流帮助调试
String error = new String(process.getErrorStream().readAllBytes());
throw new IOException("html转换图片失败退出码: " + exitCode + ", 错误信息: " + error);
}
return FileUtil.readBytes(outputImgPath);
} finally {
if (Objects.nonNull(inputHtmlPath)) {
Files.deleteIfExists(inputHtmlPath);
}
if (Objects.nonNull(outputImgPath)) {
Files.deleteIfExists(outputImgPath);
}
}
}
}

View File

@ -0,0 +1,41 @@
package com.nflg.wms.shipment.util;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.io.ByteArrayOutputStream;
import java.util.Base64;
import java.util.Hashtable;
public class QRCodeUtil {
public static byte[] generateQRCode(String text, int width, int height) throws Exception {
// 配置二维码参数
Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
hints.put(EncodeHintType.MARGIN, 0);
// 生成二维码矩阵
BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);
// 将二维码矩阵转换为字节数组
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
MatrixToImageWriter.writeToStream(bitMatrix, "PNG", byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
}
public static String generateQRCodeBase64(String text, int width, int height) {
try {
return "data:image/png;base64," + Base64.getEncoder().encodeToString(generateQRCode(text, width, height));
} catch (Exception ignored) {
return null;
}
}
}

View File

@ -0,0 +1,22 @@
package com.nflg.wms.shipment.util;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import java.util.Map;
public class ThymeleafUtil {
public static String generator(String prefix,String template,String suffix, Map<String, Object> variables){
ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
resolver.setPrefix(prefix);
resolver.setSuffix(suffix);
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(resolver);
engine.setEnableSpringELCompiler(true);
Context context = new Context();
context.setVariables(variables);
return engine.process(template, context);
}
}

View File

@ -0,0 +1,91 @@
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>包装码</title>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<style>
@page {
size: 1200px 800px;
margin: 0;
}
body {
width: 1200px;
height: 800px;
font-size: 20pt;
font-family: SimSun, Arial, sans-serif;
margin: 0;
padding: 0;
}
table {
width: 1200px;
height: 800px;
border: 3px solid #000;
border-collapse: collapse;
table-layout: fixed;
}
th, td {
border: 3px solid #000;
padding: 10px;
text-align: center;
vertical-align: middle;
word-wrap: break-word;
overflow-wrap: break-word;
}
.qrcode {
width: 380px;
height: 380px;
margin: 10px;
}
.lst{
width: 800px;
height: auto;
}
</style>
</head>
<body>
<table>
<tr>
<td style="text-align: center; width: 400px" rowspan="3">
<img alt="" class="qrcode" th:src="${ext.qrCode}"/>
<div style="font-size: 16pt" th:text="${info.no}">0PC7B724KV6FM</div>
</td>
<td style="width: 110px;">
机台编号
</td>
<td style="width: 180px;" th:text="${info.no}">
26LBZ4000L001
</td>
<td style="width: 110px;">
客户名称
</td>
<td style="width: 400px;text-align: left" th:text="${info.customerName}">
北京市京联鑫路用材料有限公司
</td>
</tr>
<tr>
<td>
物料编码
</td>
<td th:text="${info.materialNo}">
3100006701
</td>
<td>
数量
</td>
<td th:text="${info.actualNum}">
10
</td>
</tr>
<tr>
<td colspan="4">
<img alt="" src="https://img-s.msn.cn/tenant/amp/entityid/AA1VWN3Q.img?w=768&h=333&m=6" class="lst" th:src="${ext.lst}"/>
</td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1,63 @@
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>包装码</title>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<style>
@page {
size: 600px 400px;
margin: 0;
}
body {
width: 600px;
height: 400px;
font-size: 20pt;
font-family: SimSun, Arial, sans-serif;
margin: 0;
padding: 0;
}
table {
width: 600px;
height: 400px;
border: 3px solid #000;
border-collapse: collapse;
}
th, td {
border: 3px solid #000;
}
.div-with-border {
border-bottom: 3px solid #000;
padding: 18px;
text-align: left;
width: 320px;
display: block;
vertical-align: middle
}
.qrcode {
width: 260px;
height: 260px;
margin: 10px;
}
</style>
</head>
<body>
<table>
<tr>
<td style="text-align: center;">
<img alt="" class="qrcode" th:src="${info.qrCode}"/>
<div style="font-size: 16pt" th:text="${info.no}">NFLG-QZ-002</div>
</td>
<td style="text-align: left;vertical-align: top">
<div class="div-with-border">包装名称: <span th:text="${info.name}">NFLG-QZ-002 测试包装名称</span></div>
<div class="div-with-border">包装类型: <span th:text="${info.typeName}">托盘</span></div>
</td>
</tr>
</table>
</body>
</html>