Pārlūkot izejas kodu

染色激活回传

liuzejian 1 gadu atpakaļ
vecāks
revīzija
901c78cb87

+ 127 - 0
app/Jobs/Callback/JuliangAccountReportRanse.php

@@ -0,0 +1,127 @@
+<?php
+
+namespace App\Jobs\Callback;
+
+use App\Service\Callback\Tiktok\TiktokEventReportService;
+use App\Service\Callback\TrackService;
+use App\Service\User\UserRanseService;
+use App\Service\Util\Support\Trace\TraceContext;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldBeUnique;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+use Illuminate\Support\Facades\DB;
+
+class JuliangAccountReportRanse implements ShouldQueue
+{
+    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+    private $info;
+    /**
+     * Create a new job instance.
+     * <pre>
+     * [
+     *  'ip' => 'xxx',
+     *  'ranseId' => 'xxx',
+     *  'ranseStartAt' =>'xxx',
+     *  'ranseEndAt' => 'xxx,
+     *  'uid' => 'xxx',
+     *  'traceInfo' => []
+     * ]
+     * </pre>
+     */
+    public function __construct($info)
+    {
+        $this->info = $info;
+    }
+
+    /**
+     * Execute the job.
+     */
+    public function handle(): void
+    {
+        /**
+         * 1,  ip , ranseId, 在最近的3 分钟里 找到检测链接记录
+         * 2,  如果找到了,就执行回传.
+         * 3,  将信息记录入库.
+         */
+        $traceContext = TraceContext::newFromParent($this->info['traceInfo']);
+        myLog('JuliangAccountReportRanse')->info('开始执行回传', [
+            'uid' => $this->info['uid'], 'ip' => $this->info['ip'], 'ranseId' => $this->info['ranseId'],
+            'traceInfo' => $traceContext->getTraceInfo()
+        ]);
+        $trackRecord = TrackService::getTrackRecord('juliangAccount', [
+            'ip' => $this->info['ip'], 'ranseId' => $this->info['ranseId']
+        ]);
+
+        if(is_null($trackRecord)) {
+            myLog('JuliangAccountReportRanse')->warning('没有找到监测记录', [
+                'traceInfo' => $traceContext->getTraceInfo()
+            ]);
+            return ;
+        }
+
+        $promotion = DB::table('promotions')
+            ->where(['id' => $this->info['ranseId'], 'is_enabled' => 1])
+            ->select('callback_type', 'callback_config_id')->first();
+        if(!$promotion) {
+            myLog('JuliangAccountReportRanse')->warning('end:染色推广记录不存在', [
+                'traceInfo' => $traceContext->getTraceInfo()
+            ]);
+            return ;
+        }
+        if(1 != $promotion->callback_type) {
+            myLog('JuliangAccountReportRanse')->warning('end:推广记录不是巨量账户级回传', [
+                'traceInfo' => $traceContext->getTraceInfo()
+            ]);
+            return ;
+        }
+        $callbackConfig = DB::table('juliang_account_callback_config')
+            ->where(['id' => $promotion->callback_config_id])->first();
+        if(!$callbackConfig) {
+            myLog('JuliangAccountReportRanse')->warning('end:推广记录没有回传配置', [
+                'traceInfo' => $traceContext->getTraceInfo()
+            ]);
+            return ;
+        }
+        if(0 == $callbackConfig->state) {
+            myLog('JuliangAccountReportRanse')->info('end:推广记录对应回传配置关闭', [
+                'traceInfo' => $traceContext->getTraceInfo()
+            ]);
+            return ;
+        }
+        if($callbackConfig->adv_account_id != $trackRecord['advertiser_id']) {
+            myLog('JuliangAccountReportRanse')->warning('end:推广配置的广告主id和监测记录广告主id不一致', [
+                'tuiguang_advertiser_id' => $callbackConfig->adv_account_id,
+                'jiance_advertiser_id' => $trackRecord['advertiser_id'],
+                'traceInfo' => $traceContext->getTraceInfo()
+            ]);
+            return ;
+        }
+
+        $service = new TiktokEventReportService();
+        $reportResult = $service->reportActive((object)[
+            'callback' => $trackRecord['callback']
+        ]);
+        myLog('JuliangAccountReportRanse')->debug('执行回传结果', [
+            'reportResult' => $reportResult,
+            'traceInfo' => $traceContext->getTraceInfo()
+        ]);
+        $now = date('Y-m-d H:i:s');
+        DB::table('callback_report_ranse_record')
+            ->insert([
+                'uid' => $this->info['uid'],
+                'ranse_id' => $this->info['ranseId'],
+                'callback' => $trackRecord['callback'],
+                'advertiser_id' => $trackRecord['advertiser_id'],
+                'adv_promotion_id' => $trackRecord['adv_promotion_id'],
+                'report_result' => \json_encode($reportResult, JSON_UNESCAPED_UNICODE),
+                'created_at' => $now,
+                'updated_at' => $now,
+                'ranse_start_at' => $this->info['ranseStartAt'],
+                'ranse_end_at' => $this->info['ranseEndAt'],
+            ]);
+    }
+}

+ 152 - 0
app/Service/Callback/Tiktok/TiktokEventReportService.php

@@ -0,0 +1,152 @@
+<?php
+
+namespace App\Service\Callback\Tiktok;
+
+use Exception;
+use GuzzleHttp\Client;
+
+/**
+ * 抖音数据回调---新版---使用事件管理模式
+ * ios加桌和普通抖音事件管理是一个回传逻辑
+ * 开发文档:https://event-manager.oceanengine.com/docs/8650/h5_api_docs/
+ */
+class TiktokEventReportService
+{
+    /**
+     * 充值用户事件类型
+     */
+    protected $charge_event_type = 'active_pay';
+    /**
+     * 注册用户事件类型
+     */
+    protected $register_event_type = 'active_register';
+    /**
+     * 激活事件类型
+     */
+    protected $active_event_type = 'active';
+    /**
+     * 次留事件类型
+     */
+    protected $rentention_event_type = 'next_day_open';
+    /**
+     * 付费ROI事件类型
+     */
+    protected $purchase_roi_event_type = 'purchase_roi';
+
+
+    /**
+     * 充值用户数据上报地址
+     */
+    protected $report_url = 'https://analytics.oceanengine.com/api/v2/conversion';
+
+    private $user;
+
+    public function __construct()
+    {
+
+    }
+
+    /**
+     * 付费上报
+     */
+    public function reportCharge(DouyinUser $user, $amount)
+    {
+        return $this->report($this->report_url, [
+            'event_type' => $this->charge_event_type,
+            'context' => [
+                'ad' => [
+                    'callback' => $user->callback
+                ]
+            ],
+            'timestamp' => time()
+        ]);
+    }
+
+    /**
+     * 注册上报
+     */
+    public function reportRegister(DouyinUser $user)
+    {
+        return $this->report($this->report_url, [
+            'event_type' => $this->register_event_type,
+            'context' => [
+                'ad' => [
+                    'callback' => $user->callback
+                ]
+            ],
+            'timestamp' => time()
+        ]);
+    }
+
+    /**
+     * 次日留存上报
+     */
+    public function reportRentention()
+    {
+        return $this->report($this->report_url, [
+            'event_type' => $this->rentention_event_type,
+            'context' => [
+                'ad' => [
+                    'callback' => $this->user->callback
+                ]
+            ],
+            'timestamp' => time()
+        ]);
+    }
+
+    public function reportAddDesktop()
+    {
+        return [];
+    }
+
+    /**
+     * 激活上报
+     */
+    public function reportActive($user)
+    {
+        return $this->report($this->report_url, [
+            'event_type' => $this->active_event_type,
+            'context' => [
+                'ad' => [
+                    'callback' => $user->callback
+                ]
+            ],
+            'timestamp' => time()
+        ]);
+    }
+
+    /**
+     * 数据上报
+     */
+    public function report(string $url, array $query_params)
+    {
+        $result = false;
+        $content = '';
+        try {
+            myLog('tiktok_event_report')->info('report_param_event_tiktok:' . json_encode($query_params));
+
+            $client = new Client(['timeout' => 4]);
+            $response = $client->request('post', $url, ['json' => $query_params]);
+
+            $content = $response->getBody()->getContents();
+            myLog('tiktok_event_report')->info('report_result_event_tiktok:' . json_encode($content, true));
+
+            $status_code = $response->getStatusCode();
+            if ($status_code == 200) {
+                $result = true;
+            } else {
+                $result = false;
+            }
+        } catch (Exception $e) {
+            myLog('tiktok_event_report')->error('event_tiktok_ept:' . json_encode($query_params) . ' ept:' . $e->getMessage());
+        } finally {
+            $query_params['report_url'] = $url;
+            return [
+                'result' => $result,
+                'content' => $content,
+                'query_params' => $query_params,
+            ];
+        }
+    }
+
+}

+ 47 - 0
app/Service/Callback/TrackService.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace App\Service\Callback;
+
+use Illuminate\Support\Facades\DB;
+
+class TrackService
+{
+    public static function getTrackRecord($callbackType, $searchInfo) {
+        switch ($callbackType) {
+            case 'juliangAccount':
+                $ip =  $searchInfo['ip'];
+                $ranseId = $searchInfo['ranseId'];
+                $now = time();
+                foreach (self::getTrackTable($now,180) as $table) {
+                    $record = DB::connection('track_record')
+                        ->table($table)
+                        ->where([
+                            'ip' => $ip, 'connection_id' => $ranseId, 'link_source' => 'tiktok',
+                        ])->where('created_at', '>=', $now - 180)
+                        ->orderBy('id', 'desc')
+                        ->first();
+                    if($record) {
+                        break;
+                    }
+                }
+                return $record ? [
+                    'callback' => $record->callback,
+                    'advertiser_id' => $record->advertiser_id,
+                    'adv_promotion_id' => $record->promotion_id
+                ] : null;
+
+                break;
+        }
+        return null;
+    }
+
+    public static function getTrackTable($endTimstamp, $duration) {
+        $currentYm = date('Ym', $endTimstamp);
+        $startCurrentYm = date('Ym', $endTimstamp - $duration);
+        $tables = ['douyin_tracks'.$currentYm];
+        if($currentYm != $startCurrentYm) {
+            $tables[] = 'douyin_tracks'.$startCurrentYm;
+        }
+        return $tables;
+    }
+}

+ 33 - 0
app/Service/User/UserRanseService.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace App\Service\User;
+
+use Illuminate\Support\Facades\DB;
+
+class UserRanseService
+{
+    public static function getRanseInfo($uid) {
+        $uidLog = DB::table('uid_logs')->where(['id' => $uid])->first();
+        if(!$uidLog) {
+            return null;
+        }
+        $table = self::getMiniProgramUserTableName($uidLog->use_for);
+        $user = DB::table($table)->where('id', $uid)->first();
+        if(!$user) {
+            return null;
+        }
+
+        return [
+            'ranse_start_at' => $user->ranse_start_at,
+            'ranse_end_at' => $user->ranse_end_at,
+            'ranse_id' => $user->ranse_id,
+        ];
+    }
+
+    public static function getMiniProgramUserTableName($useFor) {
+        return sprintf('%s_users', [
+            '1' => 'wechat_miniprogram',
+            '2' => 'douyin_miniprogram'
+        ][$useFor]);
+    }
+}

+ 8 - 2
composer.json

@@ -25,12 +25,18 @@
             "App\\": "app/",
             "Database\\Factories\\": "database/factories/",
             "Database\\Seeders\\": "database/seeders/"
-        }
+        },
+        "files": [
+            "app/Libs/Helpers.php"
+        ]
     },
     "autoload-dev": {
         "psr-4": {
             "Tests\\": "tests/"
-        }
+        },
+        "files": [
+            "app/Libs/Helpers.php"
+        ]
     },
     "scripts": {
         "post-autoload-dump": [

+ 1 - 1
config/app.php

@@ -70,7 +70,7 @@ return [
     |
     */
 
-    'timezone' => 'UTC',
+    'timezone' => 'Asia/shanghai',
 
     /*
     |--------------------------------------------------------------------------

+ 20 - 0
config/database.php

@@ -93,6 +93,26 @@ return [
             // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
         ],
 
+        'track_record' => [
+            'driver' => 'mysql',
+            'url' => env('DATABASE_URL'),
+            'host' => env('TRACK_RECORD_DB_HOST', '127.0.0.1'),
+            'port' => env('TRACK_RECORD_DB_PORT', '3306'),
+            'database' => env('TRACK_RECORD_DB_DATABASE', 'forge'),
+            'username' => env('TRACK_RECORD_DB_USERNAME', 'forge'),
+            'password' => env('TRACK_RECORD_DB_PASSWORD', ''),
+            'unix_socket' => env('DB_SOCKET', ''),
+            'charset' => 'utf8mb4',
+            'collation' => 'utf8mb4_unicode_ci',
+            'prefix' => '',
+            'prefix_indexes' => true,
+            'strict' => true,
+            'engine' => null,
+            'options' => extension_loaded('pdo_mysql') ? array_filter([
+                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
+            ]) : [],
+        ],
+
     ],
 
     /*

+ 23 - 0
tests/Jobs/Callback/JuliangAccountReportRanseTest.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace Tests\Jobs\Callback;
+
+use App\Jobs\Callback\JuliangAccountReportRanse;
+use App\Service\Util\Support\Trace\TraceContext;
+
+class JuliangAccountReportRanseTest extends \Tests\TestCase
+{
+
+    public function testHandle()
+    {
+        $job = new JuliangAccountReportRanse([
+            'uid' => 1,
+            'ranseId' => 2,
+            'ip' => '192.168.1.123',
+            'ranseStartAt' => '2023-05-18 14:14:14',
+            'ranseEndAt' => '2023-05-18 15:14:14',
+            'traceInfo' => (new TraceContext())->getTraceInfo()
+        ]);
+        $job->handle();
+    }
+}

+ 15 - 0
tests/Service/Callback/TrackServiceTest.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace Tests\Service\Callback;
+
+use App\Service\Callback\TrackService;
+use PHPUnit\Framework\TestCase;
+
+class TrackServiceTest extends \Tests\TestCase
+{
+    public function testgetTrackTable() {
+        $startTimestamp = strtotime('2023-05-01 00:03:23');
+        $tables = TrackService::getTrackTable($startTimestamp, 180);
+        dump($tables);
+    }
+}