|
|
@@ -9,7 +9,9 @@ use app\common\model\external\DouyinOrder;
|
|
|
use app\common\model\external\DouyinRefundOrder;
|
|
|
use app\common\model\external\ExternalConsultation;
|
|
|
use app\common\model\external\ExternalConsultationOrder;
|
|
|
+use app\common\model\external\ExternalPlatformGoods;
|
|
|
use app\common\model\goods\Goods;
|
|
|
+use app\common\model\goods_category\GoodsCategory;
|
|
|
use app\common\model\recharge\RechargeOrder;
|
|
|
use app\common\model\user\User;
|
|
|
use app\common\model\user\UserAuth;
|
|
|
@@ -23,6 +25,8 @@ class DouYinService
|
|
|
{
|
|
|
protected static int $terminal = \app\common\enum\user\UserTerminalEnum::DOUYIN;
|
|
|
protected static int $external_platform_id = 6;
|
|
|
+
|
|
|
+ // ********************************* 注册登录
|
|
|
public static function register(array $params)
|
|
|
{
|
|
|
$userSn = User::createUserSn();
|
|
|
@@ -77,9 +81,191 @@ class DouYinService
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // **************************** 商品管理 goods_category_id goods_id external_platform_id
|
|
|
+
|
|
|
+ public static function addProduct($params)
|
|
|
+ {
|
|
|
+ $product_url = config('douyin.host').'goodlife/v1/goods/product/save/';
|
|
|
+ $res = http_request($product_url,self::getProductParams($params),['Content-Type' => 'application/json;charset=utf-8','access-token' => self::getClientToken()]);
|
|
|
+ Log::info('addProduct:'.json_encode($res));
|
|
|
+ // 记录到 extra 字段 productRes
|
|
|
+ $goods_id = $params['goods_id']??0;
|
|
|
+ $platformGoods = ExternalPlatformGoods::where('goods_id', $goods_id)->where('external_platform_id', $params['external_platform_id'])->findOrEmpty();
|
|
|
+ if(!$platformGoods->isEmpty()){
|
|
|
+ $extra = $platformGoods->extra?json_decode($platformGoods->extra,true):[];
|
|
|
+ $extra['productRes'] = json_encode($res);
|
|
|
+ $platformGoods->extra = json_encode($extra);
|
|
|
+ $platformGoods->save();
|
|
|
+ }
|
|
|
+ self::addSku($params);
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function addSku($params)
|
|
|
+ {
|
|
|
+ $sku_url = config('douyin.host').'goodlife/v1/goods/sku/batch_save/';
|
|
|
+ $res = http_request($sku_url,self::getSkuParams($params),['Content-Type' => 'application/json;charset=utf-8','access-token' => self::getClientToken()]);
|
|
|
+ Log::info('addSku:'.json_encode($res));
|
|
|
+ // 根据返回后更新本地库对应关系 $res['data']['sku_id_list']
|
|
|
+ if(isset($res['data']['sku_id_list']) && !empty($res['data']['sku_id_list'])){
|
|
|
+ foreach ($res['data']['sku_id_list'] as $item) {
|
|
|
+ ExternalPlatformGoods::where('goods_id', $item['out_sku_id'])->where('external_platform_id', $params['external_platform_id'])->update([
|
|
|
+ 'external_goods_sn' => $item['sku_id']
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function getProductParams($params)
|
|
|
+ {
|
|
|
+ $goodsCategory = GoodsCategory::where('id',$params['goods_category_id']??0)->findOrEmpty();
|
|
|
+ if($goodsCategory->isEmpty()){
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ $goodsCategory = $goodsCategory->toArray();
|
|
|
+ return [
|
|
|
+ "account_id" => '7511543640776017961',
|
|
|
+ "product" => [
|
|
|
+ "out_id" => $params['goods_category_id']??0,
|
|
|
+ "product_name" => $goodsCategory['name'],
|
|
|
+ "product_type" => 22,
|
|
|
+ "category_id" => 6004003,
|
|
|
+ "category_full_name" => "其他维修服务",
|
|
|
+ "biz_line" => 5,
|
|
|
+ "account_name" => "亿蜂快修·武汉市",
|
|
|
+ //{\"params\":\"{\"spuId\":\"xxxxx\",\"skuId\":\"xxxxxx\"}\",\"path\":\"pages/any/path\",\"app_id\":\"xxxxx\"}
|
|
|
+ "out_url" => json_encode(['app_id'=>config('douyin.appId'),'path'=>'pages/detail','params'=>json_encode(['goods_category_id'=>$params['goods_category_id']??0])]),
|
|
|
+ "pois" =>[
|
|
|
+ [
|
|
|
+ "poi_id" => "7511543640776017961"
|
|
|
+ ]
|
|
|
+ ],
|
|
|
+ "product_ext" => [
|
|
|
+ "auto_online" => true,
|
|
|
+ "display_price"=> ["low_price" => 30,"high_price" => 300],
|
|
|
+ "test_extra"=> ["test_flag" => true,"uids" => ["1548********2888"]]
|
|
|
+ ],
|
|
|
+ "attr_key_value_map" => self::getAttrKeyValueMapParams('product',$goodsCategory),
|
|
|
+ "sold_end_time" => time() + 180 * 86400,
|
|
|
+ "sold_start_time" => time()
|
|
|
+ ]
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ public static function getSkuParams($params)
|
|
|
+ {
|
|
|
+ $goods = Goods::where('id',$params['goods_id']??0)->findOrEmpty();
|
|
|
+ if ($goods->isEmpty()) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ $goods = $goods->toArray();
|
|
|
+ // 查询商品信息
|
|
|
+ return [
|
|
|
+ "account_id" => '7511543640776017961',
|
|
|
+ "product_out_id" => $params['goods_category_id']??0,
|
|
|
+ "sku" => [
|
|
|
+ [
|
|
|
+ "out_sku_id"=> $goods['id'],
|
|
|
+ "sku_name"=> $goods['name'],
|
|
|
+ "origin_amount"=> $goods['service_total'] * 100,
|
|
|
+ "actual_amount"=> $goods['service_fee'] * 100,
|
|
|
+ "stock"=> [
|
|
|
+ "limit_type"=> 2,
|
|
|
+ "stock_qty"=> 9999
|
|
|
+ ],
|
|
|
+ "status"=> 1,
|
|
|
+ "attr_key_value_map"=> self::getAttrKeyValueMapParams('sku',$goods)
|
|
|
+ ]
|
|
|
+ ]
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public static function getAttrKeyValueMapParams($type,$params)
|
|
|
+ {
|
|
|
+ $res = [];
|
|
|
+ if($type === 'product'){
|
|
|
+ $res = [
|
|
|
+ "appointment"=>json_encode([
|
|
|
+ "need_appointment"=>true,
|
|
|
+ "ahead_time_type"=>2,
|
|
|
+ "ahead_hour_num"=> 5,
|
|
|
+ "external_link"=>"pages/detail",
|
|
|
+ "order_appointment_time_url"=>"pages/order"
|
|
|
+ ]),
|
|
|
+ "auto_renew"=>true,
|
|
|
+ "can_no_use_date" => json_encode(["enable"=>false]),
|
|
|
+ "Description" => json_encode([]),
|
|
|
+ "image_list" => json_encode([["url"=>$params['picture']??'']]),
|
|
|
+ "limit_use_rule" => json_encode(["is_limit_use"=>true, "use_num_per_consume"=>1]),
|
|
|
+ "Notification" => json_encode([["title"=>$params['name']??'',"content"=>$params['name']??'']]),
|
|
|
+ "RefundPolicy"=> "2",
|
|
|
+ "refund_need_merchant_confirm"=> true,
|
|
|
+ "show_channel"=> 1,
|
|
|
+ "superimposed_discounts"=> false,
|
|
|
+ "trade_url"=> json_encode(['app_id'=>config('douyin.appId'),'path'=>'pages/detail','params'=>json_encode(['goods_category_id'=>$params['id']??0])]),
|
|
|
+ "use_date"=> json_encode(["use_date_type"=>2, "day_duration"=>15]),
|
|
|
+ "use_time"=> json_encode(["use_time_type"=>1]),
|
|
|
+ //"user_num_limit"=> ,
|
|
|
+ "code_source_type"=> 3,
|
|
|
+ "settle_type"=> 1,
|
|
|
+ "use_type"=> 1,
|
|
|
+ "limit_rule"=> json_encode(["is_limit"=>false]),
|
|
|
+ "out_id"=> $params['id']??0
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ if($type === 'sku'){
|
|
|
+ $res = [
|
|
|
+ "code_source_type"=> 3,
|
|
|
+ "limit_rule"=> json_encode(["is_limit"=>false]),
|
|
|
+ "settle_type"=> 1
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ return $res;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // ******************************** 订单
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 扩展点回调提交订单
|
|
|
+ * @param $params
|
|
|
+ * @throws \Exception
|
|
|
+ * @author liugc <466014217@qq.com>
|
|
|
+ * @date 2025/6/4 14:03
|
|
|
+ */
|
|
|
+ public static function submitOrderNotify($params)
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ // order_id goods total_amount discount cp_extra create_order_time phone_num contact_name open_id
|
|
|
+ if(empty($params['user_info']['mobile'])){
|
|
|
+ throw new \Exception('手机号不能为空!');
|
|
|
+ }
|
|
|
+ // goods_id user_info.mobile user_id quantity
|
|
|
+ $order_number = self::submitOrder([
|
|
|
+ 'goods_id'=>$params['goods'][0]['goods_id'],
|
|
|
+ 'user_id'=>$params['user_id'],
|
|
|
+ 'user_info'=>$params['user_info'],
|
|
|
+ 'quantity'=>$params['goods'][0]['quantity']
|
|
|
+ ]);
|
|
|
+ return [
|
|
|
+ "outOrderNo" => $order_number,
|
|
|
+ "orderEntrySchema" => [
|
|
|
+ "path" => "page/index/index",
|
|
|
+ "params" => json_encode(['order_number' => $order_number])
|
|
|
+ ],
|
|
|
+ "payNotifyUrl" => config('douyin.payNotifyUrl')
|
|
|
+ ];
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ throw new \Exception($e->getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* 提交订单
|
|
|
- * @param array $params
|
|
|
+ * @param array $params goods_id user_info.mobile user_id quantity
|
|
|
* @return array|false
|
|
|
*/
|
|
|
public static function submitOrder($params)
|
|
|
@@ -420,7 +606,48 @@ class DouYinService
|
|
|
throw new \Exception($e->getMessage());
|
|
|
}
|
|
|
}
|
|
|
+ public static function sendRefundCreate($order_number)
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ // $params['order_number']
|
|
|
+ $order = DouyinOrder::with(['goods','serviceWork'])->where('order_number', $order_number)->findOrEmpty();
|
|
|
+ if($order->isEmpty()){
|
|
|
+ throw new \Exception('订单不存在');
|
|
|
+ }
|
|
|
+ $orderInfo = $order->toArray();
|
|
|
+ $douyinRefundOrder = DouyinRefundOrder::where('order_number', $order_number)->order('id', 'desc')->findOrEmpty();
|
|
|
|
|
|
+ //通过后向抖音申请退款
|
|
|
+ //getClientToken()
|
|
|
+ $url = config('douyin.host').'api/trade_basic/v1/developer/refund_create/';
|
|
|
+ $data = [
|
|
|
+ "order_id" => $orderInfo['transaction_id'],
|
|
|
+ "out_refund_no" => $douyinRefundOrder->refund_number,
|
|
|
+ "cp_extra" => $orderInfo['id'].'|'.$douyinRefundOrder->id,
|
|
|
+ "order_entry_schema" => [
|
|
|
+ "path" => "page/index/index",
|
|
|
+ "params" => json_encode(['refund_number'=>$douyinRefundOrder->refund_number])
|
|
|
+ ],
|
|
|
+ "refund_total_amount " => $douyinRefundOrder->refund_amount * 100,
|
|
|
+ "notify_url" => config('douyin.refundNotifyUrl'),
|
|
|
+ "refund_reason" => [
|
|
|
+ [
|
|
|
+ "code" => 101,
|
|
|
+ "text" => "不想要了"
|
|
|
+ ]
|
|
|
+ ]
|
|
|
+ ];
|
|
|
+ $res = http_request($url,$data,['Content-Type' => 'application/json;charset=utf-8','access_token' => self::getClientToken()]);
|
|
|
+ if(isset($res['err_msg']) && $res['err_msg'] === 'success'){
|
|
|
+ $douyinRefundOrder->transaction_id = $res['data']['refund_id'];
|
|
|
+ $douyinRefundOrder->save();
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::info($e->getMessage());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
public static function refundNotify($params)
|
|
|
{
|
|
|
Db::startTrans();
|
|
|
@@ -452,6 +679,9 @@ class DouYinService
|
|
|
}
|
|
|
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
public static function byteAuthorization($privateKeyStr, $data, $appId, $nonceStr, $timestamp, $keyVersion) {
|
|
|
$byteAuthorization = '';
|
|
|
// 读取私钥
|
|
|
@@ -485,67 +715,27 @@ class DouYinService
|
|
|
}
|
|
|
return $str;
|
|
|
}
|
|
|
- public static function getClientToken() {
|
|
|
+ public static function getClientToken($isRefresh = false) {
|
|
|
$url = config('douyin.host').'oauth/client_token/';
|
|
|
$cache_name = 'dy_client_token';
|
|
|
$cache_data = cache($cache_name);
|
|
|
- if(empty($cache_data) || $cache_data == null){
|
|
|
+ if(empty($cache_data) || $cache_data == null || $isRefresh){
|
|
|
$data = [
|
|
|
'client_key'=> config('douyin.appId'),
|
|
|
'client_secret'=> config('douyin.appSecret'),
|
|
|
'grant_type'=> "client_credential"
|
|
|
];
|
|
|
$res = http_request($url,$data,['Content-Type' => 'application/json;charset=utf-8']);
|
|
|
+ Log::info(json_encode($res));
|
|
|
if($res['message'] === 'success'){
|
|
|
cache($cache_name, json_encode($res['data']), (time()+$res['data']['expires_in']-1));
|
|
|
$cache_data = $res['data'];
|
|
|
}
|
|
|
}
|
|
|
- return json_decode($cache_data, true)['access_token'];
|
|
|
+ return $cache_data['access_token'];
|
|
|
}
|
|
|
|
|
|
- public static function sendRefundCreate($order_number)
|
|
|
- {
|
|
|
- try {
|
|
|
- // $params['order_number']
|
|
|
- $order = DouyinOrder::with(['goods','serviceWork'])->where('order_number', $order_number)->findOrEmpty();
|
|
|
- if($order->isEmpty()){
|
|
|
- throw new \Exception('订单不存在');
|
|
|
- }
|
|
|
- $orderInfo = $order->toArray();
|
|
|
- $douyinRefundOrder = DouyinRefundOrder::where('order_number', $order_number)->order('id', 'desc')->findOrEmpty();
|
|
|
|
|
|
- //通过后向抖音申请退款
|
|
|
- //getClientToken()
|
|
|
- $url = config('douyin.host').'api/trade_basic/v1/developer/refund_create/';
|
|
|
- $data = [
|
|
|
- "order_id" => $orderInfo['transaction_id'],
|
|
|
- "out_refund_no" => $douyinRefundOrder->refund_number,
|
|
|
- "cp_extra" => $orderInfo['id'].'|'.$douyinRefundOrder->id,
|
|
|
- "order_entry_schema" => [
|
|
|
- "path" => "page/index/index",
|
|
|
- "params" => json_encode(['refund_number'=>$douyinRefundOrder->refund_number])
|
|
|
- ],
|
|
|
- "refund_total_amount " => $douyinRefundOrder->refund_amount * 100,
|
|
|
- "notify_url" => config('douyin.refundNotifyUrl'),
|
|
|
- "refund_reason" => [
|
|
|
- [
|
|
|
- "code" => 101,
|
|
|
- "text" => "不想要了"
|
|
|
- ]
|
|
|
- ]
|
|
|
- ];
|
|
|
- $res = http_request($url,$data,['Content-Type' => 'application/json;charset=utf-8','access_token' => self::getClientToken()]);
|
|
|
- if(isset($res['err_msg']) && $res['err_msg'] === 'success'){
|
|
|
- $douyinRefundOrder->transaction_id = $res['data']['refund_id'];
|
|
|
- $douyinRefundOrder->save();
|
|
|
- }
|
|
|
- return true;
|
|
|
- } catch (\Exception $e) {
|
|
|
- Log::info($e->getMessage());
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
|
|
|
}
|