feat:打印机器修改
This commit is contained in:
1 parent
9147aafec8
commit
991685ca48
28 files changed
+333
-193
No files matched your search
+3
-3
@@ -7,7 +7,7 @@ import lombok.Getter;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 打印任务失败阶段,帮助管理端区分配置问题、服务端故障和终端故障。
|
||||
* 打印任务失败阶段,帮助管理端区分配置问题、服务端故障和业务终端代理打印故障。
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@@ -19,10 +19,10 @@ public enum HardPrintFailureStageEnum {
|
||||
/** 服务端读取业务数据、绘制 PNG 或上传文件失败。 */
|
||||
IMAGE_GENERATION("IMAGE_GENERATION", "图片生成"),
|
||||
|
||||
/** 服务端向目标打印终端发布 MQTT 消息失败。 */
|
||||
/** 服务端向绑定的来源业务终端发布 MQTT 消息失败。 */
|
||||
MQTT_DISPATCH("MQTT_DISPATCH", "MQTT下发"),
|
||||
|
||||
/** 打印终端下载图片、连接 USB 或写入 ESC/POS 数据失败。 */
|
||||
/** 来源业务终端下载图片、连接 USB 或写入 ESC/POS 数据失败。 */
|
||||
TERMINAL_PRINT("TERMINAL_PRINT", "终端打印");
|
||||
|
||||
/** 持久化阶段编码。 */
|
||||
|
||||
+2
-2
@@ -20,10 +20,10 @@ public enum HardPrintStatusEnum {
|
||||
/** 图片已生成并允许下发,历史枚举名保留为 GENERATE 以保持二进制兼容。 */
|
||||
GENERATE("1", "待打印"),
|
||||
|
||||
/** 打印终端已确认完整 USB 数据和切纸命令写入成功。 */
|
||||
/** 来源业务终端已确认完整 USB 数据和切纸命令写入成功。 */
|
||||
PRINT("2", "已打印"),
|
||||
|
||||
/** 绑定、图片生成、MQTT 下发或终端打印阶段失败,可重试原任务。 */
|
||||
/** 绑定、图片生成、MQTT 下发或业务终端代理打印阶段失败,可重试原任务。 */
|
||||
FAILED("3", "打印失败"),
|
||||
|
||||
/** 核销回退等业务动作取消了尚未打印的任务。 */
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ public enum HardTypeEnum {
|
||||
YUN_XFJ("9", "云版消费机"),
|
||||
YYX_4G("10", "4G-云音响"),
|
||||
YYX_WIFI("11", "wifi-云音响"),
|
||||
/** 运行打印专用终端模式、通过 USB 驱动尔印 ESC/POS 打印机的设备。 */
|
||||
/** 由绑定的超市或食堂 Android 终端代理驱动的无屏尔印 USB 打印机。 */
|
||||
EY_PRINT("12", "尔印打印机器"),
|
||||
;
|
||||
private final String type;
|
||||
@@ -48,7 +48,7 @@ public enum HardTypeEnum {
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断指定设备类型是否为独立打印终端。
|
||||
* 判断指定设备类型是否为尔印逻辑打印机资产。
|
||||
*
|
||||
* @param hardTypeEnum 待判断的设备类型
|
||||
* @return 类型为 {@link #EY_PRINT} 时返回 {@code true}
|
||||
|
||||
+4
-4
@@ -6,10 +6,10 @@ import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* EY_PRINT 终端提交的打印结果回执。
|
||||
* 食堂或超市终端代理无屏 EY_PRINT 提交的打印结果回执。
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "打印终端结果回执")
|
||||
@Schema(description = "业务终端代理打印结果回执")
|
||||
public class HardPrintResultDto {
|
||||
|
||||
/** hard_invoice 打印任务主键。 */
|
||||
@@ -22,7 +22,7 @@ public class HardPrintResultDto {
|
||||
@Schema(description = "订单ID")
|
||||
private Long orderId;
|
||||
|
||||
/** 终端实际处理的重试版本。 */
|
||||
/** 来源业务终端实际处理的重试版本。 */
|
||||
@NotNull(message = "重试版本不能为空")
|
||||
@Min(value = 0, message = "重试版本不能小于0")
|
||||
@Schema(description = "重试版本")
|
||||
@@ -33,7 +33,7 @@ public class HardPrintResultDto {
|
||||
@Schema(description = "是否成功")
|
||||
private Boolean success;
|
||||
|
||||
/** 本版本在终端执行的 USB 尝试次数。 */
|
||||
/** 本版本在来源业务终端执行的 USB 尝试次数。 */
|
||||
@NotNull(message = "尝试次数不能为空")
|
||||
@Min(value = 1, message = "尝试次数不能小于1")
|
||||
@Schema(description = "终端尝试次数")
|
||||
|
||||
+5
-5
@@ -5,10 +5,10 @@ import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 创建业务终端与尔印打印终端绑定关系的请求。
|
||||
* 创建业务终端与无屏尔印 USB 打印机绑定关系的请求。
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "打印终端绑定请求")
|
||||
@Schema(description = "USB 打印机绑定请求")
|
||||
public class HardPrinterBindingDto {
|
||||
|
||||
/** SUPERMARKET 或 CANTEEN 来源终端 ID。 */
|
||||
@@ -16,8 +16,8 @@ public class HardPrinterBindingDto {
|
||||
@Schema(description = "来源业务终端ID")
|
||||
private Long sourceHardId;
|
||||
|
||||
/** EY_PRINT 目标终端 ID。 */
|
||||
@NotNull(message = "打印终端不能为空")
|
||||
@Schema(description = "目标打印终端ID")
|
||||
/** EY_PRINT 逻辑打印机资产 ID。 */
|
||||
@NotNull(message = "打印机不能为空")
|
||||
@Schema(description = "逻辑打印机资产ID")
|
||||
private Long printerHardId;
|
||||
}
|
||||
+5
-5
@@ -6,15 +6,15 @@ import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 保存尔印打印终端 USB 与 ESC/POS 参数的请求。
|
||||
* 保存无屏尔印 USB 打印机参数的请求。
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "打印终端配置请求")
|
||||
@Schema(description = "USB 打印机配置请求")
|
||||
public class HardPrinterConfigDto {
|
||||
|
||||
/** EY_PRINT 设备 ID。 */
|
||||
@NotNull(message = "打印终端不能为空")
|
||||
@Schema(description = "打印终端ID")
|
||||
/** EY_PRINT 逻辑打印机资产 ID。 */
|
||||
@NotNull(message = "打印机不能为空")
|
||||
@Schema(description = "逻辑打印机资产ID")
|
||||
private Long printerHardId;
|
||||
|
||||
/** 真机型号;未联调前允许为空。 */
|
||||
|
||||
+2
-2
@@ -9,10 +9,10 @@ import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 尔印打印终端上报实际 USB 打印机信息的请求。
|
||||
* 食堂或超市终端代理上报实际 USB 打印机信息的请求。
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "打印终端实际 USB 打印机信息")
|
||||
@Schema(description = "业务终端代理上报的 USB 打印机信息")
|
||||
public class HardPrinterInfoReportDto {
|
||||
|
||||
/** USB 描述符中的厂商和产品名称组合,最长保存 128 个字符。 */
|
||||
|
||||
+5
-5
@@ -44,9 +44,9 @@ public class HardInvoiceEntity extends Model<HardInvoiceEntity> {
|
||||
private Long hardId;
|
||||
|
||||
/**
|
||||
* 实际接收任务的尔印打印终端 ID;历史记录和绑定失败任务允许为空。
|
||||
* 任务路由关联的尔印逻辑打印机资产 ID;历史记录和绑定失败任务允许为空。
|
||||
*/
|
||||
@Schema(description="目标打印终端ID")
|
||||
@Schema(description="逻辑打印机资产ID")
|
||||
private Long printerHardId;
|
||||
|
||||
/**
|
||||
@@ -74,13 +74,13 @@ public class HardInvoiceEntity extends Model<HardInvoiceEntity> {
|
||||
private Integer printNo;
|
||||
|
||||
/**
|
||||
* 人工重试版本;终端用任务 ID 和该版本共同判断是否允许再次打印。
|
||||
* 人工重试版本;来源业务终端用任务 ID 和该版本共同判断是否允许再次打印。
|
||||
*/
|
||||
@Schema(description="重试版本")
|
||||
private Integer retryVersion;
|
||||
|
||||
/**
|
||||
* 打印终端上报的 USB 累计尝试次数。
|
||||
* 来源业务终端代理上报的 USB 累计尝试次数。
|
||||
*/
|
||||
@Schema(description="终端尝试次数")
|
||||
private Integer attemptCount;
|
||||
@@ -98,7 +98,7 @@ public class HardInvoiceEntity extends Model<HardInvoiceEntity> {
|
||||
private String lastError;
|
||||
|
||||
/**
|
||||
* 打印终端确认完整 USB 数据和切纸命令写入成功的时间。
|
||||
* 来源业务终端确认完整 USB 数据和切纸命令写入成功的时间。
|
||||
*/
|
||||
@Schema(description="打印成功时间")
|
||||
private LocalDateTime printedAt;
|
||||
|
||||
+4
-4
@@ -17,7 +17,7 @@ import lombok.NoArgsConstructor;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 业务终端与尔印打印终端的一对一绑定关系。
|
||||
* 业务 Android 终端与无屏尔印 USB 打印机资产的一对一绑定关系。
|
||||
*
|
||||
* <p>记录使用物理删除,数据库分别对来源和目标设备设置唯一键,确保任何时刻都不能出现多重绑定。</p>
|
||||
*/
|
||||
@@ -28,7 +28,7 @@ import java.time.LocalDateTime;
|
||||
@TenantTable
|
||||
@TableName("hard_printer_binding")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "业务终端与打印终端绑定关系")
|
||||
@Schema(description = "业务终端与 USB 打印机绑定关系")
|
||||
public class HardPrinterBindingEntity extends Model<HardPrinterBindingEntity> {
|
||||
|
||||
/** 绑定关系主键。 */
|
||||
@@ -40,8 +40,8 @@ public class HardPrinterBindingEntity extends Model<HardPrinterBindingEntity> {
|
||||
@Schema(description = "来源业务终端ID")
|
||||
private Long sourceHardId;
|
||||
|
||||
/** 目标打印终端 ID,只允许 EY_PRINT。 */
|
||||
@Schema(description = "目标打印终端ID")
|
||||
/** 逻辑打印机资产 ID,只允许 EY_PRINT;设备本身不登录、不上报心跳。 */
|
||||
@Schema(description = "逻辑打印机资产ID")
|
||||
private Long printerHardId;
|
||||
|
||||
/** 双方共同所属商户 ID 快照。 */
|
||||
|
||||
+4
-4
@@ -17,7 +17,7 @@ import lombok.NoArgsConstructor;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 尔印打印终端的 USB 和 ESC/POS 参数配置。
|
||||
* 无屏尔印 USB 打印机资产的 USB 和 ESC/POS 参数配置。
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@@ -26,7 +26,7 @@ import java.time.LocalDateTime;
|
||||
@TenantTable
|
||||
@TableName("hard_printer_config")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "尔印打印终端配置")
|
||||
@Schema(description = "尔印 USB 打印机配置")
|
||||
public class HardPrinterConfigEntity extends Model<HardPrinterConfigEntity> {
|
||||
|
||||
/** 配置主键。 */
|
||||
@@ -34,8 +34,8 @@ public class HardPrinterConfigEntity extends Model<HardPrinterConfigEntity> {
|
||||
@Schema(description = "配置主键")
|
||||
private Long id;
|
||||
|
||||
/** 配置所属 EY_PRINT 设备 ID。 */
|
||||
@Schema(description = "打印终端ID")
|
||||
/** 配置所属 EY_PRINT 逻辑打印机资产 ID。 */
|
||||
@Schema(description = "逻辑打印机资产ID")
|
||||
private Long printerHardId;
|
||||
|
||||
/** 真机联调后填写的打印机型号。 */
|
||||
|
||||
+1
-1
@@ -67,7 +67,7 @@ public class HardInvoiceVo extends HardInvoiceEntity implements BaseUserDeptInte
|
||||
|
||||
private String hardType;
|
||||
|
||||
/** 目标尔印打印终端名称。 */
|
||||
/** 任务绑定的尔印 USB 打印机资产名称。 */
|
||||
private String printerHardName;
|
||||
|
||||
/**
|
||||
|
||||
+6
-6
@@ -7,11 +7,11 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 打印终端绑定关系及两端设备展示信息。
|
||||
* 业务终端与无屏 USB 打印机绑定关系及展示信息。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "打印终端绑定详情")
|
||||
@Schema(description = "USB 打印机绑定详情")
|
||||
public class HardPrinterBindingVo extends HardPrinterBindingEntity {
|
||||
|
||||
/** 来源业务终端名称。 */
|
||||
@@ -22,11 +22,11 @@ public class HardPrinterBindingVo extends HardPrinterBindingEntity {
|
||||
@Schema(description = "来源业务终端类型")
|
||||
private String sourceHardType;
|
||||
|
||||
/** 目标打印终端名称。 */
|
||||
@Schema(description = "目标打印终端名称")
|
||||
/** 逻辑打印机资产名称。 */
|
||||
@Schema(description = "逻辑打印机资产名称")
|
||||
private String printerHardName;
|
||||
|
||||
/** 目标打印终端当前配置;尚未保存时返回默认配置。 */
|
||||
@Schema(description = "打印终端配置")
|
||||
/** 目标 USB 打印机当前配置;尚未保存时返回默认配置。 */
|
||||
@Schema(description = "USB 打印机配置")
|
||||
private HardPrinterConfigEntity printerConfig;
|
||||
}
|
||||
+3
-3
@@ -59,16 +59,16 @@ public class HardManagerVo extends HardManagerEntity implements BaseDeptInterfac
|
||||
*/
|
||||
private String disconnectReason;
|
||||
|
||||
/** 当前来源业务终端所绑定的 EY_PRINT 设备 ID;未绑定或当前行为打印机时为空。 */
|
||||
/** 当前来源业务终端所绑定的 EY_PRINT 打印机资产 ID;未绑定或当前行为打印机时为空。 */
|
||||
private Long boundPrinterHardId;
|
||||
|
||||
/** 当前来源业务终端所绑定的 EY_PRINT 设备名称。 */
|
||||
private String boundPrinterHardName;
|
||||
|
||||
/** 当前 EY_PRINT 反向绑定的来源业务终端 ID;未绑定或当前行为来源设备时为空。 */
|
||||
/** 当前 EY_PRINT 打印机资产反向绑定的来源业务终端 ID;未绑定或当前行为来源设备时为空。 */
|
||||
private Long boundSourceHardId;
|
||||
|
||||
/** 当前 EY_PRINT 反向绑定的来源业务终端名称。 */
|
||||
/** 当前 EY_PRINT 打印机资产反向绑定的来源业务终端名称。 */
|
||||
private String boundSourceHardName;
|
||||
|
||||
/** EY_PRINT 型号;未维护配置或非打印设备时为空。 */
|
||||
|
||||
+16
-16
@@ -23,16 +23,16 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 尔印打印终端绑定和配置管理接口。
|
||||
* 业务终端与无屏尔印 USB 打印机的绑定和配置管理接口。
|
||||
*/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/hard-printer")
|
||||
@Tag(description = "hard-printer", name = "尔印打印终端管理")
|
||||
@Tag(description = "hard-printer", name = "尔印 USB 打印机管理")
|
||||
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
|
||||
public class HardPrinterController {
|
||||
|
||||
/** 打印终端绑定和配置服务。 */
|
||||
/** USB 打印机绑定和配置服务。 */
|
||||
private final HardPrinterService hardPrinterService;
|
||||
|
||||
/**
|
||||
@@ -49,13 +49,13 @@ public class HardPrinterController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询来源设备可绑定的 EY_PRINT 终端。
|
||||
* 查询来源设备可绑定的 EY_PRINT 打印机资产。
|
||||
*
|
||||
* @param sourceHardId 来源业务终端 ID
|
||||
* @return 可绑定设备列表
|
||||
*/
|
||||
@GetMapping("/available")
|
||||
@Operation(summary = "查询可绑定打印终端")
|
||||
@Operation(summary = "查询可绑定打印机")
|
||||
@PreAuthorize("@pms.hasPermission('hard_hardManager_printer_bind')")
|
||||
public R<?> listAvailable(@RequestParam Long sourceHardId) {
|
||||
return R.ok(hardPrinterService.listAvailablePrinters(sourceHardId));
|
||||
@@ -75,14 +75,14 @@ public class HardPrinterController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建来源与打印终端的一对一绑定。
|
||||
* 创建来源业务终端与 USB 打印机的一对一绑定。
|
||||
*
|
||||
* @param dto 绑定请求
|
||||
* @return 绑定详情
|
||||
*/
|
||||
@PostMapping("/binding")
|
||||
@Operation(summary = "绑定打印终端")
|
||||
@SysLog("绑定打印终端")
|
||||
@Operation(summary = "绑定 USB 打印机")
|
||||
@SysLog("绑定 USB 打印机")
|
||||
@PreAuthorize("@pms.hasPermission('hard_hardManager_printer_bind')")
|
||||
public R<?> bind(@Valid @RequestBody HardPrinterBindingDto dto) {
|
||||
return R.ok(hardPrinterService.bind(dto));
|
||||
@@ -95,8 +95,8 @@ public class HardPrinterController {
|
||||
* @return 空成功响应
|
||||
*/
|
||||
@DeleteMapping("/binding/{sourceHardId}")
|
||||
@Operation(summary = "解绑打印终端")
|
||||
@SysLog("解绑打印终端")
|
||||
@Operation(summary = "解绑 USB 打印机")
|
||||
@SysLog("解绑 USB 打印机")
|
||||
@PreAuthorize("@pms.hasPermission('hard_hardManager_printer_bind')")
|
||||
public R<Void> unbind(@PathVariable Long sourceHardId) {
|
||||
hardPrinterService.unbind(sourceHardId);
|
||||
@@ -104,27 +104,27 @@ public class HardPrinterController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询打印终端当前参数。
|
||||
* 查询 USB 打印机当前参数。
|
||||
*
|
||||
* @param printerHardId EY_PRINT 设备 ID
|
||||
* @param printerHardId EY_PRINT 逻辑打印机资产 ID
|
||||
* @return 当前或默认配置
|
||||
*/
|
||||
@GetMapping("/config/{printerHardId}")
|
||||
@Operation(summary = "查询打印终端配置")
|
||||
@Operation(summary = "查询 USB 打印机配置")
|
||||
@PreAuthorize("@pms.hasPermission('hard_hardManager_view')")
|
||||
public R<?> getConfig(@PathVariable Long printerHardId) {
|
||||
return R.ok(hardPrinterService.getConfig(printerHardId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存打印终端参数。
|
||||
* 保存 USB 打印机参数。
|
||||
*
|
||||
* @param dto 配置请求
|
||||
* @return 保存后的配置
|
||||
*/
|
||||
@PutMapping("/config")
|
||||
@Operation(summary = "保存打印终端配置")
|
||||
@SysLog("保存打印终端配置")
|
||||
@Operation(summary = "保存 USB 打印机配置")
|
||||
@SysLog("保存 USB 打印机配置")
|
||||
@PreAuthorize("@pms.hasPermission('hard_hardManager_printer_bind')")
|
||||
public R<?> saveConfig(@Valid @RequestBody HardPrinterConfigDto dto) {
|
||||
return R.ok(hardPrinterService.saveConfig(dto));
|
||||
|
||||
+14
-14
@@ -331,52 +331,52 @@ public class HardApiController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前 EY_PRINT 终端绑定关系和打印机参数,用于登录后进入打印专用模式。
|
||||
* 查询当前食堂或超市终端所绑定的无屏 USB 打印机及打印参数。
|
||||
*
|
||||
* @param hardId DEVICE-ID 请求头中的打印终端 ID
|
||||
* @return 绑定来源和打印机配置
|
||||
* @param hardId DEVICE-ID 请求头中的来源业务终端 ID
|
||||
* @return 当前绑定和打印机配置;尚未绑定时数据为空
|
||||
*/
|
||||
@GetMapping("/printer/bootstrap")
|
||||
@Operation(summary = "获取打印终端启动配置")
|
||||
@Operation(summary = "获取业务终端打印机绑定")
|
||||
public R<?> printerBootstrap(@RequestHeader("DEVICE-ID") Long hardId) {
|
||||
return R.ok(hardPrinterService.getPrinterBinding(hardId));
|
||||
return R.ok(hardPrinterService.getSourceBinding(hardId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存当前 EY_PRINT 实际连接打印机的型号、VID 和 PID,目标设备只能由请求头确定。
|
||||
* 由当前食堂或超市终端上报其实际连接打印机的型号、VID 和 PID。
|
||||
*
|
||||
* @param hardId DEVICE-ID 请求头中的打印终端 ID
|
||||
* @param hardId DEVICE-ID 请求头中的来源业务终端 ID
|
||||
* @param dto Android USB Host 枚举出的打印机信息
|
||||
* @return 保留纸宽、切刀和图片模式后的完整打印机配置
|
||||
*/
|
||||
@PostMapping("/printer/info")
|
||||
@Operation(summary = "上报打印终端实际打印机信息")
|
||||
@Operation(summary = "业务终端上报 USB 打印机信息")
|
||||
public R<?> reportPrinterInfo(@RequestHeader("DEVICE-ID") Long hardId,
|
||||
@Valid @RequestBody HardPrinterInfoReportDto dto) {
|
||||
return R.ok(hardPrinterService.reportDeviceInfo(hardId, dto));
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉取当前 EY_PRINT 尚未完成的任务,补偿离线期间遗漏的 MQTT 消息。
|
||||
* 拉取当前食堂或超市终端所绑定打印机尚未完成的任务,补偿离线期间遗漏的 MQTT 消息。
|
||||
*
|
||||
* @param hardId DEVICE-ID 请求头中的打印终端 ID
|
||||
* @param hardId DEVICE-ID 请求头中的来源业务终端 ID
|
||||
* @return 待打印任务列表
|
||||
*/
|
||||
@GetMapping("/printer/tasks")
|
||||
@Operation(summary = "拉取打印终端待办")
|
||||
@Operation(summary = "拉取业务终端代理打印待办")
|
||||
public R<?> printerTasks(@RequestHeader("DEVICE-ID") Long hardId) {
|
||||
return R.ok(hardInvoiceService.listPendingTasks(hardId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交当前 EY_PRINT 的 USB 打印结果。
|
||||
* 由当前食堂或超市终端代理提交 USB 打印结果。
|
||||
*
|
||||
* @param hardId DEVICE-ID 请求头中的打印终端 ID
|
||||
* @param hardId DEVICE-ID 请求头中的来源业务终端 ID
|
||||
* @param result 任务、订单、版本和结果
|
||||
* @return 接受或幂等忽略时返回 {@code true}
|
||||
*/
|
||||
@PostMapping("/printer/result")
|
||||
@Operation(summary = "提交打印终端结果")
|
||||
@Operation(summary = "提交业务终端代理打印结果")
|
||||
public R<Boolean> printerResult(@RequestHeader("DEVICE-ID") Long hardId,
|
||||
@Valid @RequestBody HardPrintResultDto result) {
|
||||
return R.ok(hardInvoiceService.reportPrintResult(hardId, result));
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import com.bsd.pjcloud.hard.api.entity.HardPrinterBindingEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 打印终端一对一绑定关系数据访问接口。
|
||||
* 业务终端与无屏 USB 打印机资产一对一绑定关系数据访问接口。
|
||||
*/
|
||||
@Mapper
|
||||
public interface HardPrinterBindingMapper extends PjcloudBaseMapper<HardPrinterBindingEntity> {
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import com.bsd.pjcloud.hard.api.entity.HardPrinterConfigEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 尔印打印终端参数数据访问接口。
|
||||
* 尔印 USB 打印机资产参数数据访问接口。
|
||||
*/
|
||||
@Mapper
|
||||
public interface HardPrinterConfigMapper extends PjcloudBaseMapper<HardPrinterConfigEntity> {
|
||||
|
||||
+5
-5
@@ -95,21 +95,21 @@ public interface HardInvoiceService extends IService<HardInvoiceEntity> {
|
||||
int cancelPendingVoucherTasks(Long orderId);
|
||||
|
||||
/**
|
||||
* 查询指定 EY_PRINT 终端的待打印任务,供启动、重连和定时补拉。
|
||||
* 查询指定来源业务终端所绑定打印机的待打印任务,供启动、重连和定时补拉。
|
||||
*
|
||||
* @param printerHardId 目标打印终端 ID
|
||||
* @param sourceHardId DEVICE-ID 请求头中的来源业务终端 ID
|
||||
* @return 待打印任务列表
|
||||
*/
|
||||
List<HardInvoiceEntity> listPendingTasks(Long printerHardId);
|
||||
List<HardInvoiceEntity> listPendingTasks(Long sourceHardId);
|
||||
|
||||
/**
|
||||
* 校验终端身份、订单和版本后记录打印结果。
|
||||
*
|
||||
* @param printerHardId DEVICE-ID 请求头解析出的目标设备
|
||||
* @param sourceHardId DEVICE-ID 请求头解析出的来源业务终端
|
||||
* @param result 终端回执
|
||||
* @return 接受或幂等忽略回执时返回 {@code true}
|
||||
*/
|
||||
Boolean reportPrintResult(Long printerHardId, HardPrintResultDto result);
|
||||
Boolean reportPrintResult(Long sourceHardId, HardPrintResultDto result);
|
||||
|
||||
/**
|
||||
* 跨租户扫描并处理待生成和待打印任务。
|
||||
|
||||
+13
-13
@@ -12,25 +12,25 @@ import com.bsd.pjcloud.hard.api.vo.manager.HardManagerVo;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 尔印打印终端绑定和配置服务。
|
||||
* 业务终端与无屏尔印 USB 打印机的绑定和配置服务。
|
||||
*/
|
||||
public interface HardPrinterService {
|
||||
|
||||
/**
|
||||
* 查询指定来源或打印设备当前绑定详情。
|
||||
* 查询指定来源终端或打印机资产当前绑定详情。
|
||||
*
|
||||
* @param hardId 来源业务终端或打印终端 ID
|
||||
* @param hardId 来源业务终端或打印机资产 ID
|
||||
* @return 绑定详情;未绑定时返回 {@code null}
|
||||
*/
|
||||
HardPrinterBindingVo getBinding(Long hardId);
|
||||
|
||||
/**
|
||||
* 按目标打印终端身份读取启动绑定,拒绝来源业务终端借用打印模式接口。
|
||||
* 按当前来源业务终端身份读取其绑定打印机和打印参数。
|
||||
*
|
||||
* @param printerHardId DEVICE-ID 声明的 EY_PRINT 设备 ID
|
||||
* @return 已绑定的来源终端及打印参数
|
||||
* @param sourceHardId DEVICE-ID 声明的 SUPERMARKET/CANTEEN 设备 ID
|
||||
* @return 当前绑定及打印参数;尚未绑定时返回 {@code null}
|
||||
*/
|
||||
HardPrinterBindingVo getPrinterBinding(Long printerHardId);
|
||||
HardPrinterBindingVo getSourceBinding(Long sourceHardId);
|
||||
|
||||
/**
|
||||
* 批量补充设备分页中的绑定关系和打印参数,避免管理端逐行请求。
|
||||
@@ -40,10 +40,10 @@ public interface HardPrinterService {
|
||||
void enrichDevices(List<HardManagerVo> devices);
|
||||
|
||||
/**
|
||||
* 查询来源设备同商户下尚未绑定的 EY_PRINT 设备。
|
||||
* 查询来源设备同商户下尚未绑定的 EY_PRINT 打印机资产。
|
||||
*
|
||||
* @param sourceHardId 来源业务终端 ID
|
||||
* @return 可绑定打印终端列表
|
||||
* @return 可绑定打印机资产列表
|
||||
*/
|
||||
List<HardManagerEntity> listAvailablePrinters(Long sourceHardId);
|
||||
|
||||
@@ -87,16 +87,16 @@ public interface HardPrinterService {
|
||||
HardPrinterConfigEntity saveConfig(HardPrinterConfigDto dto);
|
||||
|
||||
/**
|
||||
* 由当前打印终端上报实际打印机型号和 USB 标识,保留后台维护的 ESC/POS 参数。
|
||||
* 由当前来源业务终端代理上报实际 USB 打印机型号和标识,保留后台维护的 ESC/POS 参数。
|
||||
*
|
||||
* @param printerHardId DEVICE-ID 请求头中的 EY_PRINT 设备 ID
|
||||
* @param sourceHardId DEVICE-ID 请求头中的 SUPERMARKET/CANTEEN 设备 ID
|
||||
* @param dto Android USB Host 读取到的型号、VID 和 PID
|
||||
* @return 更新后的打印机配置
|
||||
*/
|
||||
HardPrinterConfigEntity reportDeviceInfo(Long printerHardId, HardPrinterInfoReportDto dto);
|
||||
HardPrinterConfigEntity reportDeviceInfo(Long sourceHardId, HardPrinterInfoReportDto dto);
|
||||
|
||||
/**
|
||||
* 按来源业务终端解析当前有效打印终端。
|
||||
* 按来源业务终端解析当前有效打印机资产。
|
||||
*
|
||||
* @param sourceHardId 来源终端 ID
|
||||
* @return 当前绑定;未绑定时返回 {@code null}
|
||||
|
||||
+42
-17
@@ -268,7 +268,7 @@ public class HardInvoiceServiceImpl extends ServiceImpl<HardInvoiceMapper, HardI
|
||||
throw new RuntimeException("打印任务与订单不匹配");
|
||||
}
|
||||
if (detail.getPrinterHardId() != null) {
|
||||
throw new RuntimeException("尔印打印终端必须使用带设备身份的打印结果接口");
|
||||
throw new RuntimeException("尔印打印任务必须由绑定业务终端使用带设备身份的结果接口");
|
||||
}
|
||||
if (Objects.equals(detail.getStatus(), HardPrintStatusEnum.PRINT.getType())) return true;
|
||||
if (!Objects.equals(detail.getStatus(), HardPrintStatusEnum.GENERATE.getType())) return false;
|
||||
@@ -413,10 +413,11 @@ public class HardInvoiceServiceImpl extends ServiceImpl<HardInvoiceMapper, HardI
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public List<HardInvoiceEntity> listPendingTasks(Long printerHardId) {
|
||||
requirePrinterIdentity(printerHardId);
|
||||
public List<HardInvoiceEntity> listPendingTasks(Long sourceHardId) {
|
||||
HardPrinterBindingEntity binding = requireSourceBinding(sourceHardId);
|
||||
return baseMapper.selectList(Wrappers.<HardInvoiceEntity>lambdaQuery()
|
||||
.eq(HardInvoiceEntity::getPrinterHardId, printerHardId)
|
||||
.eq(HardInvoiceEntity::getHardId, sourceHardId)
|
||||
.eq(HardInvoiceEntity::getPrinterHardId, binding.getPrinterHardId())
|
||||
.eq(HardInvoiceEntity::getStatus, HardPrintStatusEnum.GENERATE.getType())
|
||||
.isNotNull(HardInvoiceEntity::getPic)
|
||||
.orderByAsc(HardInvoiceEntity::getCreateTime)
|
||||
@@ -426,14 +427,15 @@ public class HardInvoiceServiceImpl extends ServiceImpl<HardInvoiceMapper, HardI
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean reportPrintResult(Long printerHardId, HardPrintResultDto result) {
|
||||
requirePrinterIdentity(printerHardId);
|
||||
public Boolean reportPrintResult(Long sourceHardId, HardPrintResultDto result) {
|
||||
HardPrinterBindingEntity binding = requireSourceBinding(sourceHardId);
|
||||
HardInvoiceEntity task = baseMapper.selectById(result.getTaskId());
|
||||
if (task == null || !Objects.equals(task.getOrderId(), result.getOrderId())) {
|
||||
throw new RuntimeException("打印任务与订单不匹配");
|
||||
}
|
||||
if (!Objects.equals(task.getPrinterHardId(), printerHardId)) {
|
||||
throw new RuntimeException("当前设备不是任务目标打印终端");
|
||||
if (!Objects.equals(task.getHardId(), sourceHardId)
|
||||
|| !Objects.equals(task.getPrinterHardId(), binding.getPrinterHardId())) {
|
||||
throw new RuntimeException("当前业务终端不是该打印任务的绑定代理");
|
||||
}
|
||||
int currentVersion = ObjectUtil.defaultIfNull(task.getRetryVersion(), 0);
|
||||
if (result.getRetryVersion() < currentVersion) return true;
|
||||
@@ -511,7 +513,7 @@ public class HardInvoiceServiceImpl extends ServiceImpl<HardInvoiceMapper, HardI
|
||||
Long normalizedSource = sourceHardId != null && sourceHardId > 0 ? sourceHardId : null;
|
||||
HardPrinterBindingEntity binding = printerService.findBySourceHardId(normalizedSource);
|
||||
boolean canDispatch = binding != null;
|
||||
HardInvoiceEntity task = HardInvoiceEntity.builder().deptId(order.getDeptId()).hardId(normalizedSource)
|
||||
HardInvoiceEntity task = HardInvoiceEntity.builder().deptId(resolveTaskDeptId(order)).hardId(normalizedSource)
|
||||
.printerHardId(canDispatch ? binding.getPrinterHardId() : null).orderId(order.getId())
|
||||
.printType(printType.getType()).printNo(printNo).retryVersion(0).attemptCount(0)
|
||||
.status(canDispatch ? HardPrintStatusEnum.PENDING_GENERATION.getType() : HardPrintStatusEnum.FAILED.getType())
|
||||
@@ -530,6 +532,19 @@ public class HardInvoiceServiceImpl extends ServiceImpl<HardInvoiceMapper, HardI
|
||||
return task;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析打印任务的数据权限归属部门。设备订单优先沿用下单设备部门,App 预约订单没有设备上下文时
|
||||
* 使用下单时固化的商户部门快照,避免把后续核销设备的部门误写成订单归属。
|
||||
*
|
||||
* @param order 创建打印任务的订单快照
|
||||
* @return 可持久化到打印任务的部门 ID
|
||||
*/
|
||||
private Long resolveTaskDeptId(HardOrderEntity order) {
|
||||
Long deptId = order.getDeptId() != null ? order.getDeptId() : order.getMerchantDeptId();
|
||||
if (deptId == null) throw new RuntimeException("订单缺少归属部门,无法创建打印任务");
|
||||
return deptId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在当前事务提交后把任务投递到硬件异步线程池;无事务时立即投递。
|
||||
*/
|
||||
@@ -596,7 +611,7 @@ public class HardInvoiceServiceImpl extends ServiceImpl<HardInvoiceMapper, HardI
|
||||
}
|
||||
|
||||
/**
|
||||
* 向目标 EY_PRINT 发布 MQTT 任务,代理接受后仍保持待打印状态。
|
||||
* 向绑定来源业务终端发布 MQTT 任务,代理接受后仍保持待打印状态。
|
||||
*/
|
||||
private void dispatchTask(HardInvoiceEntity task) {
|
||||
try {
|
||||
@@ -604,7 +619,7 @@ public class HardInvoiceServiceImpl extends ServiceImpl<HardInvoiceMapper, HardI
|
||||
if (order == null) throw new RuntimeException("订单不存在");
|
||||
HardPrintMsg message = new HardPrintMsg();
|
||||
message.setUserId(order.getUserId());
|
||||
message.setHardId(task.getPrinterHardId());
|
||||
message.setHardId(task.getHardId());
|
||||
message.setSourceHardId(task.getHardId());
|
||||
message.setTargetHardId(task.getPrinterHardId());
|
||||
message.setMchDeptId(order.getMerchantDeptId());
|
||||
@@ -743,12 +758,22 @@ public class HardInvoiceServiceImpl extends ServiceImpl<HardInvoiceMapper, HardI
|
||||
return sourceHardId;
|
||||
}
|
||||
|
||||
/** 校验 DEVICE-ID 确实属于 EY_PRINT 终端。 */
|
||||
private void requirePrinterIdentity(Long printerHardId) {
|
||||
if (printerHardId == null) throw new RuntimeException("DEVICE-ID不能为空");
|
||||
HardManagerEntity printer = hardManagerService.getById(printerHardId);
|
||||
HardTypeEnum type = printer == null ? null : HardTypeEnum.valueOfByType(printer.getType());
|
||||
if (printer == null || !HardTypeEnum.isPrintHard(type)) throw new RuntimeException("当前设备不是尔印打印终端");
|
||||
/**
|
||||
* 校验 DEVICE-ID 属于食堂或超市 Android 终端,并返回其当前打印机绑定。
|
||||
*
|
||||
* @param sourceHardId DEVICE-ID 中的来源业务终端 ID
|
||||
* @return 当前来源终端的一对一打印机绑定
|
||||
*/
|
||||
private HardPrinterBindingEntity requireSourceBinding(Long sourceHardId) {
|
||||
if (sourceHardId == null) throw new RuntimeException("DEVICE-ID不能为空");
|
||||
HardManagerEntity source = hardManagerService.getById(sourceHardId);
|
||||
HardTypeEnum type = source == null ? null : HardTypeEnum.valueOfByType(source.getType());
|
||||
if (source == null || (type != HardTypeEnum.SUPERMARKET && type != HardTypeEnum.CANTEEN)) {
|
||||
throw new RuntimeException("当前设备不是超市或食堂业务终端");
|
||||
}
|
||||
HardPrinterBindingEntity binding = printerService.findBySourceHardId(sourceHardId);
|
||||
if (binding == null) throw new RuntimeException("当前业务终端尚未绑定尔印打印机");
|
||||
return binding;
|
||||
}
|
||||
|
||||
/** 将异常写入指定任务,条件版本防止旧处理覆盖人工新重试。 */
|
||||
|
||||
+82
-19
@@ -20,10 +20,14 @@ import com.bsd.pjcloud.hard.mapper.HardPrinterBindingMapper;
|
||||
import com.bsd.pjcloud.hard.mapper.HardPrinterConfigMapper;
|
||||
import com.bsd.pjcloud.hard.mapper.manager.HardManagerMapper;
|
||||
import com.bsd.pjcloud.hard.service.HardPrinterService;
|
||||
import com.bsd.pjcloud.mqtt.api.feign.RemoteMqttEventService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -32,10 +36,11 @@ import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 尔印打印终端绑定和配置服务实现。
|
||||
* 业务终端与无屏尔印 USB 打印机的绑定和配置服务实现。
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class HardPrinterServiceImpl implements HardPrinterService {
|
||||
|
||||
/** 默认纸张宽度,单位毫米。 */
|
||||
@@ -65,6 +70,9 @@ public class HardPrinterServiceImpl implements HardPrinterService {
|
||||
/** 打印任务 Mapper。 */
|
||||
private final HardInvoiceMapper invoiceMapper;
|
||||
|
||||
/** MQTT 配置变更通知服务,用于让业务终端立即刷新打印机绑定。 */
|
||||
private final RemoteMqttEventService mqttEventService;
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public HardPrinterBindingVo getBinding(Long hardId) {
|
||||
@@ -78,13 +86,10 @@ public class HardPrinterServiceImpl implements HardPrinterService {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public HardPrinterBindingVo getPrinterBinding(Long printerHardId) {
|
||||
HardManagerEntity printer = requirePrinter(printerHardId);
|
||||
HardPrinterBindingEntity binding = bindingMapper.selectOne(Wrappers.<HardPrinterBindingEntity>lambdaQuery()
|
||||
.eq(HardPrinterBindingEntity::getPrinterHardId, printer.getId())
|
||||
.last("limit 1"));
|
||||
if (binding == null) throw new RuntimeException("尔印打印终端尚未绑定业务终端");
|
||||
return assemble(binding);
|
||||
public HardPrinterBindingVo getSourceBinding(Long sourceHardId) {
|
||||
HardManagerEntity source = requireSource(sourceHardId);
|
||||
HardPrinterBindingEntity binding = findBySourceHardId(source.getId());
|
||||
return binding == null ? null : assemble(binding);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@@ -173,13 +178,13 @@ public class HardPrinterServiceImpl implements HardPrinterService {
|
||||
HardManagerEntity source = requireSource(dto.getSourceHardId());
|
||||
HardManagerEntity printer = requirePrinter(dto.getPrinterHardId());
|
||||
if (!Objects.equals(source.getTenantId(), printer.getTenantId())) {
|
||||
throw new RuntimeException("来源终端和打印终端必须属于同一租户");
|
||||
throw new RuntimeException("来源终端和打印机资产必须属于同一租户");
|
||||
}
|
||||
if (!Objects.equals(source.getMerchantId(), printer.getMerchantId())) {
|
||||
throw new RuntimeException("来源终端和打印终端必须属于同一商户");
|
||||
throw new RuntimeException("来源终端和打印机资产必须属于同一商户");
|
||||
}
|
||||
if (!Objects.equals(source.getDeptId(), printer.getDeptId())) {
|
||||
throw new RuntimeException("来源终端和打印终端必须属于同一商户部门");
|
||||
throw new RuntimeException("来源终端和打印机资产必须属于同一商户部门");
|
||||
}
|
||||
HardPrinterBindingEntity binding = HardPrinterBindingEntity.builder()
|
||||
.sourceHardId(source.getId())
|
||||
@@ -191,12 +196,13 @@ public class HardPrinterServiceImpl implements HardPrinterService {
|
||||
try {
|
||||
bindingMapper.insert(binding);
|
||||
} catch (DuplicateKeyException exception) {
|
||||
throw new RuntimeException("来源终端或打印终端已经绑定,请先解除原绑定", exception);
|
||||
throw new RuntimeException("来源终端或打印机资产已经绑定,请先解除原绑定", exception);
|
||||
}
|
||||
if (configMapper.selectCount(Wrappers.<HardPrinterConfigEntity>lambdaQuery()
|
||||
.eq(HardPrinterConfigEntity::getPrinterHardId, printer.getId())) == 0) {
|
||||
configMapper.insert(defaultConfig(printer));
|
||||
}
|
||||
notifyBindingChangeAfterCommit(source.getDeptId());
|
||||
return assemble(binding);
|
||||
}
|
||||
|
||||
@@ -210,6 +216,7 @@ public class HardPrinterServiceImpl implements HardPrinterService {
|
||||
throw new RuntimeException("存在待生成、待打印或打印失败任务,处理完成后才能解绑");
|
||||
}
|
||||
bindingMapper.deleteById(binding.getId());
|
||||
notifyBindingChangeAfterCommit(binding.getDeptId());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@@ -239,14 +246,17 @@ public class HardPrinterServiceImpl implements HardPrinterService {
|
||||
config.setId(existing.getId());
|
||||
configMapper.updateById(config);
|
||||
}
|
||||
HardPrinterBindingEntity binding = findByPrinterHardId(printer.getId());
|
||||
if (binding != null) notifyBindingChangeAfterCommit(binding.getDeptId());
|
||||
return configMapper.selectById(config.getId());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public HardPrinterConfigEntity reportDeviceInfo(Long printerHardId, HardPrinterInfoReportDto dto) {
|
||||
HardManagerEntity printer = requirePrinter(printerHardId);
|
||||
public HardPrinterConfigEntity reportDeviceInfo(Long sourceHardId, HardPrinterInfoReportDto dto) {
|
||||
HardPrinterBindingEntity binding = requireSourceBinding(sourceHardId);
|
||||
HardManagerEntity printer = requirePrinter(binding.getPrinterHardId());
|
||||
HardPrinterConfigEntity config = configMapper.selectOne(Wrappers.<HardPrinterConfigEntity>lambdaQuery()
|
||||
.eq(HardPrinterConfigEntity::getPrinterHardId, printer.getId())
|
||||
.last("limit 1"));
|
||||
@@ -313,21 +323,74 @@ public class HardPrinterServiceImpl implements HardPrinterService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验并返回 EY_PRINT 打印终端。
|
||||
* 校验并返回 EY_PRINT 逻辑打印机资产。
|
||||
*
|
||||
* @param hardId 打印设备 ID
|
||||
* @return 有效打印设备
|
||||
* @return 有效打印机资产
|
||||
*/
|
||||
private HardManagerEntity requirePrinter(Long hardId) {
|
||||
HardManagerEntity printer = hardManagerMapper.selectById(hardId);
|
||||
HardTypeEnum type = printer == null ? null : HardTypeEnum.valueOfByType(printer.getType());
|
||||
if (printer == null || !HardTypeEnum.isPrintHard(type)) {
|
||||
throw new RuntimeException("目标设备必须是尔印打印终端");
|
||||
throw new RuntimeException("目标设备必须是尔印打印机");
|
||||
}
|
||||
if (printer.getMerchantId() == null) throw new RuntimeException("打印终端未绑定商户");
|
||||
if (printer.getMerchantId() == null) throw new RuntimeException("打印机未绑定商户");
|
||||
return printer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验当前 Android 来源终端并返回其一对一打印机绑定。
|
||||
*
|
||||
* @param sourceHardId DEVICE-ID 中的来源业务终端 ID
|
||||
* @return 当前来源终端的有效绑定
|
||||
*/
|
||||
private HardPrinterBindingEntity requireSourceBinding(Long sourceHardId) {
|
||||
HardManagerEntity source = requireSource(sourceHardId);
|
||||
HardPrinterBindingEntity binding = findBySourceHardId(source.getId());
|
||||
if (binding == null) throw new RuntimeException("当前业务终端尚未绑定尔印打印机");
|
||||
return binding;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询逻辑打印机资产当前绑定的来源业务终端。
|
||||
*
|
||||
* @param printerHardId EY_PRINT 逻辑打印机资产 ID
|
||||
* @return 当前一对一绑定;未绑定时为空
|
||||
*/
|
||||
private HardPrinterBindingEntity findByPrinterHardId(Long printerHardId) {
|
||||
if (printerHardId == null || printerHardId <= 0) return null;
|
||||
return bindingMapper.selectOne(Wrappers.<HardPrinterBindingEntity>lambdaQuery()
|
||||
.eq(HardPrinterBindingEntity::getPrinterHardId, printerHardId)
|
||||
.last("limit 1"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 在本地事务提交后通知业务终端刷新绑定,MQTT 暂时不可用时不回滚已保存的数据。
|
||||
*
|
||||
* @param deptId 来源业务终端所属部门 ID;为空时跳过通知
|
||||
*/
|
||||
private void notifyBindingChangeAfterCommit(Long deptId) {
|
||||
if (deptId == null) return;
|
||||
Runnable notifyAction = () -> {
|
||||
try {
|
||||
mqttEventService.sendConfigChangeMsg(deptId);
|
||||
} catch (Exception exception) {
|
||||
log.warn("打印机绑定配置已保存,但MQTT刷新通知发送失败,deptId:{}", deptId, exception);
|
||||
}
|
||||
};
|
||||
if (!TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
notifyAction.run();
|
||||
return;
|
||||
}
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
||||
/** 本地绑定事务提交后再通知,避免终端读取到尚未提交的旧关系。 */
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
notifyAction.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验受首期协议约束的打印参数。
|
||||
*
|
||||
@@ -399,7 +462,7 @@ public class HardPrinterServiceImpl implements HardPrinterService {
|
||||
/**
|
||||
* 创建尚未持久化的首期默认打印配置。
|
||||
*
|
||||
* @param printer 打印终端
|
||||
* @param printer 逻辑打印机资产
|
||||
* @return 默认配置
|
||||
*/
|
||||
private HardPrinterConfigEntity defaultConfig(HardManagerEntity printer) {
|
||||
|
||||
+16
-9
@@ -2,6 +2,7 @@ package com.bsd.pjcloud.hard.service.impl.manager;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
@@ -67,7 +68,7 @@ public class HardManagerServiceImpl extends ServiceImpl<HardManagerMapper, HardM
|
||||
private final RemoteDeptService deptService;
|
||||
private final RemoteMqttEventService remoteMqttEventService;
|
||||
|
||||
/** 打印终端绑定服务,用于保护已绑定设备的关键属性和删除动作。 */
|
||||
/** 打印机绑定服务,用于保护已绑定设备的关键属性和删除动作。 */
|
||||
private final HardPrinterService hardPrinterService;
|
||||
/**
|
||||
* 为已完成数据权限过滤的设备分页批量补充终端运行状态。
|
||||
@@ -147,11 +148,15 @@ public class HardManagerServiceImpl extends ServiceImpl<HardManagerMapper, HardM
|
||||
dto.setHardGroupId(deptHardGroup.getHardGroupId());
|
||||
dto.setDeptId(mch.getDeptId());
|
||||
dto.setUniqueCode(dto.getUniqueCode());
|
||||
// mq地址和端口
|
||||
dto.setMqSocketAddress(mqttConfig.getAndroidAddress());
|
||||
dto.setMqSocketPort(mqttConfig.getAndroidPort());
|
||||
boolean logicalPrinter = HardTypeEnum.EY_PRINT.getType().equals(dto.getType());
|
||||
// EY_PRINT 是由业务终端代理的无屏 USB 外设,不生成自身 MQTT 连接配置。
|
||||
if (!logicalPrinter) {
|
||||
dto.setMqSocketAddress(mqttConfig.getAndroidAddress());
|
||||
dto.setMqSocketPort(mqttConfig.getAndroidPort());
|
||||
}
|
||||
// 插入
|
||||
baseMapper.insert(dto);
|
||||
if (logicalPrinter) return dto.getId();
|
||||
// topic
|
||||
HardManagerEntity updateObj = HardManagerEntity.builder().id(dto.getId()).build();
|
||||
String topic = createMqConfigByAction(deptHardGroup.getHardGroupId(), null, null, 1) + "/#";
|
||||
@@ -185,7 +190,10 @@ public class HardManagerServiceImpl extends ServiceImpl<HardManagerMapper, HardM
|
||||
dto.setDeptId(mch.getDeptId());
|
||||
dto.setUniqueCode(dto.getUniqueCode());
|
||||
dto.setHardGroupId(deptHardGroup.getHardGroupId());
|
||||
if (!ObjectUtil.equals(dto.getMerchantId(), detail.getMerchantId())) {
|
||||
String effectiveType = StrUtil.blankToDefault(dto.getType(), detail.getType());
|
||||
boolean logicalPrinter = HardTypeEnum.EY_PRINT.getType().equals(effectiveType);
|
||||
// 无屏打印机资产不连接 MQTT;调整其归属时也不能生成 Android 终端凭据。
|
||||
if (!logicalPrinter && !ObjectUtil.equals(dto.getMerchantId(), detail.getMerchantId())) {
|
||||
// topic
|
||||
String topic = createMqConfigByAction(deptHardGroup.getHardGroupId(), null, null, 1) + "/#";
|
||||
dto.setMainTopic(topic);
|
||||
@@ -197,8 +205,8 @@ public class HardManagerServiceImpl extends ServiceImpl<HardManagerMapper, HardM
|
||||
dto.setMqUsername(mqUsername);
|
||||
}
|
||||
baseMapper.updateById(dto);
|
||||
// 更新mq
|
||||
remoteMqttEventService.sendConfigChangeMsg(detail.getDeptId());
|
||||
// 普通业务终端更新后沿用原逻辑刷新 MQ 配置;打印机资产的绑定接口会通知实际代理终端。
|
||||
if (!logicalPrinter) remoteMqttEventService.sendConfigChangeMsg(detail.getDeptId());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@@ -216,8 +224,7 @@ public class HardManagerServiceImpl extends ServiceImpl<HardManagerMapper, HardM
|
||||
throw new RuntimeException("设备不存在");
|
||||
}
|
||||
if (HardTypeEnum.EY_PRINT.getType().equals(detail.getType())) {
|
||||
// 打印终端必须先由管理端完成一对一来源绑定,避免未归属设备登录后接收错误商户任务。
|
||||
hardPrinterService.getPrinterBinding(detail.getId());
|
||||
throw new RuntimeException("尔印打印机是无屏 USB 外设,请在绑定的超市或食堂终端上操作");
|
||||
}
|
||||
if (existUniqueCode(dto.getUniqueCode(), dto.getId())) {
|
||||
throw new RuntimeException("该唯一编码已经被绑定");
|
||||
|
||||
+3
-4
@@ -147,14 +147,13 @@ public class HardTerminalStatusServiceImpl extends ServiceImpl<HardTerminalStatu
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断设备是否属于支持在线监控的收银或尔印打印 Android 终端。
|
||||
* 判断设备是否属于支持在线监控的食堂或超市 Android 终端。
|
||||
*
|
||||
* @param hardType {@code hard_manager.type} 的持久化编码
|
||||
* @return 超市、食堂或尔印打印设备返回 {@code true}
|
||||
* @return 超市或食堂终端返回 {@code true};无屏 EY_PRINT 外设不单独上报心跳
|
||||
*/
|
||||
private boolean isSupported(String hardType) {
|
||||
return ObjectUtil.equals(HardTypeEnum.SUPERMARKET.getType(), hardType)
|
||||
|| ObjectUtil.equals(HardTypeEnum.CANTEEN.getType(), hardType)
|
||||
|| ObjectUtil.equals(HardTypeEnum.EY_PRINT.getType(), hardType);
|
||||
|| ObjectUtil.equals(HardTypeEnum.CANTEEN.getType(), hardType);
|
||||
}
|
||||
}
|
||||
+50
-19
@@ -3941,27 +3941,58 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
|
||||
HardOrderTypeEnum orderType = HardOrderTypeEnum.valueOfByType(order.getOrderType());
|
||||
boolean isCancel = validateCodeIsCancel(orderType, order.getId());
|
||||
if (isCancel) throw new I18nBizException(ErrorCodes.HARD_QR_ALREADY_VERIFIED);
|
||||
// 核销二维码
|
||||
getSelf().cancelCode(order, userInfo);
|
||||
LocalDateTime verificationTime = LocalDateTime.now();
|
||||
HardOrderEntity updateObj = HardOrderEntity.builder()
|
||||
.id(order.getId())
|
||||
.androidOrderCode(dto.getAndroidOrderCode())
|
||||
.hardId(dto.getHardwareId())
|
||||
.orderStatus(HardOrderStatusEnum.CANCEL.getType())
|
||||
.verificationTime(verificationTime)
|
||||
.build();
|
||||
boolean isReservationVerification = isReservationVerification(order);
|
||||
int updated = isReservationVerification
|
||||
? baseMapper.update(updateObj, new LambdaUpdateWrapper<HardOrderEntity>()
|
||||
.eq(HardOrderEntity::getId, order.getId())
|
||||
.eq(HardOrderEntity::getOrderStatus, HardOrderStatusEnum.PAY.getType()))
|
||||
: baseMapper.updateById(updateObj);
|
||||
if (updated == 0) {
|
||||
throw new I18nBizException(ErrorCodes.HARD_VERIFY_STATUS_CHANGED);
|
||||
boolean remoteCodeCancelled = false;
|
||||
try {
|
||||
// Wallet 是独立远程事务,成功返回后若 Hardware 本地事务失败,必须显式恢复预约二维码。
|
||||
getSelf().cancelCode(order, userInfo);
|
||||
remoteCodeCancelled = true;
|
||||
LocalDateTime verificationTime = LocalDateTime.now();
|
||||
HardOrderEntity updateObj = HardOrderEntity.builder()
|
||||
.id(order.getId())
|
||||
.androidOrderCode(dto.getAndroidOrderCode())
|
||||
.hardId(dto.getHardwareId())
|
||||
.orderStatus(HardOrderStatusEnum.CANCEL.getType())
|
||||
.verificationTime(verificationTime)
|
||||
.build();
|
||||
int updated = isReservationVerification
|
||||
? baseMapper.update(updateObj, new LambdaUpdateWrapper<HardOrderEntity>()
|
||||
.eq(HardOrderEntity::getId, order.getId())
|
||||
.eq(HardOrderEntity::getOrderStatus, HardOrderStatusEnum.PAY.getType()))
|
||||
: baseMapper.updateById(updateObj);
|
||||
if (updated == 0) {
|
||||
throw new I18nBizException(ErrorCodes.HARD_VERIFY_STATUS_CHANGED);
|
||||
}
|
||||
if (isReservationVerification) createReservationVerificationArtifacts(order, verificationTime, dto.getHardwareId());
|
||||
return true;
|
||||
} catch (RuntimeException exception) {
|
||||
if (isReservationVerification && remoteCodeCancelled) {
|
||||
rollbackReservationCodeAfterLocalFailure(order, exception);
|
||||
}
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hardware 本地核销事务失败后补偿已经提交的 Wallet 预约码状态,使订单仍可重新核销。补偿失败时
|
||||
* 保留原始业务异常,并把恢复异常作为 suppressed exception 记录,便于运维识别需要人工修复的订单。
|
||||
*
|
||||
* @param order 本次核销失败的预约订单
|
||||
* @param originalException 触发 Hardware 本地事务回滚的原始异常
|
||||
*/
|
||||
private void rollbackReservationCodeAfterLocalFailure(HardOrderEntity order, RuntimeException originalException) {
|
||||
try {
|
||||
R<Boolean> result = remoteCodeUseService.rollbackReservationCode(order.getId());
|
||||
if (result != null && result.isOk() && Boolean.TRUE.equals(result.getData())) return;
|
||||
String message = result == null ? "恢复预约核销码无响应"
|
||||
: StrUtil.blankToDefault(result.getMsg(), "恢复预约核销码失败");
|
||||
IllegalStateException rollbackException = new IllegalStateException(message);
|
||||
originalException.addSuppressed(rollbackException);
|
||||
log.error("预约核销本地事务失败且二维码补偿失败,orderId:{},message:{}", order.getId(), message);
|
||||
} catch (RuntimeException rollbackException) {
|
||||
originalException.addSuppressed(rollbackException);
|
||||
log.error("预约核销本地事务失败且二维码补偿异常,orderId:{}", order.getId(), rollbackException);
|
||||
}
|
||||
if (isReservationVerification) createReservationVerificationArtifacts(order, verificationTime, dto.getHardwareId());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+4
-4
@@ -95,7 +95,7 @@ class HardApiControllerTest {
|
||||
assertEquals(10, result.get(0).getOriginalProductCount());
|
||||
}
|
||||
|
||||
/** 验证上报目标只使用可信 DEVICE-ID,并将服务保存结果原样返回。 */
|
||||
/** 验证来源终端代理上报只使用可信 DEVICE-ID,并将服务保存结果原样返回。 */
|
||||
@Test
|
||||
void reportPrinterInfoUsesTrustedDeviceHeader() {
|
||||
HardPrinterInfoReportDto request = new HardPrinterInfoReportDto();
|
||||
@@ -106,12 +106,12 @@ class HardApiControllerTest {
|
||||
.printerHardId(20L).printerModel(request.getPrinterModel())
|
||||
.usbVendorId(10473).usbProductId(649).paperWidth(80)
|
||||
.autoCut("1").imageMode("GS_V0").build();
|
||||
when(hardPrinterService.reportDeviceInfo(20L, request)).thenReturn(saved);
|
||||
when(hardPrinterService.reportDeviceInfo(10L, request)).thenReturn(saved);
|
||||
|
||||
HardPrinterConfigEntity result = (HardPrinterConfigEntity) controller.reportPrinterInfo(20L, request).getData();
|
||||
HardPrinterConfigEntity result = (HardPrinterConfigEntity) controller.reportPrinterInfo(10L, request).getData();
|
||||
|
||||
assertSame(saved, result);
|
||||
verify(hardPrinterService).reportDeviceInfo(20L, request);
|
||||
verify(hardPrinterService).reportDeviceInfo(10L, request);
|
||||
}
|
||||
|
||||
/** 构造带原购、剩余数量和原行金额的购物车展示对象。 */
|
||||
|
||||
+8
-8
@@ -125,8 +125,10 @@ class HardInvoiceServiceImplTest {
|
||||
@Test
|
||||
void reportPrintResultExcludesCancelledStatusAtUpdateTime() {
|
||||
HardInvoiceEntity pending = task(100L, HardPrintStatusEnum.GENERATE, 2);
|
||||
pending.setHardId(10L);
|
||||
pending.setPrinterHardId(20L);
|
||||
when(managerService.getById(20L)).thenReturn(printer());
|
||||
when(managerService.getById(10L)).thenReturn(source());
|
||||
when(printerService.findBySourceHardId(10L)).thenReturn(binding());
|
||||
when(invoiceMapper.selectById(100L)).thenReturn(pending);
|
||||
when(invoiceMapper.update(isNull(), any(Wrapper.class))).thenReturn(0);
|
||||
HardPrintResultDto result = new HardPrintResultDto();
|
||||
@@ -136,7 +138,7 @@ class HardInvoiceServiceImplTest {
|
||||
result.setSuccess(true);
|
||||
result.setAttemptCount(1);
|
||||
|
||||
assertFalse(service.reportPrintResult(20L, result));
|
||||
assertFalse(service.reportPrintResult(10L, result));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ArgumentCaptor<LambdaUpdateWrapper<HardInvoiceEntity>> wrapperCaptor =
|
||||
@@ -151,8 +153,10 @@ class HardInvoiceServiceImplTest {
|
||||
@Test
|
||||
void lateFailureCannotOverwritePrintedTask() {
|
||||
HardInvoiceEntity printed = task(100L, HardPrintStatusEnum.PRINT, 2);
|
||||
printed.setHardId(10L);
|
||||
printed.setPrinterHardId(20L);
|
||||
when(managerService.getById(20L)).thenReturn(printer());
|
||||
when(managerService.getById(10L)).thenReturn(source());
|
||||
when(printerService.findBySourceHardId(10L)).thenReturn(binding());
|
||||
when(invoiceMapper.selectById(100L)).thenReturn(printed);
|
||||
HardPrintResultDto result = new HardPrintResultDto();
|
||||
result.setTaskId(100L);
|
||||
@@ -162,7 +166,7 @@ class HardInvoiceServiceImplTest {
|
||||
result.setAttemptCount(3);
|
||||
result.setErrorMessage("late error");
|
||||
|
||||
assertTrue(service.reportPrintResult(20L, result));
|
||||
assertTrue(service.reportPrintResult(10L, result));
|
||||
verify(invoiceMapper, never()).update(isNull(), any(Wrapper.class));
|
||||
}
|
||||
|
||||
@@ -174,10 +178,6 @@ class HardInvoiceServiceImplTest {
|
||||
return HardManagerEntity.builder().id(10L).type(HardTypeEnum.CANTEEN.getType()).merchantId(30L).build();
|
||||
}
|
||||
|
||||
private static HardManagerEntity printer() {
|
||||
return HardManagerEntity.builder().id(20L).type(HardTypeEnum.EY_PRINT.getType()).merchantId(30L).build();
|
||||
}
|
||||
|
||||
private static HardPrinterBindingEntity binding() {
|
||||
return HardPrinterBindingEntity.builder().sourceHardId(10L).printerHardId(20L).merchantId(30L).build();
|
||||
}
|
||||
|
||||
+29
-14
@@ -3,6 +3,7 @@ package com.bsd.pjcloud.hard.service.impl;
|
||||
import com.bsd.pjcloud.hard.api.constant.HardTypeEnum;
|
||||
import com.bsd.pjcloud.hard.api.dto.HardPrinterConfigDto;
|
||||
import com.bsd.pjcloud.hard.api.dto.HardPrinterInfoReportDto;
|
||||
import com.bsd.pjcloud.hard.api.entity.HardPrinterBindingEntity;
|
||||
import com.bsd.pjcloud.hard.api.entity.HardPrinterConfigEntity;
|
||||
import com.bsd.pjcloud.hard.api.entity.manager.HardManagerEntity;
|
||||
import com.bsd.pjcloud.hard.api.vo.HardPrinterBindingVo;
|
||||
@@ -10,6 +11,7 @@ import com.bsd.pjcloud.hard.api.vo.manager.HardManagerVo;
|
||||
import com.bsd.pjcloud.hard.mapper.HardPrinterBindingMapper;
|
||||
import com.bsd.pjcloud.hard.mapper.HardPrinterConfigMapper;
|
||||
import com.bsd.pjcloud.hard.mapper.manager.HardManagerMapper;
|
||||
import com.bsd.pjcloud.mqtt.api.feign.RemoteMqttEventService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
@@ -33,19 +35,29 @@ import static org.mockito.Mockito.when;
|
||||
class HardPrinterServiceImplTest {
|
||||
|
||||
private final HardManagerMapper managerMapper = mock(HardManagerMapper.class);
|
||||
/** 打印配置数据访问对象,用于验证终端上报只修改允许字段。 */
|
||||
/** 打印机绑定数据访问对象,用于把来源业务终端解析为目标打印机资产。 */
|
||||
private final HardPrinterBindingMapper bindingMapper = mock(HardPrinterBindingMapper.class);
|
||||
/** 打印配置数据访问对象,用于验证来源终端代理上报只修改允许字段。 */
|
||||
private final HardPrinterConfigMapper configMapper = mock(HardPrinterConfigMapper.class);
|
||||
/** MQTT 通知服务,用于隔离绑定配置刷新通知。 */
|
||||
private final RemoteMqttEventService mqttEventService = mock(RemoteMqttEventService.class);
|
||||
|
||||
/** 使用真实业务方法和注入 Mapper 的被测服务。 */
|
||||
private final HardPrinterServiceImpl service = mock(HardPrinterServiceImpl.class, CALLS_REAL_METHODS);
|
||||
|
||||
/** 为每个用例注入相同 Mapper,并准备一台有效的 EY_PRINT 设备。 */
|
||||
/** 为每个用例注入相同 Mapper,并准备一台来源终端及其绑定的 EY_PRINT 打印机。 */
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
ReflectionTestUtils.setField(service, "hardManagerMapper", managerMapper);
|
||||
ReflectionTestUtils.setField(service, "bindingMapper", bindingMapper);
|
||||
ReflectionTestUtils.setField(service, "configMapper", configMapper);
|
||||
ReflectionTestUtils.setField(service, "mqttEventService", mqttEventService);
|
||||
when(managerMapper.selectById(10L)).thenReturn(HardManagerEntity.builder()
|
||||
.id(10L).type(HardTypeEnum.CANTEEN.getType()).merchantId(30L).tenantId(50L).build());
|
||||
when(managerMapper.selectById(20L)).thenReturn(HardManagerEntity.builder()
|
||||
.id(20L).type(HardTypeEnum.EY_PRINT.getType()).merchantId(30L).tenantId(50L).build());
|
||||
when(bindingMapper.selectOne(any())).thenReturn(HardPrinterBindingEntity.builder()
|
||||
.sourceHardId(10L).printerHardId(20L).merchantId(30L).tenantId(50L).build());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -60,8 +72,6 @@ class HardPrinterServiceImplTest {
|
||||
/** 未绑定打印机的普通设备应保留空配置,不能因空打印机 ID 导致列表查询失败。 */
|
||||
@Test
|
||||
void enrichDevicesSkipsPrinterConfigForUnboundDevice() {
|
||||
HardPrinterBindingMapper bindingMapper = mock(HardPrinterBindingMapper.class);
|
||||
ReflectionTestUtils.setField(service, "bindingMapper", bindingMapper);
|
||||
HardManagerVo device = new HardManagerVo();
|
||||
device.setId(10L);
|
||||
device.setType(HardTypeEnum.SUPERMARKET.getType());
|
||||
@@ -73,6 +83,14 @@ class HardPrinterServiceImplTest {
|
||||
assertNull(device.getPrinterModel());
|
||||
}
|
||||
|
||||
/** 未绑定来源业务终端查询绑定时应返回空,由客户端保留本地 USB 测试能力。 */
|
||||
@Test
|
||||
void getSourceBindingReturnsNullWhenBusinessTerminalIsUnbound() {
|
||||
when(bindingMapper.selectOne(any())).thenReturn(null);
|
||||
|
||||
assertNull(service.getSourceBinding(10L));
|
||||
}
|
||||
|
||||
@Test
|
||||
void usbVidAndPidMustBeConfiguredTogether() {
|
||||
HardPrinterConfigDto config = validConfig();
|
||||
@@ -94,7 +112,7 @@ class HardPrinterServiceImplTest {
|
||||
assertEquals("USB VID必须在0到65535之间", exception.getMessage());
|
||||
}
|
||||
|
||||
/** 终端重新上报真机参数时必须保留管理端维护的纸宽、切刀和图片模式。 */
|
||||
/** 来源终端重新上报真机参数时必须保留管理端维护的纸宽、切刀和图片模式。 */
|
||||
@Test
|
||||
void reportDeviceInfoPreservesEscPosConfiguration() {
|
||||
HardPrinterConfigEntity existing = HardPrinterConfigEntity.builder()
|
||||
@@ -103,7 +121,7 @@ class HardPrinterServiceImplTest {
|
||||
.autoCut("0").imageMode("ESC_STAR").tenantId(50L).build();
|
||||
when(configMapper.selectOne(any())).thenReturn(existing);
|
||||
|
||||
HardPrinterConfigEntity result = service.reportDeviceInfo(20L, reportRequest());
|
||||
HardPrinterConfigEntity result = service.reportDeviceInfo(10L, reportRequest());
|
||||
|
||||
assertEquals("GEZHI / micro-printer", result.getPrinterModel());
|
||||
assertEquals(10473, result.getUsbVendorId());
|
||||
@@ -119,7 +137,7 @@ class HardPrinterServiceImplTest {
|
||||
void reportDeviceInfoCreatesDefaultConfiguration() {
|
||||
when(configMapper.selectOne(any())).thenReturn(null);
|
||||
|
||||
HardPrinterConfigEntity result = service.reportDeviceInfo(20L, reportRequest());
|
||||
HardPrinterConfigEntity result = service.reportDeviceInfo(10L, reportRequest());
|
||||
|
||||
assertEquals(20L, result.getPrinterHardId());
|
||||
assertEquals("GEZHI / micro-printer", result.getPrinterModel());
|
||||
@@ -131,16 +149,13 @@ class HardPrinterServiceImplTest {
|
||||
verify(configMapper).insert(result);
|
||||
}
|
||||
|
||||
/** 普通业务终端不能借用设备信息接口覆盖打印终端配置。 */
|
||||
/** EY_PRINT 资产不能冒充有屏 Android 来源终端上报自身配置。 */
|
||||
@Test
|
||||
void reportDeviceInfoRejectsNonPrinterDevice() {
|
||||
when(managerMapper.selectById(21L)).thenReturn(HardManagerEntity.builder()
|
||||
.id(21L).type(HardTypeEnum.CANTEEN.getType()).merchantId(30L).tenantId(50L).build());
|
||||
|
||||
void reportDeviceInfoRejectsPrinterAssetIdentity() {
|
||||
RuntimeException exception = assertThrows(RuntimeException.class,
|
||||
() -> service.reportDeviceInfo(21L, reportRequest()));
|
||||
() -> service.reportDeviceInfo(20L, reportRequest()));
|
||||
|
||||
assertEquals("目标设备必须是尔印打印终端", exception.getMessage());
|
||||
assertEquals("来源终端必须是超市或食堂设备", exception.getMessage());
|
||||
}
|
||||
|
||||
/** 已绑定设备的部门属于一对一绑定身份,修改部门前必须先解绑。 */
|
||||
|
||||
+3
-3
@@ -9,7 +9,7 @@ public class HardPrintMsg extends MqttHardBaseMsg {
|
||||
// 用户id
|
||||
private Long userId;
|
||||
|
||||
// 设备id
|
||||
// 实际接收 MQTT 并代理 USB 打印的食堂或超市终端 ID
|
||||
private Long hardId;
|
||||
|
||||
/**
|
||||
@@ -19,9 +19,9 @@ public class HardPrintMsg extends MqttHardBaseMsg {
|
||||
private Long sourceHardId;
|
||||
|
||||
/**
|
||||
* 实际接收 MQTT 并执行 USB 打印的 EY_PRINT 终端 ID。
|
||||
* 后台绑定的 EY_PRINT 逻辑打印机资产 ID,用于客户端校验绑定关系。
|
||||
*/
|
||||
@Schema(description = "目标打印终端ID")
|
||||
@Schema(description = "逻辑打印机资产ID")
|
||||
private Long targetHardId;
|
||||
|
||||
// 设备部门id
|
||||
|
||||
Reference in new issue
Block a user