抖音订单
This commit is contained in:
parent
f8acc18abe
commit
6759df85c9
|
@ -182,9 +182,17 @@
|
|||
>
|
||||
同步
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="scope.row.is_direct_mode && scope.row.appointment_status == 1"
|
||||
size="small"
|
||||
icon="el-icon-thumb"
|
||||
@click="dyOrderConfirm(scope.row)"
|
||||
>
|
||||
确认接单
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
v-if="scope.row.appointment_status == 1"
|
||||
v-if="scope.row.appointment_status == 1 && !scope.row.is_direct_mode"
|
||||
size="small"
|
||||
icon="el-icon-edit"
|
||||
@click="onOneClickYyHandle(scope.row)"
|
||||
|
@ -1031,6 +1039,24 @@ export default {
|
|||
});
|
||||
});
|
||||
},
|
||||
dyOrderConfirm(item) {
|
||||
this.$axios
|
||||
.post("/admin/order/dyOrderConfirm", { id: item.id })
|
||||
.then((res) => {
|
||||
this.$notify({
|
||||
title: "成功",
|
||||
message: "接单成功",
|
||||
type: "success",
|
||||
});
|
||||
// this.getList();
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$notify.error({
|
||||
title: "接单失败",
|
||||
message: err,
|
||||
});
|
||||
});
|
||||
},
|
||||
onOneClickYyHandle(item) {
|
||||
this.$axios
|
||||
.post("/admin/order/changeAppointmentStatus", { id: item.id })
|
||||
|
|
|
@ -40,8 +40,8 @@ module.exports = {
|
|||
"/dev-api": {
|
||||
// 接口地址 以 api开头的都走下面的配置
|
||||
// target: 'https://www.szjinao.cn', // 代理目标地址为后端服务器地址 127.0.0.1 192.168.1.2
|
||||
// target: "http://hex.jipinq.cn", // 代理目标地址为后端服务器地址 127.0.0.1 192.168.1.2
|
||||
target: "http://192.168.0.100:8787",
|
||||
target: "http://hex.jipinq.cn", // 代理目标地址为后端服务器地址 127.0.0.1 192.168.1.2
|
||||
// target: "http://192.168.0.100:8787",
|
||||
ws: true, // 是否支持 websocket 请求 支持
|
||||
changeOrigin: true, // 是否启用跨域
|
||||
pathRewrite: {
|
||||
|
|
|
@ -119,16 +119,16 @@ class DataController extends base
|
|||
$totalArr[1]['month_write_num'] += $list[$k]['month_write_num'];
|
||||
}
|
||||
if (isset($totalArr[1]['orders']) && $totalArr[1]['orders'] > 0) {
|
||||
$totalArr[1]['write_rate'] = $totalArr[1]['orders'] ?: (float)number_format(($totalArr[1]['assets']/$totalArr[1]['orders'])*100,2);
|
||||
$totalArr[1]['write_rate'] = (float)number_format(($totalArr[1]['assets']/$totalArr[1]['orders'])*100,2);
|
||||
}
|
||||
if (isset($totalArr[1]['total_price']) && $totalArr[1]['total_price'] > 0) {
|
||||
$totalArr[1]['write_rate_price'] = $totalArr[1]['total_price'] ?: (float)number_format(($totalArr[1]['asset_price']/$totalArr[1]['total_price'])*100,2);
|
||||
$totalArr[1]['write_rate_price'] = (float)number_format(($totalArr[1]['asset_price']/$totalArr[1]['total_price'])*100,2);
|
||||
}
|
||||
if (isset($totalArr[1]['m_orders']) && $totalArr[1]['m_orders'] > 0) {
|
||||
$totalArr[1]['month_write_rate'] = $totalArr[1]['m_orders'] ?: (float)number_format(($totalArr[1]['m_assets']/$totalArr[1]['m_orders'])*100,2);
|
||||
$totalArr[1]['month_write_rate'] = (float)number_format(($totalArr[1]['m_assets']/$totalArr[1]['m_orders'])*100,2);
|
||||
}
|
||||
if (isset($totalArr[1]['m_total_price']) && $totalArr[1]['m_total_price'] > 0) {
|
||||
$totalArr[1]['month_write_rate_price'] = $totalArr[1]['m_total_price'] ?: (float)number_format(($totalArr[1]['m_asset_price']/$totalArr[1]['m_total_price'])*100,2);
|
||||
$totalArr[1]['month_write_rate_price'] = (float)number_format(($totalArr[1]['m_asset_price']/$totalArr[1]['m_total_price'])*100,2);
|
||||
}
|
||||
$list = array_merge($list->toArray(), $totalArr);
|
||||
|
||||
|
|
|
@ -196,4 +196,4 @@ class LiveRoomController extends base {
|
|||
$data = LiveRoomWorks::staticOrder(3, 38, '2024-09-17 16:00:00', '2024-09-18 15:59:59');
|
||||
return $this->success($data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,12 @@ require_once(__DIR__.'/xlsxwriter.class.php');
|
|||
|
||||
use app\model\Admins;
|
||||
use app\model\Backs;
|
||||
use app\model\Blacks;
|
||||
use app\model\DyOrderProductAppointments;
|
||||
use app\model\DyOrderProducts;
|
||||
use app\model\Follows;
|
||||
use app\model\Orders;
|
||||
use app\model\Logs;
|
||||
use app\model\ThirdMobileLogs;
|
||||
use app\server\SMS;
|
||||
use app\server\DyApiService;
|
||||
use app\server\ThirdApiService;
|
||||
use app\server\Orders as ServerOrders;
|
||||
use stdClass;
|
||||
|
@ -678,4 +678,119 @@ class OrderController extends base
|
|||
return $this->error(2006, '出错了:' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取预约信息
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function getAppointInfo(Request $request) {
|
||||
try {
|
||||
$id = $request->get('id', 0);
|
||||
$order = Orders::where('id', $id)->find();
|
||||
if (empty($order)) {
|
||||
return $this->error(2004, '记录没有找到.');
|
||||
}
|
||||
|
||||
// 抖音预约信息
|
||||
$appoint = DyOrderProductAppointments::query()->where(['dy_order_id' => $order['sn']])->find();
|
||||
return $this->success($appoint);
|
||||
}catch(\Exception $e) {
|
||||
return $this->error(2006, '出错了:' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 抖音确认订单
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function dyOrderConfirm(Request $request) {
|
||||
try {
|
||||
$id = $request->post('id', 0);
|
||||
$order = Orders::where('id', $id)->find();
|
||||
if (empty($order)) {
|
||||
return $this->error(2004, '记录没有找到.');
|
||||
}
|
||||
// 1:接单 2:拒单
|
||||
// if (!$request->post('confirm_result') || !in_array($request->post('confirm_result'), [1, 2])) {
|
||||
// return $this->error(2005, '确认状态错误');
|
||||
// }
|
||||
// 抖音预约信息
|
||||
$appoint = DyOrderProductAppointments::query()->where(['source_order_id' => $order['sn']])->find();
|
||||
if (empty($appoint)) {
|
||||
return $this->error(2004, '该订单暂未预约,不可接单');
|
||||
}
|
||||
$dyOrderProduct = DyOrderProducts::query()->where(['dy_order_id' => $order['sn']])->find();
|
||||
if (empty($dyOrderProduct)) {
|
||||
return $this->error(2004, '订单商品未找到,不可接单');
|
||||
}
|
||||
|
||||
$jnCategoryIds = [
|
||||
"18004001", "18004003", "18004004", "18004005", "18004006", "18004007", "18004008", "18004009",
|
||||
"18004010", "18003004", "4015004", "18003001", "18003002", "18003003", "18010001", "32001001",
|
||||
"18002001", "18011001", "18011002", "18012001", "18012002", "18010001", "32001001", "32006002",
|
||||
"32007001", "32007002", "32007003",
|
||||
];
|
||||
$zyxCategoryIds = ['32002001', '18010002', '32006001'];
|
||||
|
||||
$confirmData = [
|
||||
'order_id' => $appoint->dy_order_id,
|
||||
'source_order_id' => $appoint->source_order_id,
|
||||
'confirm_info' => [
|
||||
'confirm_result' => $request->post('confirm_result', 1),
|
||||
'reject_code' => $request->post('reject_code'), // 1: 库存已约满 2:商品需加价 3:无法满足顾客需求
|
||||
// 'hotel_info' => [], // 境内住宿类目/酒景套餐 必填
|
||||
// 'play_info' => [], // 境内游玩类目 必填
|
||||
// 'free_travel_info' => $freeTravelInfo, // 自由行类目 必填
|
||||
],
|
||||
];
|
||||
// 自由行必填参数
|
||||
$dyApiService = new DyApiService();
|
||||
if (in_array($dyOrderProduct->category_id, $zyxCategoryIds)) {
|
||||
$onedayTourList = [];
|
||||
foreach ($dyOrderProduct->travel_details as $k => $travel_detail) {
|
||||
array_push($onedayTourList, [
|
||||
'sequence' => $k+1,
|
||||
'hotel_info_list' => [],
|
||||
'play_info_list' => []
|
||||
]);
|
||||
}
|
||||
$confirmData['confirm_info']['free_travel_info']['oneday_tour_list'] = $onedayTourList;
|
||||
}
|
||||
if (in_array($dyOrderProduct->category_id, $jnCategoryIds)) {
|
||||
// 获取poi信息
|
||||
$poiRes = $dyApiService->send(DyApiService::POI_QUERY, ['order_id' => $order->sn, 'account_id' => env('DY_ACCOUNT_ID')]);
|
||||
$payInfo = [
|
||||
'entrance_types' => [3],
|
||||
'poi_info' => $poiRes['data']['poi_list'] ?? []
|
||||
];
|
||||
$showCerts = [];
|
||||
if (isset($appoint['book_info'])) {
|
||||
$bookInfo = json_decode(json_encode($appoint['book_info']), true);
|
||||
foreach ($bookInfo['occupancies'] as $info) {
|
||||
array_push($showCerts, [
|
||||
'name' => $info['name'],
|
||||
'card_no' => $info['license_id'] ?? '',
|
||||
'cert_no' => $info['cert_no'] ?? '',
|
||||
]);
|
||||
}
|
||||
}
|
||||
$payInfo['show_certs'] = $showCerts;
|
||||
$confirmData['confirm_info']['play_info'] = $payInfo;
|
||||
}
|
||||
|
||||
$res = $dyApiService->send(DyApiService::ORDER_CONFIRM, $confirmData);
|
||||
if ($res['flag'] == true) {
|
||||
// 预约成功,更新预约状态
|
||||
$order->appointment_status = 2;
|
||||
$order->save();
|
||||
|
||||
return $this->success($res);
|
||||
}
|
||||
return $this->error(2005, $res['data']['description']);
|
||||
}catch(\Exception $e) {
|
||||
return $this->error(2006, '出错了:' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,425 @@
|
|||
<?php
|
||||
namespace app\api\controller;
|
||||
|
||||
use app\model\Admins;
|
||||
use app\model\DyOrderProductAppointments;
|
||||
use app\model\DyOrderProducts;
|
||||
use app\model\DyOrders;
|
||||
use app\model\Orders;
|
||||
use app\model\Products;
|
||||
use support\Log;
|
||||
use support\Request;
|
||||
use think\facade\Db;
|
||||
|
||||
/**
|
||||
* 抖音回调处理
|
||||
*/
|
||||
class DyNotifyController extends base {
|
||||
/**
|
||||
* 创建预售订单
|
||||
* @param Request $request
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function orderCreate(Request $request) {
|
||||
try {
|
||||
$params = $request->all();
|
||||
Log::info('orderCreate params:' . json_encode($params));
|
||||
if (!empty($order = DyOrders::query()->where(['dy_order_id' => $params['order_id']])->find())) {
|
||||
return $this->success(['order_out_id' => $order->order_id, 'order_id' => $order->dy_order_id]);
|
||||
}
|
||||
|
||||
$orderId = getNewOrderId('Dy');
|
||||
$orderData = [
|
||||
'order_id' => $orderId,
|
||||
'dy_order_id' => $params['order_id'],
|
||||
'biz_type' => $params['biz_type'] ?? '',
|
||||
'total_amount' => $params['total_amount'] ?? 0,
|
||||
'total_coupon_count' => $params['total_coupon_count'] ?? 0,
|
||||
'each_coupon_amount' => $params['each_coupon_amount'] ?? 0,
|
||||
'pay_amount' => $params['pay_amount'] ?? 0,
|
||||
'actual_amount' => $params['actual_amount'] ?? 0,
|
||||
'merchant_discount_amount' => $params['merchant_discount_amount'] ?? 0,
|
||||
'pay_time_unix' => $params['pay_info']['pay_time_unix'] ?? 0,
|
||||
'status' => 0,
|
||||
'phone' => $this->decrypt($params['buyer_info']['phone'], env('DY_APPSECRET')),
|
||||
];
|
||||
// 已支付
|
||||
if ($orderData['pay_time_unix']) {
|
||||
$orderData['status'] = 10;
|
||||
}
|
||||
$res = DyOrders::create($orderData);
|
||||
Log::info('res:' . json_encode($res));
|
||||
if (!empty($res) && isset($params['product_snap_shot']) && !empty($params['product_snap_shot'])) {
|
||||
$orderProducts = [];
|
||||
foreach ($params['product_snap_shot'] as $product) {
|
||||
array_push($orderProducts, [
|
||||
'dy_order_id' => $orderData['dy_order_id'],
|
||||
'sku_id' => $product['sku_id'] ?? '',
|
||||
'product_id' => $product['product_id'] ?? '',
|
||||
'out_product_id' => $product['out_product_id'] ?? '',
|
||||
'name' => $product['name'] ?? '',
|
||||
'category_id' => $product['category_id'] ?? '',
|
||||
'category_full_name' => $product['category_full_name'] ?? '',
|
||||
'travel_details' => json_encode($product['travel_details'] ?? []),
|
||||
'commodity' => json_encode($product['commodity'] ?? []),
|
||||
'is_superimposed_discounts' => $product['is_superimposed_discounts'] ? 1: 0,
|
||||
'date_add_price_rule' => isset($product['date_add_price_rule']) ? json_encode($product['date_add_price_rule']) : '',
|
||||
'user_add_price_rule' => isset($product['user_add_price_rule']) ? json_encode($product['user_add_price_rule']) : '',
|
||||
'room_add_price_rule' => isset($product['room_add_price_rule']) ? json_encode($product['room_add_price_rule']) : '',
|
||||
'room_upgrade_rule' => isset($product['room_upgrade_rule']) ? json_encode($product['room_upgrade_rule']) : '',
|
||||
'add_price_policy' => isset($product['add_price_policy']) ? json_encode($product['add_price_policy']) : '',
|
||||
'description_rich_text' => isset($product['description_rich_text']) ? json_encode($product['description_rich_text']) : '',
|
||||
'fee_include' => isset($product['fee_include']) ? json_encode($product['fee_include']) : '',
|
||||
'fee_not_include' => isset($product['fee_not_include']) ? json_encode($product['fee_not_include']) : '',
|
||||
'self_pay_expense_rule' => isset($product['self_pay_expense_rule']) ? json_encode($product['self_pay_expense_rule']) : '',
|
||||
'earliest_appointment' => isset($product['earliest_appointment']) ? json_encode($product['earliest_appointment']) : '',
|
||||
'appointment' => isset($product['appointment']) ? json_encode($product['appointment']) : '',
|
||||
'refund_rule' => isset($product['refund_rule']) ? json_encode($product['refund_rule']) : '',
|
||||
'use_date' => isset($product['use_date']) ? json_encode($product['use_date']) : '',
|
||||
'refund_description' => isset($product['refund_description']) ? json_encode($product['refund_description']) : '',
|
||||
'merchant_break_rule' => isset($product['merchant_break_rule']) ? json_encode($product['merchant_break_rule']) : '',
|
||||
'merchant_break_description' => isset($product['merchant_break_description']) ? json_encode($product['merchant_break_description']) : '',
|
||||
'presale_appointment_cancel_policy' => isset($product['presale_appointment_cancel_policy']) ? json_encode($product['presale_appointment_cancel_policy']) : '',
|
||||
]);
|
||||
}
|
||||
|
||||
Log::info('orderProducts:' . json_encode($orderProducts));
|
||||
// 批量插入
|
||||
/** @var DyOrderProducts $dyOrderProducts */
|
||||
$dyOrderProducts = (new DyOrderProducts());
|
||||
$dyOrderProducts->insertAll($orderProducts);
|
||||
|
||||
if ($orderData['status'] == 10) {
|
||||
$this->createPlatformOrder($orderData, $orderProducts[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// order_out_id - 第三方订单ID, order_id - 抖音订单号
|
||||
return $this->success(['order_out_id' => $orderId, 'order_id' => $params['order_id']]);
|
||||
} catch (\Exception $exception) {
|
||||
return $this->error('-1', $exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 通知支付结果
|
||||
public function pay(Request $request) {
|
||||
try {
|
||||
$params = $request->all();
|
||||
// Validator::input($params, [
|
||||
// 'order_id' => Validator::notEmpty()->setName('订单号'),
|
||||
// 'biz_type' => Validator::notEmpty()->setName('旅行社预售券'),
|
||||
// 'pay_amount' => Validator::notEmpty()->setName('支付金额'),
|
||||
// 'pay_time_unix' => Validator::notEmpty()->setName('支付时间'),
|
||||
// ]);
|
||||
Log::info('pay params:' . json_encode($params));
|
||||
// » biz_type - 旅行社预售券:3011;旅行社预定订单:3012
|
||||
// » pay_amount 用户实付金额(分)
|
||||
// » pay_time_unix 支付时间戳
|
||||
if (isset($params['biz_type']) && $params['biz_type'] == 3012) {
|
||||
if (empty($order = DyOrderProductAppointments::query()->where(['dy_order_id' => $params['source_order_id']])->find())) {
|
||||
return $this->error('-2', '订单信息未找到');
|
||||
}
|
||||
$res = DyOrderProductAppointments::query()->where(['order_id' => $params['order_id']])->update(['pay_amount' => $params['pay_amount'] ?? 0]);
|
||||
} else {
|
||||
if (empty($order = DyOrders::query()->where(['dy_order_id' => $params['source_order_id']])->find())) {
|
||||
return $this->error('-2', '订单信息未找到');
|
||||
}
|
||||
$res = DyOrders::query()->where(['dy_order_id' => $params['order_id']])->update(['status' => 10, 'pay_amount' => $params['pay_amount'], 'pay_time_unix' => $params['pay_time_unix']]);
|
||||
$orderProduct = DyOrderProducts::query()->where(['dy_order_id' => $params['order_id']])->find();
|
||||
if (!$res) {
|
||||
$this->createPlatformOrder($order, $orderProduct);
|
||||
}
|
||||
}
|
||||
if ($res) {
|
||||
return $this->success([]);
|
||||
} else {
|
||||
return $this->error('-2', '操作失败');
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
return $this->error('-1', $exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $order
|
||||
* @param $orderProduct
|
||||
* @return Orders
|
||||
*/
|
||||
private function createPlatformOrder($order, $orderProduct) {
|
||||
$item = Orders::query()->where(['sn' => $order['dy_order_id']])->find();
|
||||
if (!empty($item)) {
|
||||
return $item;
|
||||
}
|
||||
// 查找用户归属
|
||||
$product = Products::query()->where('third_product_id', $orderProduct['product_id'])->find();
|
||||
$adminId = 0;
|
||||
if (!empty($product)) {
|
||||
$adminId = Admins::where('status', 1)->whereFindInSet('product_ids', $product->id)->value('id');
|
||||
}
|
||||
|
||||
// 订单支付成功,写入平台订单表
|
||||
$item = new Orders();
|
||||
$item->os = 5;
|
||||
$item->sn = $order['dy_order_id'];
|
||||
$item->product_id = $orderProduct['product_id'];
|
||||
$item->product_name = $orderProduct['name'];
|
||||
$item->category_id = $orderProduct['category_id'];
|
||||
$item->create_at = $order['pay_time_unix'] * 1000;
|
||||
$item->mobile = $order['phone'] ?? null;
|
||||
$item->unit_price = $order['pay_amount'];
|
||||
$item->total_price = $order['pay_amount'];
|
||||
$item->actual_price = $order['pay_amount'];
|
||||
$item->quantity = $order['total_coupon_count'];
|
||||
$item->order_status = 1;
|
||||
$item->asset_status = 0;
|
||||
$item->category_desc = $orderProduct['category_full_name'];
|
||||
$item->asset_price = 0;
|
||||
$item->is_refunded = 0; // 是否已退款(1-已退款,0-未退款)
|
||||
$item->admin_id = $adminId;
|
||||
$item->is_direct_mode = 1; // 是否直连模式(0-否,1-是)
|
||||
$item->save();
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理预约信息
|
||||
* @param $params
|
||||
* @return array
|
||||
*/
|
||||
private function handleBookInfo($params) {
|
||||
$bookInfo = [];
|
||||
if (isset($params['book_info']) && !empty($params['book_info'])) {
|
||||
$bookInfo = $params['book_info'];
|
||||
if (isset($bookInfo['occupancies']) && is_array($bookInfo['occupancies'])) {
|
||||
foreach ($bookInfo['occupancies'] as &$occupancy) {
|
||||
if (isset($occupancy['name']) && !empty($occupancy['name'])) {
|
||||
$occupancy['name'] = $this->decrypt($occupancy['name'], env('DY_APPSECRET'));
|
||||
}
|
||||
if (isset($occupancy['license_id']) && !empty($occupancy['license_id'])) {
|
||||
$occupancy['license_id'] = $this->decrypt($occupancy['license_id'], env('DY_APPSECRET'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $bookInfo;
|
||||
}
|
||||
|
||||
// 用户创建预约订单
|
||||
public function userMakeAppointment(Request $request) {
|
||||
$params = $request->all();
|
||||
Log::info('userMakeAppointment params:' . json_encode($params));
|
||||
$bookInfo = $this->handleBookInfo($params);
|
||||
$orderData = [
|
||||
'dy_order_id' => $params['order_id'] ?? '',
|
||||
'source_order_id' => $params['source_order_id'] ?? '',
|
||||
'presale_coupon_id' => $params['presale_coupon_id'] ?? '',
|
||||
'out_presale_coupon_id' => $params['out_presale_coupon_id'] ?? '',
|
||||
'biz_type' => $params['biz_type'] ?? 0,
|
||||
'pay_amount' => $params['pay_amount'] ?? 0,
|
||||
'actual_amount' => $params['actual_amount'] ?? 0,
|
||||
'merchant_discount_amount' => $params['merchant_discount_amount'] ?? 0,
|
||||
'discount_amount' => $params['discount_amount'] ?? 0,
|
||||
'original_amount' => $params['original_amount'] ?? 0,
|
||||
'pay_info' => isset($params['pay_info']) ? json_encode($params['pay_info']) : '',
|
||||
'book_info' => $bookInfo,
|
||||
'buyer_info' => isset($params['buyer_info']) ? json_encode($params['buyer_info']) : '',
|
||||
'remark_from_guest' => $params['remark_from_guest'],
|
||||
];
|
||||
if (empty($order = DyOrders::query()->where(['dy_order_id' => $orderData['source_order_id']])->find())) {
|
||||
return $this->error('-2', '订单信息未找到');
|
||||
}
|
||||
$orderData['appoint_order_id'] = getNewOrderId('Yy');
|
||||
if (!empty($appoint = DyOrderProductAppointments::query()->where(['dy_order_id' => $orderData['dy_order_id']])->find())) {
|
||||
return $this->success(['order_id' => $appoint->dy_order_id, 'order_out_id' => $appoint->appoint_order_id]);
|
||||
}
|
||||
|
||||
// biz_type - 旅行社预售券:3011;旅行社预定订单:3012
|
||||
$res = DyOrderProductAppointments::create($orderData);
|
||||
if ($res) {
|
||||
// 更新平台订单表
|
||||
Orders::query()->where('sn', $params['source_order_id'])->update(['appointment_status' => 1, 'travel_date' => $bookInfo['book_start_date']]);
|
||||
return $this->success(['order_id' => $orderData['dy_order_id'], 'order_out_id' => $orderData['appoint_order_id']]);
|
||||
} else {
|
||||
return $this->error('-1');
|
||||
}
|
||||
}
|
||||
|
||||
// 用户取消订单
|
||||
public function userCancelOrder(Request $request) {
|
||||
$params = $request->all();
|
||||
Log::info('userCancelOrder params:' . json_encode($params));
|
||||
if (!isset($params['order_id']) || empty($params['order_id'])) {
|
||||
throw new \Exception('订单号缺失');
|
||||
}
|
||||
if (isset($params['biz_type']) && $params['biz_type'] == 3012) {
|
||||
// 取消预约
|
||||
$appoint = DyOrderProductAppointments::query()->where('dy_order_id', $params['order_id'])->find();
|
||||
Orders::query()->where('sn', $appoint['source_order_id'])->update(['appointment_status' => 0, 'travel_date' => null]);
|
||||
return $this->success([]);
|
||||
}
|
||||
if (empty($order = Orders::query()->where(['sn' => $params['order_id']])->find())) {
|
||||
return $this->error('-2', '订单信息未找到');
|
||||
}
|
||||
|
||||
// » refund_type 枚举值:1、订单退款,2、补差价退款
|
||||
$res = Db::transaction(function () use ($order, $params) {
|
||||
DyOrders::query()->where('dy_order_id', $params['order_id'])->update(['status' => 30]);
|
||||
// 更新平台订单表
|
||||
if ($order->order_status < 3) {
|
||||
Orders::query()->where('sn', $params['order_id'])->update(['order_status' => 3]);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if ($res) {
|
||||
return $this->success([]);
|
||||
}
|
||||
|
||||
return $this->error('-1', '取消失败');
|
||||
}
|
||||
|
||||
// 订单退款结果通知
|
||||
public function orderRefundNotify(Request $request) {
|
||||
$params = $request->all();
|
||||
Log::info('orderRefundNotify params:' . json_encode($params));
|
||||
if (!isset($params['order_id']) || empty($params['order_id'])) {
|
||||
throw new \Exception('订单号缺失');
|
||||
}
|
||||
|
||||
if (isset($params['biz_type']) && $params['biz_type'] == 3012) {
|
||||
// 取消预约退款, 暂不处理
|
||||
return $this->success([]);
|
||||
}
|
||||
|
||||
if (empty($order = DyOrders::query()->where(['dy_order_id' => $params['order_id']])->find())) {
|
||||
return $this->error('-2', '订单信息未找到');
|
||||
}
|
||||
|
||||
$res = Db::transaction(function () use ($order, $params) {
|
||||
DyOrders::query()->where(['order_id' => $params['order_id']])->update(['status' => 40]);
|
||||
// 更新平台订单表
|
||||
Orders::query()->where(['sn' => $params['order_id']])->update(['order_status' => 4, 'is_refunded' => 1, 'refund_status' => 3]);
|
||||
return true;
|
||||
});
|
||||
|
||||
if ($res) {
|
||||
return $this->success([]);
|
||||
}
|
||||
|
||||
return $this->error('-1', '取消失败');
|
||||
}
|
||||
|
||||
public function success($data,$mess = null, $ext = null) {
|
||||
$res = [
|
||||
'error_code' => 0,
|
||||
'description' => 'success',
|
||||
];
|
||||
if (isset($data['order_id'])) {
|
||||
$res['order_id'] = $data['order_id'];
|
||||
}
|
||||
if (isset($data['order_out_id'])) {
|
||||
$res['order_out_id'] = $data['order_out_id'];
|
||||
}
|
||||
return json([
|
||||
'data' => $res
|
||||
]);
|
||||
}
|
||||
|
||||
public function error($code, $mess = null) {
|
||||
$res = [
|
||||
'error_code' => $code,
|
||||
'description' => $mess,
|
||||
];
|
||||
return json([
|
||||
'data' => $res
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
1.根据ClientKev找到ClientSecret,将ClientSecret向左右使用字符补齐32位/裁剪至32位,补齐:补位字符:#,先补左侧再补右侧再补左侧………直到补满32位。
|
||||
裁剪:先裁剪左侧再裁右侧再裁左侧………直到剩余32位。(正常不需要补齐,secret默认为32位,此举是为了
|
||||
以防万一)
|
||||
2.将ClientSecret作为Key,右侧16位为向量IV
|
||||
3.将密文进行base64解码。
|
||||
4.使用AES-256-CBC模式解密解码后的密文,对齐使用PKCS5Padding方式
|
||||
* @param $cipherText
|
||||
* @param $clientSecret
|
||||
* @return false|string
|
||||
*/
|
||||
private function decrypt($cipherText, $clientSecret) {
|
||||
Log::info('$cipherText:' . $cipherText);
|
||||
// 补齐或裁剪 ClientSecret 为 32 位
|
||||
$clientSecret = $this->padOrTruncate($clientSecret);
|
||||
Log::info('$cipherText step 2:' . $clientSecret);
|
||||
|
||||
// 使用 ClientSecret 作为密钥
|
||||
$key = $clientSecret;
|
||||
|
||||
// 右侧16位为初始化向量IV
|
||||
$iv = substr($key, 16, 16);
|
||||
|
||||
// 将密文 base64 解码
|
||||
$cipherTextDecoded = base64_decode($cipherText);
|
||||
|
||||
// 使用 AES-256-CBC 解密
|
||||
return openssl_decrypt($cipherTextDecoded, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $clientSecret
|
||||
* @return false|string
|
||||
*/
|
||||
private function padOrTruncate($clientSecret) {
|
||||
// 1. 如果 clientSecret 长度为32,直接返回
|
||||
if (strlen($clientSecret) == 32) {
|
||||
return $clientSecret;
|
||||
}
|
||||
|
||||
// 2. 如果 length < 32,补齐至32位
|
||||
if (strlen($clientSecret) < 32) {
|
||||
// 补齐过程:先补左侧,再补右侧,再补左侧,直到长度为32
|
||||
$paddingChar = '#';
|
||||
$padded = $clientSecret;
|
||||
|
||||
// 左侧补齐
|
||||
$left = true;
|
||||
while (strlen($padded) < 32) {
|
||||
if ($left) {
|
||||
$padded = $paddingChar . $padded;
|
||||
$left = false;
|
||||
} else {
|
||||
$padded = $padded . $paddingChar;
|
||||
$left = true;
|
||||
}
|
||||
}
|
||||
|
||||
return substr($padded, 0, 32); // 确保返回32位
|
||||
}
|
||||
|
||||
// 3. 如果 length > 32,裁剪至32位
|
||||
if (strlen($clientSecret) > 32) {
|
||||
// 裁剪过程:先裁左侧,再裁右侧,再裁左侧,直到长度为32
|
||||
$cropped = $clientSecret;
|
||||
|
||||
// 左侧裁剪
|
||||
while (strlen($cropped) > 32) {
|
||||
$cropped = substr($cropped, 1);
|
||||
}
|
||||
|
||||
// 右侧裁剪
|
||||
while (strlen($cropped) > 32) {
|
||||
$cropped = substr($cropped, 0, -1);
|
||||
}
|
||||
|
||||
// 左侧裁剪(再一次)
|
||||
while (strlen($cropped) > 32) {
|
||||
$cropped = substr($cropped, 1);
|
||||
}
|
||||
|
||||
return substr($cropped, 0, 32); // 确保返回32位
|
||||
}
|
||||
|
||||
return $clientSecret;
|
||||
}
|
||||
}
|
|
@ -28,8 +28,8 @@ class SpiderDy extends Command
|
|||
{
|
||||
protected static $defaultName = 'spider:dy';
|
||||
protected static $defaultDescription = '抖音订单拉取器';
|
||||
|
||||
protected $_users = [];
|
||||
protected $page = 3;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
|
@ -39,7 +39,9 @@ class SpiderDy extends Command
|
|||
new InputDefinition(array(
|
||||
new InputOption('sn', 'sn', InputOption::VALUE_REQUIRED),
|
||||
new InputOption('os', 'os', InputOption::VALUE_REQUIRED),
|
||||
new InputOption('day', 'day', InputOption::VALUE_REQUIRED)
|
||||
new InputOption('day', 'day', InputOption::VALUE_REQUIRED),
|
||||
// 最大页数
|
||||
new InputOption('max_page', 'max_page', InputOption::VALUE_OPTIONAL)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
@ -144,6 +146,9 @@ class SpiderDy extends Command
|
|||
if (empty($d)) {
|
||||
$d = 40;
|
||||
}
|
||||
if ($input->getOption('max_page')) {
|
||||
$this->page = $input->getOption('max_page');
|
||||
}
|
||||
|
||||
if ($orderid) {
|
||||
$this->reloadStatus($orderid, $os, $output);
|
||||
|
@ -301,7 +306,7 @@ class SpiderDy extends Command
|
|||
{
|
||||
|
||||
foreach (Orders::OSS as $k => $os) {
|
||||
$pages = 3;
|
||||
$pages = $this->page;
|
||||
$page = 1;
|
||||
|
||||
while (true) {
|
||||
|
|
|
@ -30,6 +30,7 @@ class SpiderMt extends Command
|
|||
|
||||
protected $_users = [];
|
||||
protected $order_num = 99999999;
|
||||
protected $page = 20;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
|
@ -39,7 +40,9 @@ class SpiderMt extends Command
|
|||
new InputDefinition(array(
|
||||
new InputOption('sn', 'sn', InputOption::VALUE_REQUIRED),
|
||||
new InputOption('os', 'os', InputOption::VALUE_REQUIRED),
|
||||
new InputOption('day', 'day', InputOption::VALUE_REQUIRED)
|
||||
new InputOption('day', 'day', InputOption::VALUE_REQUIRED),
|
||||
// 最大页数
|
||||
new InputOption('max_page', 'max_page', InputOption::VALUE_OPTIONAL)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
@ -159,6 +162,9 @@ class SpiderMt extends Command
|
|||
if (empty($d)) {
|
||||
$d = 90;
|
||||
}
|
||||
if ($input->getOption('max_page')) {
|
||||
$this->page = $input->getOption('max_page');
|
||||
}
|
||||
|
||||
if ($orderid) {
|
||||
$this->reloadStatus($orderid, $os, $output);
|
||||
|
@ -317,7 +323,7 @@ class SpiderMt extends Command
|
|||
{
|
||||
|
||||
foreach (Orders::OSS as $k => $os) {
|
||||
$pages = 20;
|
||||
$pages = $this->page;
|
||||
$page = 1;
|
||||
|
||||
while (true) {
|
||||
|
|
|
@ -36,4 +36,35 @@ function isUrlInDomainWithPath($urlToCheck,$baseUrl): bool
|
|||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_week_days() {
|
||||
// 获取当前日期
|
||||
$currentDate = new DateTime();
|
||||
|
||||
// 获取本周的周一(使用ISO-8601标准:一周的开始是周一)
|
||||
$currentDate->modify('this week monday');
|
||||
|
||||
// 存储周一到周日的日期
|
||||
$weekDays = [];
|
||||
|
||||
// 循环获取本周的每一天
|
||||
for ($i = 0; $i < 7; $i++) {
|
||||
// 获取当前日期并添加到数组
|
||||
$weekDays[] = [
|
||||
'date' => $currentDate->format('Y-m-d')
|
||||
];
|
||||
|
||||
// 将日期调整到下一个日期(例如,周二 -> 周三)
|
||||
$currentDate->modify('+1 day');
|
||||
}
|
||||
|
||||
return $weekDays;
|
||||
}
|
||||
|
||||
function getNewOrderId($type) {
|
||||
list($msec, $sec) = explode(' ', microtime());
|
||||
$msectime = number_format((floatval($msec) + floatval($sec)) * 1000, 0, '', '');
|
||||
$orderId = $type . $msectime . mt_rand(10000, max(intval($msec * 10000) + 10000, 98369));
|
||||
return $orderId;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace app\model;
|
||||
|
||||
use support\Log;
|
||||
use think\facade\Db;
|
||||
use support\Redis;
|
||||
|
||||
class DyOrderProductAppointments extends base {
|
||||
protected $table = 'dy_order_appointments';
|
||||
protected $json = [
|
||||
'pay_info',
|
||||
'book_info',
|
||||
'buyer_info',
|
||||
];
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace app\model;
|
||||
|
||||
use support\Log;
|
||||
use think\facade\Db;
|
||||
use support\Redis;
|
||||
|
||||
class DyOrderProducts extends base {
|
||||
protected $table = 'dy_order_products';
|
||||
protected $json = [
|
||||
'travel_details',
|
||||
'commodity',
|
||||
'date_add_price_rule',
|
||||
'user_add_price_rule',
|
||||
'room_add_price_rule',
|
||||
'room_upgrade_rule'
|
||||
];
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace app\model;
|
||||
|
||||
use support\Log;
|
||||
use think\facade\Db;
|
||||
use support\Redis;
|
||||
|
||||
class DyOrders extends base {
|
||||
protected $table = 'dy_orders';
|
||||
protected $json = [];
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
<?php
|
||||
namespace app\server;
|
||||
|
||||
use app\model\Orders;
|
||||
use app\model\ThirdMobileLogs;
|
||||
use http\Client;
|
||||
use support\Log;
|
||||
use support\Redis;
|
||||
use think\Exception;
|
||||
|
||||
/**
|
||||
* 抖音接口
|
||||
*/
|
||||
class DyApiService {
|
||||
// 生成 client_token
|
||||
CONST CLIENT_TOKEN = '/oauth/client_token/';
|
||||
// 确认接单
|
||||
CONST ORDER_CONFIRM = '/goodlife/v1/trip/trade/travelagency/order/confirm/';
|
||||
// 订单POI信息查询接口
|
||||
CONST POI_QUERY = '/goodlife/v1/trip/trade/travelagency/order/poi/query/';
|
||||
|
||||
// redis key
|
||||
CONST DY_TOKEN_KEY = 'dy_client_key';
|
||||
// 请求地址
|
||||
private $host;
|
||||
private $app_id;
|
||||
// 加密密钥
|
||||
private $app_secret;
|
||||
|
||||
/**
|
||||
* 构造函数.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->host = env('DY_API_URL');
|
||||
$this->app_id = env('DY_APPID');
|
||||
$this->app_secret = env('DY_APPSECRET');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $url
|
||||
* @param array $data
|
||||
* @param array $extra
|
||||
* @return array
|
||||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||||
*/
|
||||
public function send($url, array $data = [], $extra = []): array {
|
||||
$signData = [
|
||||
'Api-App-Key' => $this->app_id,
|
||||
'Api-Time-Stamp' => time() * 1000,
|
||||
];
|
||||
// 组装请求数据
|
||||
$reqData = $data;
|
||||
|
||||
// 请求头加上签名
|
||||
// $header['Api-Sign'] = $this->getSign($signData, $reqData);
|
||||
$header['access-token'] = $this->getAccessToken();
|
||||
if ($this->app_id == 'sandbox289') {
|
||||
$header['x-sandbox-token'] = 1;
|
||||
}
|
||||
|
||||
return $this->request($url, $reqData, $header, $extra);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取token
|
||||
* @return bool|mixed|string
|
||||
* @throws Exception
|
||||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||||
*/
|
||||
private function getAccessToken() {
|
||||
// 测试token
|
||||
if ($this->app_id == 'sandbox289') {
|
||||
return 'ka.F9tiX0EN5QB5plK43W22p3cDgji9O9ZTAigryyd1A7AlbDwTmDxEN0PwjfI9';
|
||||
}
|
||||
$key = self::DY_TOKEN_KEY;
|
||||
if ($token = Redis::get($key)) {
|
||||
return $token;
|
||||
}
|
||||
|
||||
$reqData = [
|
||||
'client_key' => $this->app_id,
|
||||
'client_secret' => $this->app_secret,
|
||||
'grant_type' => 'client_credential',
|
||||
];
|
||||
$res = $this->request(self::CLIENT_TOKEN, $reqData);
|
||||
if (!$res['flag'] || !isset($res['data']['access_token'])) {
|
||||
throw new Exception('获取token失败');
|
||||
}
|
||||
Redis::setEx($key, $res['data']['expires_in'], $res['data']['access_token']);
|
||||
return $res['data']['access_token'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取签名
|
||||
*/
|
||||
public function getSign($signData, $postData): string {
|
||||
// $signData = array_merge($signData, $postData);
|
||||
$buff = "";
|
||||
ksort($signData);
|
||||
// 将key和value按照顺序直接拼接到一起
|
||||
foreach ($signData as $k => $v){
|
||||
if (!empty($v)) {
|
||||
if (is_array($v)) {
|
||||
$v = json_encode(ksort($v), JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
$buff .= $k . $v;
|
||||
}
|
||||
}
|
||||
|
||||
// 签名步骤三:在上一步的结果后直接拼secretKey
|
||||
$str = $buff . $this->app_secret;
|
||||
// 在上一步结果后直接拼接,经过去除空白字符(\s)的HTTP Body原始字符串
|
||||
$str .= preg_replace('/\s+/', '', json_encode($postData));
|
||||
// 对上一步结果进行sha1加密,得到16进制字符串
|
||||
$str = sha1($str);
|
||||
// 对上一步结果进行md5加密,得到16进制字符串
|
||||
// 将上一步结果转为大写
|
||||
return strtoupper(md5($str));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param array $data
|
||||
* @param array $header
|
||||
* @param array $extra
|
||||
* @return array
|
||||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||||
*/
|
||||
private function request(string $url, array $data = [], $header = []): array {
|
||||
$client = new \GuzzleHttp\Client();
|
||||
try {
|
||||
$reqUrl = $this->host . $url;
|
||||
$header['Content-Type'] = 'application/json';
|
||||
$header['charset'] = 'UTF-8';
|
||||
$options['headers'] = $header;
|
||||
$options['json'] = $data;
|
||||
$method = 'POST';
|
||||
|
||||
$response = $client->request($method, $reqUrl, $options);
|
||||
Log::info(sprintf('dy url:%s, req:%s, response:%s', $reqUrl, json_encode($data), $response->getBody())) ;
|
||||
$result = ['code' => $response->getStatusCode(), 'body' => json_decode($response->getBody(), true, 512, JSON_BIGINT_AS_STRING)];
|
||||
if (isset($result['code']) && $result['code'] == 200) {
|
||||
if ($result['body']['data']['error_code'] == '0') {
|
||||
return ['flag' => true, 'data' => $result['body']['data'] ?? [], 'message' => $result['body']['data']['description '] ?? ''];
|
||||
} else {
|
||||
return ['flag' => false, 'data' => $result['body']['data'] ?? [], 'message' => $result['body']['data']['description '] ?? ''];
|
||||
}
|
||||
}
|
||||
|
||||
return ['flag' => false, 'message' => $result['body']['data']['description'] ?? '', 'data' => []];
|
||||
} catch (\Exception $exception) {
|
||||
Log::info(sprintf('dy req fail:%s, req:%s,res:%s', $exception->getMessage(), $exception->getFile(), $exception->getLine())) ;
|
||||
return ['flag' => false, 'message' => $exception->getMessage(), 'data' => []];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,7 +36,8 @@
|
|||
"webman/console": "^1.3",
|
||||
"mk-j/php_xlsxwriter": "^0.39.0",
|
||||
"workerman/crontab": "^1.0",
|
||||
"workerman/validation": "^1.0"
|
||||
"workerman/validation": "^1.0",
|
||||
"guzzlehttp/guzzle": "^7.9"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-event": "For better performance. "
|
||||
|
|
|
@ -37,3 +37,7 @@ ALTER TABLE `follows`
|
|||
ADD INDEX `idx_order_id`(`order_id`) USING HASH;
|
||||
|
||||
update orders set verification_date =( SELECT FROM_UNIXTIME(create_time) FROM `follows` where status = 2 and order_id = orders.id limit 1)
|
||||
|
||||
##### 2024-11-21 #####
|
||||
ALTER TABLE `orders`
|
||||
ADD COLUMN `is_direct_mode` tinyint NOT NULL DEFAULT 0 COMMENT '是否直连模式(0-否,1-是)' AFTER `verification_date`;
|
||||
|
|
Loading…
Reference in New Issue