feat:对接读写卡器
feat:优化用户下拉框搜索 feat:优化下单卡顿问题 feat:优化商户列表样式
This commit is contained in:
1 parent
ceff6c8831
commit
ba7e31dbd8
3 files changed
+116
-3
No files matched your search
@@ -488,9 +488,25 @@ mixin OrderMixin {
|
||||
sqlOrderDetail.serviceUniqueCode = data.orderId;
|
||||
result = data as T;
|
||||
} else {
|
||||
final data = await HardApi.createHardwareOrder(pa);
|
||||
if (data == null) throw Error();
|
||||
if (ObjectUtil.isEmpty(data)) throw Error();
|
||||
String? data;
|
||||
try {
|
||||
data = await HardApi.createHardwareOrder(pa);
|
||||
if (data == null) throw Error();
|
||||
if (ObjectUtil.isEmpty(data)) throw Error();
|
||||
} on DioException catch (e) {
|
||||
// 统一网络层会把服务端业务拒绝(库存不足等)也包装成 DioException 抛出,
|
||||
// 只有超时/连接类异常才存在"服务端已建单扣款但响应丢失"的可能,需要先对账。
|
||||
final isTimeoutLike = e.type == DioExceptionType.connectionTimeout ||
|
||||
e.type == DioExceptionType.sendTimeout ||
|
||||
e.type == DioExceptionType.receiveTimeout ||
|
||||
e.type == DioExceptionType.connectionError;
|
||||
if (!isTimeoutLike) rethrow;
|
||||
data = await _recoverTimeoutCreateOrder(
|
||||
serviceId: serviceId!,
|
||||
order: sqlOrderDetail,
|
||||
);
|
||||
if (data == null) rethrow;
|
||||
}
|
||||
logger.i("|$_tag||有网络|创建api订单,下单成功res:|$data|");
|
||||
sqlOrderDetail.status = OrderStatus.PAY;
|
||||
sqlOrderDetail.serviceUniqueCode = data;
|
||||
@@ -596,6 +612,47 @@ mixin OrderMixin {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// 创建订单请求超时后,按终端本地订单号反查服务端订单结果。
|
||||
///
|
||||
/// 网络抖动时服务端处理可能长达数十秒,终端 10 秒就超时,但订单可能已建单扣款成功;
|
||||
/// 此结果必须找回并按成功收尾,否则收银员重试会造成重复下单。服务端已按本地订单号
|
||||
/// 幂等(重复提交返回原订单),即使对账期间收银员再次点击也不会重复扣款。
|
||||
/// 最多轮询 3 次(间隔 3 秒)等待服务端长事务提交;查到同号已支付且金额一致的订单时
|
||||
/// 返回服务端订单号,否则返回 null 由调用方按原失败流程处理。
|
||||
Future<String?> _recoverTimeoutCreateOrder({
|
||||
required String serviceId,
|
||||
required OrderEntity order,
|
||||
}) async {
|
||||
final expectedPayPrice = order.price + order.extraPrice;
|
||||
for (var attempt = 0; attempt < 3; attempt++) {
|
||||
if (attempt > 0) {
|
||||
await Future<void>.delayed(const Duration(seconds: 3));
|
||||
}
|
||||
try {
|
||||
final remote = await HardApi.getOrderByAndroidCode(
|
||||
hardId: serviceId,
|
||||
androidOrderCode: order.uniqueCode,
|
||||
);
|
||||
if (remote == null) continue;
|
||||
// 状态 5=已支付,且金额与本次结算一致才认定为本次订单。
|
||||
if (remote.orderStatus == '5' && remote.payPrice == expectedPayPrice) {
|
||||
logger.i(
|
||||
"|$_tag|超时对账命中已支付订单,orderId:|${remote.orderId}|attempt:|$attempt|",
|
||||
);
|
||||
return remote.orderId;
|
||||
}
|
||||
// 已查到订单但状态或金额不符(如已被退款、金额被调整),不再轮询等待。
|
||||
logger.w(
|
||||
"|$_tag|超时对账查到订单但状态或金额不符,orderStatus:|${remote.orderStatus}|payPrice:|${remote.payPrice}|expected:|$expectedPayPrice|",
|
||||
);
|
||||
return null;
|
||||
} catch (error) {
|
||||
logger.w("|$_tag|超时对账查询失败,attempt:|$attempt|error:|$error|");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// 支付成功后从 SQLite 重读当前食堂分类,使扣减后的库存立即展示在商品卡片上。
|
||||
///
|
||||
/// 页面刷新失败不改变已经确认的支付结果;现有 `productSync` 会在后续空闲周期重新校准
|
||||
|
||||
Reference in new issue
Block a user