完成了基本调整调整

This commit is contained in:
2026-09-18 20:55:21 +08:00
parent 864187e105
commit 57e0854a0e
56 changed files with 3122 additions and 105 deletions
@@ -340,58 +340,91 @@ class CallbackQueue extends Command
continue;
}
$payTime = !empty($c['pay_time']) ? (strtotime($c['pay_time']) ?: time()) : time();
// 落消费流水(uk_consume 去重:重复回调直接忽略)
// 一单可以分多次加油:每条推送是一次加油,consume_amount = 本次占用运单金额(分)
$consumeFen = (int)($c['consume_amount'] ?? 0);
$consumeYuan = number_format($consumeFen / 100, 2, '.', '');
$orderCode = trim((string)($c['order_code'] ?? ''));
// 去重键:文档里 order_code 是选填,缺失时用本笔消费的特征字段做指纹,
// 否则同一运单的第二笔加油会被唯一键误判为重复推送而丢掉(口径与迁移脚本回填一致)
$consumeKey = $orderCode !== '' ? $orderCode : 'FP' . md5(implode('|', [
$c['quota_id'] ?? '', $c['pay_time'] ?? '', $c['consume_amount'] ?? '',
$c['pay_fee'] ?? '', $c['station_code'] ?? '', $c['litter'] ?? '',
]));
$consumeId = 0;
try {
Db::name('qyt_consume')->insert([
'order_id' => $order['order_id'],
'waybill_no' => $c['waybill_no'] ?? '',
'waybill_no_code' => $code,
'order_code' => $c['order_code'] ?? '',
'station_code' => $c['station_code'] ?? '',
'station_name' => $c['station_name'] ?? '',
'oil_name' => $c['oil_name'] ?? '',
'litter' => $c['litter'] ?? '',
'oil_price' => (int)($c['oil_price'] ?? 0),
'actual_oil_price' => (int)($c['actual_oil_price'] ?? 0),
'pay_fee' => (int)($c['pay_fee'] ?? 0),
'consume_amount' => (int)($c['consume_amount'] ?? 0),
'pay_time' => $payTime,
'raw' => json_encode($c, 320),
'store_id' => $order['store_id'],
'create_time' => time(),
]);
// 流水落库与订单累计放在同一事务:唯一键挡住重推,重推既不重复累计也不重复通知
Db::transaction(function () use ($order, $c, $code, $orderCode, $consumeKey, $payTime, $consumeFen, $consumeYuan, &$consumeId) {
$consumeId = (int)Db::name('qyt_consume')->insertGetId([
'order_id' => $order['order_id'],
'waybill_no' => $c['waybill_no'] ?? '',
'waybill_no_code' => $code,
'order_code' => $orderCode,
'consume_key' => $consumeKey,
'station_code' => $c['station_code'] ?? '',
'station_name' => $c['station_name'] ?? '',
'oil_name' => $c['oil_name'] ?? '',
'litter' => $c['litter'] ?? '',
'oil_price' => (int)($c['oil_price'] ?? 0),
'actual_oil_price' => (int)($c['actual_oil_price'] ?? 0),
'pay_fee' => (int)($c['pay_fee'] ?? 0),
'consume_amount' => $consumeFen,
'pay_time' => $payTime,
'raw' => json_encode($c, 320),
'store_id' => $order['store_id'],
'create_time' => time(),
]);
// 累计已加油金额 / 次数,并记下最近一次加油信息(原子自增,不读后写)
Db::name('partners_order')->where('order_id', $order['order_id'])->update([
'used_amount' => Db::raw('`used_amount` + ' . $consumeYuan),
'used_num' => Db::raw('`used_num` + 1'),
'use_text' => '加油',
'qyt_order_code' => $orderCode,
'station_name' => $c['station_name'] ?? '',
'oil_name' => $c['oil_name'] ?? '',
'litter' => $c['litter'] ?? '',
'pay_fee' => (int)($c['pay_fee'] ?? 0),
'consume_time' => $payTime,
'update_time' => time(),
]);
// use_status 语义不变(0 未加油 / 1 有加油记录):只在第一笔加油时置 1 并记首次加油时间
Db::name('partners_order')->where('order_id', $order['order_id'])->where('use_status', 0)->update([
'use_status' => 1,
'use_time' => time(),
'shareNo' => $orderCode !== '' ? $orderCode : $order['shareNo'],
]);
});
} catch (\Exception $e) {
if (strpos($e->getMessage(), 'Duplicate') === false) {
throw $e;
}
$SybOil->saveLogStore('企油通消费回调重复,忽略流水:' . $code . '/' . ($c['order_code'] ?? ''));
$SybOil->saveLogStore('企油通消费回调重复,忽略(不重复累计、不重复通知):' . $code . '/' . $consumeKey);
continue;
}
// 条件跃迁 use_status 0 -> 1(要求已发放),仅胜出者通知下单平台
$affected = Db::name('partners_order')->where('order_id', $order['order_id'])
->where('use_status', 0)
->where('oil_status', 1)
->update([
'use_status' => 1,
'use_time' => time(),
'use_text' => '加油',
'qyt_order_code' => $c['order_code'] ?? '',
'shareNo' => $c['order_code'] ?: $order['shareNo'],
'station_name' => $c['station_name'] ?? '',
'oil_name' => $c['oil_name'] ?? '',
'litter' => $c['litter'] ?? '',
'pay_fee' => (int)($c['pay_fee'] ?? 0),
'consume_time' => $payTime,
'update_time' => time(),
]);
if ($affected) {
$queueService = new QueueService();
$queueService->push('notify_queue', json_encode([
'order_id' => $order['order_id'],
'optType' => 'add_oil',
'retry_count' => 0,
], 320));
$SybOil->saveLogStore('企油通消费回调处理成功:' . json_encode($c, 320));
// 超额告警:累计加油 + 已退款 > 订单金额。上游额度按司机凭证累计,
// 归属到本单的消费可能与本地可退金额算出的不一致,需要人工核对
$fresh = Db::name('partners_order')->where('order_id', $order['order_id'])
->field('total_price,used_amount,refund_amount,oil_status_zsy')->find();
if ($fresh && (float)$fresh['used_amount'] + (float)$fresh['refund_amount'] > (float)$fresh['total_price'] + 0.005) {
$SybOil->saveLogStore('【告警】订单已加油+已退款超出订单金额 order=' . $order['order_id']
. ' total=' . $fresh['total_price'] . ' used=' . $fresh['used_amount'] . ' refund=' . $fresh['refund_amount']);
}
// 每笔加油都通知下单平台(amount = 本次占用金额)
$notify = json_encode([
'order_id' => $order['order_id'],
'optType' => 'add_oil',
'consume_id' => $consumeId,
'retry_count' => 0,
], 320);
$queueService = new QueueService();
if ((int)($fresh['oil_status_zsy'] ?? 2) === 2) {
$queueService->push('notify_queue', $notify);
} else {
// 7.8 发放结果还没确认就先收到了加油:延后 60 秒再通知,尽量让「分油成功」通知先到下游
$queueService->laterPush('notify_queue', $notify, 60);
}
$SybOil->saveLogStore('企油通消费回调处理成功:' . json_encode($c, 320));
}
break;
default:
+29 -5
View File
@@ -87,12 +87,31 @@ class NotifyQueue extends Command
return false;
}
$partnersOil = new PartnersOil();
$optType = (string)($data['optType'] ?? '');
// 加油:一单可多次加油,每笔单独通知。消息里带 consume_id 时推这一笔的占用金额和消费单号;
// 老消息没有 consume_id(上线前入队的)则沿用旧口径推订单金额
$consume = null;
if ($optType == 'add_oil' && !empty($data['consume_id'])) {
$consume = Db::name('qyt_consume')->where('id', (int)$data['consume_id'])->find();
}
if ($optType == 'refund') {
$amount = $order['refund_amount'];
} elseif ($consume) {
$amount = number_format((int)$consume['consume_amount'] / 100, 2, '.', '');
} else {
$amount = $order['total_price'];
}
$data = [
'oilCardNo' => $order['oilCardNo'],
'amount' => $order['total_price'],
'shareNo' => $order['shareNo'],
'type' => $data['optType'] == 'share_oil' ? 'add' : 'sub',
'optType' => $data['optType'],
// 分油:订单金额;加油:本次加油占用金额;退款:退款金额
'amount' => $amount,
// 订单实付金额(即分油金额),所有场景都带,方便对接方拿 amount 对照参考
'orderAmount' => number_format((float)$order['total_price'], 2, '.', ''),
'shareNo' => $consume && $consume['order_code'] !== '' ? $consume['order_code'] : $order['shareNo'],
'type' => $optType == 'share_oil' ? 'add' : 'sub',
'optType' => $optType,
];
$header['method'] = 'syb.notify.oilCard.change';
$res = $partnersOil->sendRequest($partners, $partners['callback'], $data, $header);
@@ -103,11 +122,16 @@ class NotifyQueue extends Command
'oil_callback' => 1,
'oil_callback_time' => time(),
]);
}else{
}elseif($data['optType'] == 'add_oil'){
// 退款通知成功不记 use_callback,避免把「加油已回调」标错
$order->save([
'use_callback' => 1,
'use_callback_time' => time(),
]);
// 逐笔记录这一笔加油已通知
if ($consume) {
Db::name('qyt_consume')->where('id', $consume['id'])->update(['notify_status' => 1, 'notify_time' => time()]);
}
}
return true;
}