feat: add enterprise order cancel open api
This commit is contained in:
@@ -65,6 +65,34 @@ class OrdersController
|
||||
return api_success($result, '运单已提交');
|
||||
}
|
||||
|
||||
public function cancel(Request $request)
|
||||
{
|
||||
try {
|
||||
$auth = (new EnterpriseOpenApiAuthService())->authenticate($request);
|
||||
} catch (\Throwable $e) {
|
||||
return api_error($e->getMessage(), 401);
|
||||
}
|
||||
|
||||
$payload = json_decode($request->rawBody(), true);
|
||||
if (!is_array($payload)) {
|
||||
return api_error('请求体必须是合法 JSON 对象', 422);
|
||||
}
|
||||
|
||||
try {
|
||||
$result = (new EnterpriseOrderService())->cancelOrder($auth['customer'], $payload);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), 422);
|
||||
} catch (\RuntimeException $e) {
|
||||
return api_error($e->getMessage(), 404);
|
||||
} catch (\Throwable $e) {
|
||||
return api_error('订单取消失败', 500, [
|
||||
'detail' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
|
||||
return api_success($result, '订单已取消');
|
||||
}
|
||||
|
||||
public function saveReturnAddress(Request $request)
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -169,6 +169,93 @@ class EnterpriseOrderService
|
||||
return $this->buildOrderProgress((int)$customer['id'], $ref, (string)$customer['customer_code']);
|
||||
}
|
||||
|
||||
public function cancelOrder(array $customer, array $payload): array
|
||||
{
|
||||
$externalOrderNo = trim((string)($payload['external_order_no'] ?? ''));
|
||||
if ($externalOrderNo === '') {
|
||||
throw new \InvalidArgumentException('external_order_no 不能为空');
|
||||
}
|
||||
|
||||
$cancelReason = trim((string)($payload['cancel_reason'] ?? ''));
|
||||
if (mb_strlen($cancelReason, 'UTF-8') > 255) {
|
||||
throw new \InvalidArgumentException('cancel_reason 不能超过 255 个字符');
|
||||
}
|
||||
|
||||
$ref = Db::name('enterprise_customer_order_refs')
|
||||
->where('customer_id', (int)$customer['id'])
|
||||
->where('external_order_no', $externalOrderNo)
|
||||
->find();
|
||||
if (!$ref) {
|
||||
throw new \RuntimeException('订单不存在');
|
||||
}
|
||||
|
||||
$now = date('Y-m-d H:i:s');
|
||||
$nodeDesc = $cancelReason === ''
|
||||
? '第三方客户取消订单。'
|
||||
: sprintf('第三方客户取消订单:%s', $cancelReason);
|
||||
$cancelled = true;
|
||||
|
||||
Db::startTrans();
|
||||
try {
|
||||
$order = Db::name('orders')->where('id', (int)$ref['order_id'])->lock(true)->find();
|
||||
if (!$order) {
|
||||
throw new \RuntimeException('订单不存在');
|
||||
}
|
||||
|
||||
if ((string)$order['order_status'] === 'cancelled') {
|
||||
$cancelled = false;
|
||||
Db::commit();
|
||||
} else {
|
||||
if ((string)$order['order_status'] !== 'pending_shipping') {
|
||||
throw new \InvalidArgumentException('当前订单状态不可取消');
|
||||
}
|
||||
|
||||
$inboundLogistics = Db::name('order_logistics')
|
||||
->where('order_id', (int)$order['id'])
|
||||
->where('logistics_type', 'send_to_center')
|
||||
->where('tracking_no', '<>', '')
|
||||
->lock(true)
|
||||
->find();
|
||||
if ($inboundLogistics) {
|
||||
throw new \InvalidArgumentException('订单已提交寄入运单,当前不可取消');
|
||||
}
|
||||
|
||||
Db::name('orders')->where('id', (int)$order['id'])->update([
|
||||
'order_status' => 'cancelled',
|
||||
'display_status' => '已取消',
|
||||
'cancelled_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
Db::name('appraisal_tasks')
|
||||
->where('order_id', (int)$order['id'])
|
||||
->where('status', 'pending')
|
||||
->delete();
|
||||
|
||||
Db::name('order_timelines')->insert([
|
||||
'order_id' => (int)$order['id'],
|
||||
'node_code' => 'cancelled',
|
||||
'node_text' => '订单已取消',
|
||||
'node_desc' => $nodeDesc,
|
||||
'operator_type' => 'system',
|
||||
'operator_id' => null,
|
||||
'occurred_at' => $now,
|
||||
'created_at' => $now,
|
||||
]);
|
||||
|
||||
Db::commit();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Db::rollback();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return [
|
||||
'cancelled' => $cancelled,
|
||||
'order' => $this->buildOrderProgress((int)$customer['id'], $ref, (string)$customer['customer_code']),
|
||||
];
|
||||
}
|
||||
|
||||
public function submitShipping(array $customer, array $payload): array
|
||||
{
|
||||
$externalOrderNo = trim((string)($payload['external_order_no'] ?? ''));
|
||||
@@ -220,69 +307,103 @@ class EnterpriseOrderService
|
||||
$updated = (bool)$existing;
|
||||
$logisticsId = 0;
|
||||
$resetLogisticsSync = false;
|
||||
$idempotentLogistics = null;
|
||||
|
||||
Db::startTrans();
|
||||
try {
|
||||
if ($existing) {
|
||||
$logisticsId = (int)$existing['id'];
|
||||
$resetLogisticsSync = true;
|
||||
Db::name('order_logistics')->where('id', $logisticsId)->update([
|
||||
'logistics_type' => 'send_to_center',
|
||||
'express_company' => $expressCompany,
|
||||
'tracking_no' => $trackingNo,
|
||||
'tracking_status' => 'submitted',
|
||||
'latest_desc' => $latestDesc,
|
||||
'latest_time' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
$nodeText = '已更新运单';
|
||||
$nodeDesc = sprintf('客户更新了寄送运单:%s %s', $expressCompany, $trackingNo);
|
||||
} else {
|
||||
$logisticsId = (int)Db::name('order_logistics')->insertGetId([
|
||||
'order_id' => (int)$order['id'],
|
||||
'logistics_type' => 'send_to_center',
|
||||
'express_company' => $expressCompany,
|
||||
'tracking_no' => $trackingNo,
|
||||
'tracking_status' => 'submitted',
|
||||
'latest_desc' => $latestDesc,
|
||||
'latest_time' => $now,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
$nodeText = '已提交运单';
|
||||
$nodeDesc = sprintf('客户已提交寄送运单:%s %s', $expressCompany, $trackingNo);
|
||||
$lockedOrder = Db::name('orders')->where('id', (int)$order['id'])->lock(true)->find();
|
||||
if (!$lockedOrder) {
|
||||
throw new \RuntimeException('订单不存在');
|
||||
}
|
||||
if ((string)$lockedOrder['order_status'] !== 'pending_shipping') {
|
||||
throw new \InvalidArgumentException('当前订单状态不支持提交运单');
|
||||
}
|
||||
|
||||
Db::name('order_logistics_nodes')->insert([
|
||||
'logistics_id' => $logisticsId,
|
||||
'node_time' => $now,
|
||||
'node_desc' => $latestDesc,
|
||||
'node_location' => '第三方',
|
||||
'created_at' => $now,
|
||||
]);
|
||||
$existing = Db::name('order_logistics')
|
||||
->where('order_id', (int)$order['id'])
|
||||
->where('logistics_type', 'send_to_center')
|
||||
->order('id', 'desc')
|
||||
->lock(true)
|
||||
->find();
|
||||
$sameLogistics = $existing
|
||||
&& (string)$existing['express_company'] === $expressCompany
|
||||
&& (string)$existing['tracking_no'] === $trackingNo;
|
||||
if ($sameLogistics) {
|
||||
$idempotentLogistics = $existing;
|
||||
Db::commit();
|
||||
} else {
|
||||
$updated = (bool)$existing;
|
||||
|
||||
Db::name('orders')->where('id', (int)$order['id'])->update([
|
||||
'display_status' => '已提交运单',
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
if ($existing) {
|
||||
$logisticsId = (int)$existing['id'];
|
||||
$resetLogisticsSync = true;
|
||||
Db::name('order_logistics')->where('id', $logisticsId)->update([
|
||||
'logistics_type' => 'send_to_center',
|
||||
'express_company' => $expressCompany,
|
||||
'tracking_no' => $trackingNo,
|
||||
'tracking_status' => 'submitted',
|
||||
'latest_desc' => $latestDesc,
|
||||
'latest_time' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
$nodeText = '已更新运单';
|
||||
$nodeDesc = sprintf('客户更新了寄送运单:%s %s', $expressCompany, $trackingNo);
|
||||
} else {
|
||||
$logisticsId = (int)Db::name('order_logistics')->insertGetId([
|
||||
'order_id' => (int)$order['id'],
|
||||
'logistics_type' => 'send_to_center',
|
||||
'express_company' => $expressCompany,
|
||||
'tracking_no' => $trackingNo,
|
||||
'tracking_status' => 'submitted',
|
||||
'latest_desc' => $latestDesc,
|
||||
'latest_time' => $now,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
$nodeText = '已提交运单';
|
||||
$nodeDesc = sprintf('客户已提交寄送运单:%s %s', $expressCompany, $trackingNo);
|
||||
}
|
||||
|
||||
Db::name('order_timelines')->insert([
|
||||
'order_id' => (int)$order['id'],
|
||||
'node_code' => 'tracking_submitted',
|
||||
'node_text' => $nodeText,
|
||||
'node_desc' => $nodeDesc,
|
||||
'operator_type' => 'system',
|
||||
'operator_id' => null,
|
||||
'occurred_at' => $now,
|
||||
'created_at' => $now,
|
||||
]);
|
||||
Db::name('order_logistics_nodes')->insert([
|
||||
'logistics_id' => $logisticsId,
|
||||
'node_time' => $now,
|
||||
'node_desc' => $latestDesc,
|
||||
'node_location' => '第三方',
|
||||
'created_at' => $now,
|
||||
]);
|
||||
|
||||
Db::commit();
|
||||
Db::name('orders')->where('id', (int)$order['id'])->update([
|
||||
'display_status' => '已提交运单',
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
Db::name('order_timelines')->insert([
|
||||
'order_id' => (int)$order['id'],
|
||||
'node_code' => 'tracking_submitted',
|
||||
'node_text' => $nodeText,
|
||||
'node_desc' => $nodeDesc,
|
||||
'operator_type' => 'system',
|
||||
'operator_id' => null,
|
||||
'occurred_at' => $now,
|
||||
'created_at' => $now,
|
||||
]);
|
||||
|
||||
Db::commit();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Db::rollback();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if ($idempotentLogistics) {
|
||||
return [
|
||||
'idempotent' => true,
|
||||
'updated' => false,
|
||||
'logistics' => $this->formatLogistics($idempotentLogistics),
|
||||
'order' => $this->buildOrderProgress((int)$customer['id'], $ref, (string)$customer['customer_code']),
|
||||
];
|
||||
}
|
||||
|
||||
$syncService = new OrderLogisticsSyncService();
|
||||
if ($resetLogisticsSync) {
|
||||
Db::name('order_logistics_syncs')->where('logistics_id', $logisticsId)->delete();
|
||||
|
||||
Reference in New Issue
Block a user