From 212cbbead0c244d7db38e494db6a5ef84c1b7c8e Mon Sep 17 00:00:00 2001 From: huangguancheng Date: Sat, 15 Feb 2025 17:21:00 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=89=E4=B8=AA=E5=B9=BF=E5=91=8A=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0=E6=9B=B4=E6=8D=A2=E8=B4=A6=E5=8F=B7=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controller/BpsAdController.php | 250 ++-------------- app/controller/CustomerController.php | 98 ++++++- app/controller/NoticeController.php | 98 +++++++ app/controller/OAuthController.php | 49 +++- app/event/ShopifyOrders.php | 324 +++++++++++++++++++++ app/model/BpsAdsMerchantRelation.php | 39 +++ app/process/UpdateGoogleAdsTask.php | 19 +- app/service/AdsInsightService.php | 320 ++------------------- app/service/BpsAdAccountService.php | 360 +++++++++++++----------- app/service/GoogleAdsAccountService.php | 29 +- app/service/GoogleOAuthService.php | 84 +++++- config/event.php | 8 + 12 files changed, 945 insertions(+), 733 deletions(-) create mode 100644 app/controller/NoticeController.php create mode 100644 app/event/ShopifyOrders.php create mode 100644 app/model/BpsAdsMerchantRelation.php diff --git a/app/controller/BpsAdController.php b/app/controller/BpsAdController.php index 5f3b381..37c4e50 100644 --- a/app/controller/BpsAdController.php +++ b/app/controller/BpsAdController.php @@ -114,25 +114,7 @@ class BpsAdController // $dateRange = 'Last Week'; // 默认日期范围 // 根据 platformType 获取广告账户 - if ($platformType === 1) { - if (!$request->refresh_token_facebook) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getMetaAdAccounts(['refresh_token' => $request->refresh_token_facebook]); - } elseif ($platformType === 2) { - if (!$request->refresh_token_google) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getGoogleAdAccounts(['refresh_token' => $request->refresh_token_google]); - } elseif ($platformType === 3) { - if (!$request->refresh_token_tiktok) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getTiktokAdAccounts(['refresh_token' => $request->refresh_token_tiktok]); - } else { - // TODO: 匹配jwt的商户id还是登录用户id - $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id']]); - } + $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id'], 'platform' => $platformType]); if (empty($accounts)) { return $this->successResponse(['data' => []], $request); @@ -159,59 +141,6 @@ class BpsAdController return $this->successResponse($result, $request); } - //旧原型方法 作废 2025-1-14 - public function listThirdUsers2222(Request $request) - { - $options = $request->all(); - $options['jwtClaims'] = $request->jwtClaims; - - // 获取请求参数 - $page = $options['pageNo'] ?? 1; // 页码 - $pageSize = $options['pageSize'] ?? 1000; // 每页数量 - $keyword = $options['conditions']['keyword'] ?? ''; // 关键字搜索 - $platformType = $options['conditions']['platformType'] ?? 0; // 平台类型 - $startDate = $options['conditions']['startDate'] ?? null; // 开始日期 - $endDate = $options['conditions']['endDate'] ?? null; // 结束日期 -// dump($options); - // 根据 platformType 获取第三方用户数据 - if ($platformType === 1) { - // 获取 Facebook 第三方用户数据 - $users = $this->bpsAdAccountService->getMetaThirdUsers(['merchant_id' => $options['jwtClaims']['merchant_id']]); - } elseif ($platformType === 2) { - // 获取 Google 第三方用户数据 - $users = $this->bpsAdAccountService->getGoogleThirdUsers(['merchant_id' => $options['jwtClaims']['merchant_id']]); - } elseif ($platformType === 3) { - // 获取 TikTok 第三方用户数据 - $users = $this->bpsAdAccountService->getTiktokThirdUsers(['merchant_id' => $options['jwtClaims']['merchant_id']]); - } else { - // 根据 JWT claims 获取所有平台的第三方用户 - $users = $this->bpsAdAccountService->getAllThirdUsers(['merchant_id' => $options['jwtClaims']['merchant_id']]); - } - - if (empty($users)) { - return $this->successResponse(['data' => []], $request); - } - -// 获取客户 ID 数组,并去重 - $userIds = array_unique(array_column($users, 'id')); -// dump($userIds); - - // 调用 Service 层查询第三方用户数据列表 - $result = $this->adsInsightService::getThirdUserList( - $platformType, // 平台类型 - $userIds, // 第三方用户 ID 数组 - $page, // 页码 - $pageSize, // 每页数量 - $keyword, // 关键字 - $startDate, // 开始日期 - $endDate // 结束日期 - ); - - // 返回结果 - return $this->successResponse($result, $request); - } - - public function listAds(Request $request) { $options = $request->all(); @@ -229,25 +158,7 @@ class BpsAdController // $dateRange = 'Last Week'; // 默认日期范围 // 根据 platformType 获取广告账户 - if ($platformType === 1) { - if (!$request->refresh_token_facebook) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getMetaAdAccounts(['refresh_token' => $request->refresh_token_facebook]); - } elseif ($platformType === 2) { - if (!$request->refresh_token_google) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getGoogleAdAccounts(['refresh_token' => $request->refresh_token_google]); - } elseif ($platformType === 3) { - if (!$request->refresh_token_tiktok) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getTiktokAdAccounts(['refresh_token' => $request->refresh_token_tiktok]); - } else { - // TODO: 匹配jwt的商户id还是登录用户id - $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id']]); - } + $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id'], 'platform' => $platformType]); if (empty($accounts)) { return $this->successResponse(['data' => []], $request); @@ -289,25 +200,7 @@ class BpsAdController $requireSpend = (bool)($options['conditions']['requireSpend'] ?? false); // $dateRange = 'Last Week'; // 默认日期范围 // 根据 platformType 获取广告账户 - if ($platformType === 1) { - if (!$request->refresh_token_facebook) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getMetaAdAccounts(['refresh_token' => $request->refresh_token_facebook]); - } elseif ($platformType === 2) { - if (!$request->refresh_token_google) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getGoogleAdAccounts(['refresh_token' => $request->refresh_token_google]); - } elseif ($platformType === 3) { - if (!$request->refresh_token_tiktok) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getTiktokAdAccounts(['refresh_token' => $request->refresh_token_tiktok]); - } else { - // TODO: 匹配jwt的商户id还是登录用户id - $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id']]); - } + $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id'], 'platform' => $platformType]); if (empty($accounts)) { return $this->successResponse(['data' => []], $request); @@ -347,25 +240,7 @@ class BpsAdController $requireSpend = (bool)($options['conditions']['requireSpend'] ?? false); // $dateRange = 'Last Week'; // 默认日期范围 // 根据 platformType 获取广告账户 - if ($platformType === 1) { - if (!$request->refresh_token_facebook) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getMetaAdAccounts(['refresh_token' => $request->refresh_token_facebook]); - } elseif ($platformType === 2) { - if (!$request->refresh_token_google) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getGoogleAdAccounts(['refresh_token' => $request->refresh_token_google]); - } elseif ($platformType === 3) { - if (!$request->refresh_token_tiktok) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getTiktokAdAccounts(['refresh_token' => $request->refresh_token_tiktok]); - } else { - // TODO: 匹配jwt的商户id还是登录用户id - $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id']]); - } + $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id'], 'platform' => $platformType]); if (empty($accounts)) { $data = [ @@ -403,30 +278,12 @@ class BpsAdController $keyword = $options['conditions']['keyword'] ?? ''; // 关键字搜索 $platformType = $options['conditions']['platformType'] ?? 0; // 关键字搜索 // $status = $options['conditions']['status'] ?? 0; // 平台类型 - $startDate = $options['conditions']['startDate'] ?? null; // 开始日期 - $endDate = $options['conditions']['endDate'] ?? null; // 结束日期 - $requireSpend = (bool)($options['conditions']['requireSpend']?? false); + $startDate = $options['conditions']['startDate'] ?? null; // 开始日期 + $endDate = $options['conditions']['endDate'] ?? null; // 结束日期 + $requireSpend = (bool)($options['conditions']['requireSpend'] ?? false); // $dateRange = 'Last Week'; // 默认日期范围 // 根据 platformType 获取广告账户 - if ($platformType === 1) { - if (!$request->refresh_token_facebook) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getMetaAdAccounts(['refresh_token' => $request->refresh_token_facebook]); - } elseif ($platformType === 2) { - if (!$request->refresh_token_google) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getGoogleAdAccounts(['refresh_token' => $request->refresh_token_google]); - } elseif ($platformType === 3) { - if (!$request->refresh_token_tiktok) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getTiktokAdAccounts(['refresh_token' => $request->refresh_token_tiktok]); - } else { - // TODO: 匹配jwt的商户id还是登录用户id - $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id']]); - } + $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id'], 'platform' => $platformType]); if (empty($accounts)) { $data = [ @@ -464,9 +321,9 @@ class BpsAdController $keyword = $options['conditions']['keyword'] ?? ''; // 关键字搜索 $platformType = $options['conditions']['platformType'] ?? 0; // 关键字搜索 // $status = $options['conditions']['status'] ?? 0; // 平台类型 - $startDate = $options['conditions']['startDate'] ?? null; // 开始日期 - $endDate = $options['conditions']['endDate'] ?? null; // 结束日期 - $requireSpend = (bool)($options['conditions']['requireSpend']?? false); + $startDate = $options['conditions']['startDate'] ?? null; // 开始日期 + $endDate = $options['conditions']['endDate'] ?? null; // 结束日期 + $requireSpend = (bool)($options['conditions']['requireSpend'] ?? false); // $dateRange = 'Last Week'; // 默认日期范围 // 根据 platformType 获取广告账户 if ($platformType === 1) { @@ -530,25 +387,7 @@ class BpsAdController $requireSpend = (bool)($options['conditions']['requireSpend'] ?? false); // $dateRange = 'Last Week'; // 默认日期范围 // 根据 platformType 获取广告账户 - if ($platformType === 1) { - if (!$request->refresh_token_facebook) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getMetaAdAccounts(['refresh_token' => $request->refresh_token_facebook]); - } elseif ($platformType === 2) { - if (!$request->refresh_token_google) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getGoogleAdAccounts(['refresh_token' => $request->refresh_token_google]); - } elseif ($platformType === 3) { - if (!$request->refresh_token_tiktok) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getTiktokAdAccounts(['refresh_token' => $request->refresh_token_tiktok]); - } else { - // TODO: 匹配jwt的商户id还是登录用户id - $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id']]); - } + $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id'], 'platform' => $platformType]); if (empty($accounts)) { $data = [ @@ -589,28 +428,10 @@ class BpsAdController $status = $options['conditions']['status'] ?? 0; // 平台类型 $startDate = $options['conditions']['startDate'] ?? null; // 开始日期 $endDate = $options['conditions']['endDate'] ?? null; // 结束日期 - $requireSpend = (bool)($options['conditions']['requireSpend']?? false); + $requireSpend = (bool)($options['conditions']['requireSpend'] ?? false); // $dateRange = 'Last Week'; // 默认日期范围 // 根据 platformType 获取广告账户 - if ($platformType === 1) { - if (!$request->refresh_token_facebook) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getMetaAdAccounts(['refresh_token' => $request->refresh_token_facebook]); - } elseif ($platformType === 2) { - if (!$request->refresh_token_google) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getGoogleAdAccounts(['refresh_token' => $request->refresh_token_google]); - } elseif ($platformType === 3) { - if (!$request->refresh_token_tiktok) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getTiktokAdAccounts(['refresh_token' => $request->refresh_token_tiktok]); - } else { - // TODO: 匹配jwt的商户id还是登录用户id - $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id']]); - } + $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id'], 'platform' => $platformType]); if (empty($accounts)) { $data = [ @@ -655,25 +476,7 @@ class BpsAdController // $dateRange = 'Last Week'; // 默认日期范围 // 根据 platformType 获取广告账户 - if ($platformType === 1) { - if (!$request->refresh_token_facebook) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getMetaAdAccounts(['refresh_token' => $request->refresh_token_facebook]); - } elseif ($platformType === 2) { - if (!$request->refresh_token_google) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getGoogleAdAccounts(['refresh_token' => $request->refresh_token_google]); - } elseif ($platformType === 3) { - if (!$request->refresh_token_tiktok) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getTiktokAdAccounts(['refresh_token' => $request->refresh_token_tiktok]); - } else { - // TODO: 匹配jwt的商户id还是登录用户id - $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id']]); - } + $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id'], 'platform' => $platformType]); if (empty($accounts)) { return $this->successResponse(['data' => []], $request); @@ -711,7 +514,7 @@ class BpsAdController $platformType = $options['conditions']['platformType'] ?? 0; // 平台类型 $startDate = $options['conditions']['startDate'] ?? null; // 开始日期 $endDate = $options['conditions']['endDate'] ?? null; // 结束日期 - $requireSpend = (bool)($options['conditions']['requireSpend']?? false); + $requireSpend = (bool)($options['conditions']['requireSpend'] ?? false); // $dateRange = 'Last Week'; // 默认日期范围 @@ -829,25 +632,7 @@ class BpsAdController // $dateRange = 'Last Week'; // 默认日期范围 // 根据 platformType 获取广告账户 - if ($platformType === 1) { - if (!$request->refresh_token_facebook) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getMetaAdAccounts(['refresh_token' => $request->refresh_token_facebook]); - } elseif ($platformType === 2) { - if (!$request->refresh_token_google) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getGoogleAdAccounts(['refresh_token' => $request->refresh_token_google]); - } elseif ($platformType === 3) { - if (!$request->refresh_token_tiktok) { - return $this->successResponse(['data' => []], $request); - } - $accounts = $this->bpsAdAccountService->getTiktokAdAccounts(['refresh_token' => $request->refresh_token_tiktok]); - } else { - // TODO: 匹配jwt的商户id还是登录用户id - $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id']]); - } + $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id'], 'platform' => $platformType]); if (empty($accounts)) { return $this->successResponse(['data' => []], $request); @@ -881,7 +666,6 @@ class BpsAdController $endDate = $options['conditions']['endDate'] ?? null; // 结束日期 // $dateRange = 'Last Week'; // 默认日期范围 - // TODO: 匹配jwt的商户id还是登录用户id $accounts = $this->bpsAdAccountService->getAllAdAccounts(['merchant_id' => $options['jwtClaims']['merchant_id']]); diff --git a/app/controller/CustomerController.php b/app/controller/CustomerController.php index 41100d2..5c5debc 100644 --- a/app/controller/CustomerController.php +++ b/app/controller/CustomerController.php @@ -8,12 +8,15 @@ use Google\ApiCore\ApiException; use support\Log; use support\Request; use support\Response; +use support\Redis; use DI\Annotation\Inject; //use app\model\ThirdUserAdvertiser; class CustomerController { + // 育才定义 绑定广告账号时的该uuid的广告token Redis 键名前缀 + const REDIS_KEY_PREFIX = 'bps-goui:third:token:key:'; /** * @Inject @@ -28,13 +31,30 @@ class CustomerController */ private $googleAdsAccountService; + /** + * 作废2025-2-13 + * + */ +// public function getCustomerList(Request $request) +// { +// $thirdUserId = $request->input('third_user_id'); // bps_third_user的id +// +// $googleOAuthService = new GoogleOAuthService(); +// $hasThirdUser = $googleOAuthService->getCustomerList($thirdUserId); +// if (!$hasThirdUser) { +// return $this->errorResponse(300, 'Invalid state parameter'); +// } +// return $this->successResponse($hasThirdUser); +// +// } + //调试用 public function getCustomerList(Request $request) { - $thirdUserId = $request->input('third_user_id'); // bps_third_user的id + $merchantId = $request->input('merchant_id'); // bps_third_user的id $googleOAuthService = new GoogleOAuthService(); - $hasThirdUser = $googleOAuthService->getCustomerList($thirdUserId); + $hasThirdUser = $googleOAuthService->getCustomerListNew($merchantId); if (!$hasThirdUser) { return $this->errorResponse(300, 'Invalid state parameter'); } @@ -64,7 +84,48 @@ class CustomerController return $this->getAccountHierarchy($options); } - //管理用户访问权限 + //绑定接口-广告主体下层级账号 + public function handleBinding(Request $request) + { + $options = $request->all(); + $options['jwtClaims'] = $request->jwtClaims; + +// dump($options,22222222); + // token即uuid 例如:f47ac10b-58cc-4372-a567-0e02b2c3d479 + $redisKey = self::REDIS_KEY_PREFIX . $options['token']; + + // 尝试从 Redis 中获取缓存值 + $refresh_token = Redis::get($redisKey); +// dump($redisKey, $refresh_token, 444444); +// return $this->successResponse($refresh_token); + if ($refresh_token) { +// $options['refresh_token'] = $refresh_token; +// // 继续处理 Google Ads API 操作 +// $googleAdsAccounts = $this->getAccountHierarchyForBind($options); +// +// dump($googleAdsAccounts); + + $googleOAuthService = new GoogleOAuthService(); +// dump($options);return 0; + $hasThirdUser = $googleOAuthService->getCustomerListNew($options['jwtClaims']['merchant_id']); + dump($hasThirdUser,777); +// if(!empty($hasThirdUser)) { +// //$googleAdsAccounts和$hasThirdUser 合并 +// foreach ($hasThirdUser as $key => $value) { +// +// } +// +// return $this->successResponse($hasThirdUser);} +// } + + + } else { + return $this->errorResponse(300, 'token expired'); + } + + } + + // 没调用 管理用户访问权限 public function accountAccess(Request $request) { $options = $request->all(); @@ -94,14 +155,14 @@ class CustomerController public function getAccountHierarchy($options): Response { if (!isset($options['manager_customer_id'])) { - $resourceName = []; + $resourceName = []; $listAccessibleCustomers = $this->googleAdsAccountService->runListAccessibleCustomers($options); foreach ($listAccessibleCustomers as $rootAccountId) { $options['manager_customer_id'] = $rootAccountId; //开发者 $options['login_customer_id'] = $rootAccountId; try { // 获取当前 rootAccountId 的所有账户 - $allAccountsByRoot = $this->googleAdsAccountService->runGetAccountHierarchy($options); + $allAccountsByRoot = $this->googleAdsAccountService->runGetAccountHierarchy($options); $resourceName[$rootAccountId] = $allAccountsByRoot; } catch (\Exception $e) { // 记录错误日志并跳过当前循环 @@ -113,7 +174,32 @@ class CustomerController $resourceName = $this->googleAdsAccountService->runListAccessibleCustomers($options); } - return $this->successResponse(['links_resource_name' => $resourceName]); + return $this->successResponse(['links_resource_name' => $resourceName]); + } + + /** + * 绑定接口-广告主体下层级账号 + * @throws ApiException + */ + public function getAccountHierarchyForBind($options) + { + //TODO 过滤经理账号 2025-2-13 + $resourceName = []; + $listAccessibleCustomers = $this->googleAdsAccountService->runListAccessibleCustomers($options); + foreach ($listAccessibleCustomers as $rootAccountId) { + $options['manager_customer_id'] = $rootAccountId; //开发者 + $options['login_customer_id'] = $rootAccountId; + try { + // 获取当前 rootAccountId 的所有账户 + $allAccountsByRoot = $this->googleAdsAccountService->runGetAccountHierarchy($options); + $resourceName[$rootAccountId] = $allAccountsByRoot; + } catch (\Exception $e) { + // 记录错误日志并跳过当前循环 + Log::error("Binding Account List Error processing rootAccountId {$rootAccountId}: " . $e->getMessage()); + continue; + } + } + return $resourceName; } /** diff --git a/app/controller/NoticeController.php b/app/controller/NoticeController.php new file mode 100644 index 0000000..afdb78d --- /dev/null +++ b/app/controller/NoticeController.php @@ -0,0 +1,98 @@ +input('state') ?? $request->jwtClaims['uid']; + $state = $request->input('state') ?? $request->jwtClaims['merchant_id']; + $code = $request->input('code'); // 授权码 + + if (!$state) { + return $this->errorResponse(300, 'Invalid state parameter'); + } + // state值验证通过,继续处理授权码 + $googleOAuthService = new GoogleOAuthService(); + + $tokens = $googleOAuthService->getRefreshToken($code); + + if (!isset($tokens['refresh_token'])) { + if (isset($tokens['access_token'])) { + return $this->errorResponse(300, 'Google Ads Account is Authorized'); + } + return $this->errorResponse(300, 'Refresh Token getting failed'); + } else { + $googleOAuthService->saveRefreshToken($tokens['refresh_token'], $state); + } + + return $this->successResponse($tokens, $request); + + } + + + public function initNewGoogleAdsAccountData(Request $request) + { + $state = $request->input('state') ??''; + if ($state != 'sdf^&^*7hkjhjk') { + return $this->errorResponse(300, 'Invalid state parameter'); + } + $refresh_token = $request->input('refresh_token'); // 授权码 + // state值验证通过,继续处理授权码 + $googleOAuthService = new GoogleOAuthService(); + + if (!isset($refresh_token)) { + return $this->errorResponse(300, 'Refresh Token getting failed'); + } else { + $googleOAuthService->initNewGoogleAdsAccountData($refresh_token); + } + + return $this->successResponse('', $request); + + } + + // 可以加入一些公共方法 + protected function successResponse($data, Request $request): Response + { +// if ($request->jwtNewToken) { +// return new Response(200, +// [ +// 'Content-Type' => 'application/json', +// 'X-New-Token' => $request->jwtNewToken +// ], +// json_encode($data, JSON_UNESCAPED_UNICODE)); +// } else { + return Json([ + 'code' => 0, + 'msg' => 'ok', + 'data' => $data, + ]); +// } + } + + protected function errorResponse($code, $message, $data = []): Response + { + return Json([ + 'code' => $code, + 'msg' => $message ?: 'error', + 'data' => $data + ]); + } + +} \ No newline at end of file diff --git a/app/controller/OAuthController.php b/app/controller/OAuthController.php index 4c3a906..f02d69c 100644 --- a/app/controller/OAuthController.php +++ b/app/controller/OAuthController.php @@ -9,6 +9,7 @@ use support\Response; use DI\Annotation\Inject; use app\model\ThirdUserAdvertiser; use app\model\ThirdUser; +use support\Redis; use app\event\GoogleAdsCustomers; use Webman\Event\Event; @@ -16,6 +17,9 @@ use Webman\Event\Event; class OAuthController { + // 育才定义 绑定广告账号时的该uuid的广告token Redis 键名前缀 + const REDIS_KEY_PREFIX = 'bps-goui:third:token:key:'; + /** * @Inject * @var GoogleOAuthService @@ -62,7 +66,7 @@ class OAuthController } - + //作废2025-2-13 public function handleCallback(Request $request) { // $state = $request->input('state') ?? $request->jwtClaims['uid']; @@ -90,6 +94,49 @@ class OAuthController } + public function handleCallbackNew(Request $request) + { +// $state = $request->input('state') ?? $request->jwtClaims['uid']; + $state = $request->input('state') ?? $request->jwtClaims['merchant_id']; + $code = $request->input('code'); // 授权码 + + if (!$state) { + return $this->errorResponse(300, 'Invalid state parameter'); + } + // state值验证通过,继续处理授权码 + $googleOAuthService = new GoogleOAuthService(); + + $tokens = $googleOAuthService->getRefreshToken($code); + + if (!isset($tokens['refresh_token'])) { + if (isset($tokens['access_token'])) { + return $this->errorResponse(300, 'Google Ads Account is Authorized'); + } + return $this->errorResponse(300, 'Refresh Token getting failed'); + } + +// 生成 UUID + $uuid = $this->generateUuid(); +// echo $uuid; // 例如:f47ac10b-58cc-4372-a567-0e02b2c3d479 + $redisKey = self::REDIS_KEY_PREFIX . $uuid; + //把$tokens['refresh_token']存入redis的redisKey, 并设置过期时间为10分钟 + Redis::setex($redisKey, 600, $tokens['refresh_token']); + // 保存refresh token到数据库 +// $googleOAuthService->saveRefreshToken($tokens['refresh_token'], $state, $uuid); +// // 触发事件 + return $this->successResponse(['token' => $uuid], $request); + + } + + public function generateUuid() + { + $data = random_bytes(16); + $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // 设置版本为 4 + $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // 设置变体为 RFC 4122 + return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)); + } + + public function getRefreshToken(Request $request) { $authCode = $request->input('code'); diff --git a/app/event/ShopifyOrders.php b/app/event/ShopifyOrders.php new file mode 100644 index 0000000..5868349 --- /dev/null +++ b/app/event/ShopifyOrders.php @@ -0,0 +1,324 @@ + $options['token'] + ]; + + $customerIds = []; + $orderIdsNotOrderCount = $orderIdsOrderCountOne = $orderIdsOrderCountOther = []; + $pageInfo = ""; + + while (true) { + $params = []; + if ($pageInfo !== "") { + $params = [ + 'limit' => 200, + 'page_info' => $pageInfo + ]; + } else { + $params = [ + 'limit' => 200, + 'fields' => 'id,orders_count,total_spent,last_order_id,created_at', +// 'created_at_min' => '2025-02-1T00:00:00-08:00', +// 'created_at_max' => '2025-02-13T23:59:59-08:00', + 'ids' => $options['aaa'] +// 'created_at_min' => '2025-02-14T00:00:00+00:00', +// 'created_at_max' => '2025-02-14T23:59:59+00:00' + ]; +// +// $createdAtMin = new DateTime($params['created_at_min']); +// $createdAtMax = new DateTime($params['created_at_max']); + } + +// dump($params,$headers); + dump(str_replace("{storeName}", $options['storeName'], self::SHOPIFY_API_URL_CUSTOMER)); + + try { + $response = $client->get(str_replace("{storeName}", $options['storeName'], self::SHOPIFY_API_URL_CUSTOMER), [ + 'headers' => $headers, + 'query' => $params + ]); + + $data = json_decode($response->getBody(), true); + +// dump($data); + + // Loop through the orders and collect the order IDs + foreach ($data['customers'] as $customer) { + $customerIds[] = (string)$customer['id']; + +// echo $order['id'] . PHP_EOL; // Log order ID + // 将日期时间字符串转换为 DateTime 对象 + $customerCreatedAt = new DateTime($customer['created_at']); + $customerOrderCount = max($customer['orders_count'], 0); + + // 判断 $orderCreatedAt 是否在 $createdAtMin 和 $createdAtMax 之间 +// if ($customerOrderCount >= $createdAtMin && $orderCustomerCreatedAt <= $createdAtMax) { +// $orderIdsCreatedAt[] = (string)$order['id']; +// } else { +// $orderIdsNotCreatedAt[] = (string)$order['id']; +// } +// dump($customer['id'],$customerOrderCount); + if ($customerOrderCount == 0) { + $orderIdsNotOrderCount[] = (string)$customer['id']; + } else if ($customerOrderCount == 1) { + $orderIdsOrderCountOne[] = (string)$customer['id']; + } else { + $orderIdsOrderCountOther[] = (string)$customer['id']; + } + +// if($order['customer']['']) +// $orderDatass[$customer['id']] = [ +// 'id' => $order['id'], +// 'cus' => $order['customer'] +// ]; + + } + $customerIds = array_unique($customerIds); + dump('Total number of customer IDs: ' . count($customerIds)); + dump('customer IDs: ' . implode(',', $customerIds)); + +// dump('Total number of orderIdsCreatedAt IDs: ' . count($orderIdsCreatedAt)); +// dump('orderIdsCreatedAt IDs: ' . implode(',', $orderIdsCreatedAt)); +// dump('Total number of orderIdsNotCreatedAt IDs: ' . count($orderIdsNotCreatedAt)); +// dump('orderIdsNotCreatedAt IDs: ' . implode(',', $orderIdsNotCreatedAt)); + dump('Total number of customerIdsNotOrderCount IDs: ' . count($orderIdsNotOrderCount)); + dump('customerIdsNotOrderCount IDs: ' . implode(',', $orderIdsNotOrderCount)); + dump('Total number of customerIdsOrderCountOne IDs: ' . count($orderIdsOrderCountOne)); + dump('customerIdsOrderCountOne IDs: ' . implode(',', $orderIdsOrderCountOne)); + dump('Total number of customerOrderCountOther IDs: ' . count($orderIdsOrderCountOther)); + dump('customerOrderCountOther IDs: ' . implode(',', $orderIdsOrderCountOther)); +// dump($orderDatass); + // Check if there's a next page + if (isset($response->getHeader('link')[0]) && strpos($response->getHeader('link')[0], 'rel="next"')) { + preg_match('/page_info=([^&]*)/', $response->getHeader('link')[0], $matches); + $pageInfo = $matches[1]; + } else { + break; // Exit loop if no more pages + } + } catch (GuzzleException $e) { + echo 'Error fetching Shopify orders: ' . $e->getMessage() . PHP_EOL; + break; + } + } + +// echo 'Total number of order IDs: ' . count($orderIds) . PHP_EOL; +// dump('Total number of order IDs: ' . count($orderIds)); +// dump('Order IDs: ' . implode(',', $orderIds)); + return ; + } + +// const SHOPIFY_API_URL = 'https://fefc94-67.myshopify.com/admin/api/2024-07/orders.json'; + + public function fetchOrderIds($options = []) + { + $client = new Client(); + $headers = [ + 'X-Shopify-Access-Token' => $options['token'] + ]; + + $orderIds = []; + $pageInfo = ""; + + while (true) { + $params = []; + if ($pageInfo !== "") { + $params = [ + 'limit' => 200, + 'page_info' => $pageInfo + ]; + } else { + $params = [ + 'limit' => 200, + 'status' => 'any', + 'fields' => 'id,customer', + 'created_at_min' => '2025-02-13T00:00:00-08:00', + 'created_at_max' => '2025-02-13T23:59:59-08:00' +// 'created_at_min' => '2025-02-14T00:00:00+00:00', +// 'created_at_max' => '2025-02-14T23:59:59+00:00' + ]; + + $createdAtMin = new DateTime($params['created_at_min']); + $createdAtMax = new DateTime($params['created_at_max']); + } + +// dump($params,$headers); + dump(str_replace("{storeName}", $options['storeName'], self::SHOPIFY_API_URL)); + + try { + $response = $client->get(str_replace("{storeName}", $options['storeName'], self::SHOPIFY_API_URL), [ + 'headers' => $headers, + 'query' => $params + ]); + + $data = json_decode($response->getBody(), true); + +// dump($data); + + // Loop through the orders and collect the order IDs + foreach ($data['orders'] as $order) { + $orderIds[] = (string)$order['id']; + $customerIds[] = (string)$order['customer']['id']; + +// echo $order['id'] . PHP_EOL; // Log order ID + // 将日期时间字符串转换为 DateTime 对象 +// $orderCustomerCreatedAt = new DateTime($order['customer']['created_at']); +// $orderCustomerOrderCount = $order['customer']['orders_count']?? 0; + + // 判断 $orderCreatedAt 是否在 $createdAtMin 和 $createdAtMax 之间 +// if ($orderCustomerCreatedAt >= $createdAtMin && $orderCustomerCreatedAt <= $createdAtMax) { +// $orderIdsCreatedAt[] = (string)$order['id']; +// } else { +// $orderIdsNotCreatedAt[] = (string)$order['id']; +// } +// if($orderCustomerOrderCount == 0){ +// $orderIdsNotOrderCount[] = (string)$order['id']; +// }else if($orderCustomerOrderCount == 1){ +// $orderIdsOrderCountOne[] = (string)$order['id']; +// }else{ +// $orderIdsOrderCountOther[] = (string)$order['id']; +// } + +// if($order['customer']['']) +// $orderDatass[$order['id']] = [ +// 'id' => $order['id'], +// 'cus' => $order['customer'] +// ]; + + } + $customerIds = array_unique($customerIds); + $customerIdsStr = implode(',', $customerIds); + + dump('Total number of customer IDs: ' . count($customerIds)); + dump('customer IDs: ' . $customerIdsStr); + dump('Total number of order IDs: ' . count($orderIds)); + dump('Order IDs: ' . implode(',', $orderIds)); + Event::emit(ShopifyOrders::event_customer, ['storeName' => 'fefc94-67', 'token' => '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','aaa' => $customerIdsStr]); +// dump('Total number of orderIdsCreatedAt IDs: ' . count($orderIdsCreatedAt)); +// dump('orderIdsCreatedAt IDs: ' . implode(',', $orderIdsCreatedAt)); +// dump('Total number of orderIdsNotCreatedAt IDs: ' . count($orderIdsNotCreatedAt)); +// dump('orderIdsNotCreatedAt IDs: ' . implode(',', $orderIdsNotCreatedAt)); +// dump('orderIdsNotOrderCount IDs: ' . implode(',', $orderIdsNotOrderCount)); +// dump('orderIdsOrderCountOne IDs: ' . implode(',', $orderIdsOrderCountOne)); +// dump('orderIdsOrderCountOther IDs: ' . implode(',', $orderIdsOrderCountOther)); +// dump($orderDatass); + // Check if there's a next page + if (isset($response->getHeader('link')[0]) && strpos($response->getHeader('link')[0], 'rel="next"')) { + preg_match('/page_info=([^&]*)/', $response->getHeader('link')[0], $matches); + $pageInfo = $matches[1]; + } else { + break; // Exit loop if no more pages + } + } catch (GuzzleException $e) { + echo 'Error fetching Shopify orders: ' . $e->getMessage() . PHP_EOL; + break; + } + } + +// echo 'Total number of order IDs: ' . count($orderIds) . PHP_EOL; +// dump('Total number of order IDs: ' . count($orderIds)); +// dump('Order IDs: ' . implode(',', $orderIds)); + return $orderIds; + } + + // Method to save order data into bps.shopify_orders + private function saveShopifyOrder($orderData) + { + // Define the table name dynamically + $tableName = 'bps.shopify_orders'; + $tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName; + + // Prepare data for insertion + $data = [ + 'id' => $orderData['id'], + 'admin_graphql_api_id' => $orderData['admin_graphql_api_id'], + 'browser_ip' => $orderData['browser_ip'], + 'buyer_accepts_marketing' => $orderData['buyer_accepts_marketing'], + 'cancel_reason' => $orderData['cancel_reason'], + 'cancelled_at' => $orderData['cancelled_at'], + 'created_at' => $orderData['created_at'], + 'currency' => $orderData['currency'], + 'current_subtotal_price' => $orderData['current_subtotal_price'], + 'current_total_discounts' => $orderData['current_total_discounts'], + 'current_total_price' => $orderData['current_total_price'], + 'customer_email' => $orderData['customer_email'], + 'customer_name' => $orderData['customer_name'], + 'customer_phone' => $orderData['customer_phone'] + ]; + + // SQL statement for inserting or updating order data + $sql = " + INSERT INTO {$tableName} ( + id, + admin_graphql_api_id, + browser_ip, + buyer_accepts_marketing, + cancel_reason, + cancelled_at, + created_at, + currency, + current_subtotal_price, + current_total_discounts, + current_total_price, + customer_email, + customer_name, + customer_phone + ) + VALUES ( + :id, + :admin_graphql_api_id, + :browser_ip, + :buyer_accepts_marketing, + :cancel_reason, + :cancelled_at, + :created_at, + :currency, + :current_subtotal_price, + :current_total_discounts, + :current_total_price, + :customer_email, + :customer_name, + :customer_phone + ) + ON CONFLICT (id) + DO UPDATE SET + admin_graphql_api_id = EXCLUDED.admin_graphql_api_id, + browser_ip = EXCLUDED.browser_ip, + buyer_accepts_marketing = EXCLUDED.buyer_accepts_marketing, + cancel_reason = EXCLUDED.cancel_reason, + cancelled_at = EXCLUDED.cancelled_at, + created_at = EXCLUDED.created_at, + currency = EXCLUDED.currency, + current_subtotal_price = EXCLUDED.current_subtotal_price, + current_total_discounts = EXCLUDED.current_total_discounts, + current_total_price = EXCLUDED.current_total_price, + customer_email = EXCLUDED.customer_email, + customer_name = EXCLUDED.customer_name, + customer_phone = EXCLUDED.customer_phone + "; + + // Execute the SQL query + ThinkDb::execute($sql, $data); + } +} diff --git a/app/model/BpsAdsMerchantRelation.php b/app/model/BpsAdsMerchantRelation.php new file mode 100644 index 0000000..67e6128 --- /dev/null +++ b/app/model/BpsAdsMerchantRelation.php @@ -0,0 +1,39 @@ + 'int', + 'platform' => 'int', + 'ext_info' => 'json', // 将 ext_info 字段映射为 JSON 类型 + 'is_unbind' => 'bool', + 'is_del' => 'bool', + ]; + + // 默认值设置 + protected $defaults = [ + 'currency' => '', // 设置默认货币类型 + 'ext_info' => '{}', // 设置默认 ext_info 为空的 JSON 对象 + 'is_unbind' => false, // 设置默认 is_unbind 为 false + 'is_del' => false, // 设置默认 is_del 为 false + ]; + + // 其他自定义方法可以根据需求添加 +} \ No newline at end of file diff --git a/app/process/UpdateGoogleAdsTask.php b/app/process/UpdateGoogleAdsTask.php index 9e94382..89ae8fa 100644 --- a/app/process/UpdateGoogleAdsTask.php +++ b/app/process/UpdateGoogleAdsTask.php @@ -11,6 +11,7 @@ use app\event\GoogleAdsAds; use app\event\GoogleAdsAssets; use app\event\GoogleAdsAssetRelations; use app\event\GoogleAdsDateDatas; +use app\event\ShopifyOrders; use Webman\Event\Event; use Workerman\Crontab\Crontab; @@ -25,7 +26,7 @@ class UpdateGoogleAdsTask // 每15分钟执行一次 - new Crontab('* * */11 * * *', function () { + new Crontab('2 2 0 * * *', function () { $data = []; $data['endDate'] = date('Y-m-d'); // 获取今天的日期 $data['startDate'] = date('Y-m-d', strtotime('-7 days')); // 获取7天前的日期 @@ -62,7 +63,7 @@ class UpdateGoogleAdsTask // } // ); // 每15分钟执行一次 - new Crontab('* * */14 * * *', function () { + new Crontab('2 5 0 * * *', function () { $data = []; $data['endDate'] = date('Y-m-d'); // 获取今天的日期 $data['startDate'] = date('Y-m-d', strtotime('-7 days')); // 获取7天前的日期 @@ -72,7 +73,7 @@ class UpdateGoogleAdsTask ); // 每15分钟执行一次 - new Crontab('30 * */12 * * *', function () { + new Crontab('30 2 */12 * * *', function () { dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsGroups::event . '开始'); Event::emit(GoogleAdsGroups::event, []); @@ -82,14 +83,14 @@ class UpdateGoogleAdsTask ); // 每15分钟执行一次 - new Crontab('5 * */12 * * *', function () { + new Crontab('5 2 */12 * * *', function () { dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAds::event . '开始'); Event::emit(GoogleAdsAds::event, []); } ); // 每15分钟执行一次 - new Crontab('* * */12 * * *', function () { + new Crontab('1 2 */12 * * *', function () { dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsCreatives::event . '开始'); Event::emit(GoogleAdsCreatives::event, []); @@ -107,6 +108,14 @@ class UpdateGoogleAdsTask } ); + //临时调试shopify店铺定时任务 +// new Crontab('*/20 * * * * *', function () { +// dump(date('Y-m-d H:i:s') . '更新' . ShopifyOrders::event . '开始'); +// Event::emit(ShopifyOrders::event, ['storeName' => 'fefc94-67', 'token' => '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']); // PSA shop +// Event::emit(ShopifyOrders::event, ['storeName' => 'aeb0e7-b3', 'token' => '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']);// VIVI shop +// } +// ); + // 每15分钟执行一次 // new Crontab('58 */15 * * * *', function () { diff --git a/app/service/AdsInsightService.php b/app/service/AdsInsightService.php index 9f6c824..bee0b66 100644 --- a/app/service/AdsInsightService.php +++ b/app/service/AdsInsightService.php @@ -5,6 +5,7 @@ namespace app\service; use app\model\Ad; use app\model\BpsAdCreativeInsight; use app\model\BpsAdInsight; +use app\model\BpsAdsMerchantRelation; use app\model\DayData; use app\model\Campaign; use app\model\BpsAdCampaign; @@ -1180,13 +1181,16 @@ class AdsInsightService ]; } // 构建查询条件 - $query = ThirdUserAdvertiser::alias('a') +// $query = ThirdUserAdvertiser::alias('a') +// ->cache(false) +// ->where('a.advertiser_id', 'in', $customerIds); + $query = BpsAdsMerchantRelation::alias('bamr') ->cache(false) - ->where('a.advertiser_id', 'in', $customerIds); + ->where('bamr.account_id', 'in', $customerIds); // 仅计数时优化查询 if ($countOnly) { - return $query->count('distinct(a.advertiser_id)'); // 只查询总记录数 + return $query->count('distinct(bamr.account_id)'); // 只查询总记录数 } // 动态构建日期条件 $dateCondition = ''; @@ -1197,9 +1201,8 @@ class AdsInsightService // 基础查询:广告和日数据表联接 // 其他联表及字段计算 - $query->leftJoin('bps.bps_ads_insights d', "a.advertiser_id = d.account_id AND {$dateCondition}") - ->leftJoin('bps.bps_third_user u', 'a.doc_ = u.id') - ->field('a.advertiser_id, a.advertiser_name,u.third_type, + $query->leftJoin('bps.bps_ads_insights d', "bamr.account_id = d.account_id AND {$dateCondition}") + ->field('bamr.account_id, bamr.account_name,bamr.platform, COALESCE(SUM(d.clicks), 0) as clicks, COALESCE(SUM(d.spend) / 1000000, 0) as spend, COALESCE(SUM(d.impressions), 0) as impressions, @@ -1211,8 +1214,8 @@ class AdsInsightService COALESCE(SUM(d.revenue) / 1000000, 0) as revenue, COALESCE(SUM(d.total_cost) / 1000000, 0) as total_cost, -1 as conversion_rate, -1 as roas, -1 as ctr, -1 as net_profit, -1 as net_profit_margin, -1 as net_profit_on_ad_spend') - ->group('a.advertiser_id, a.advertiser_name,u.third_type') - ->where('a.advertiser_id', 'in', $customerIds); // 添加 customerIds 条件 + ->group('bamr.account_id, bamr.account_name,bamr.platform') + ->where('bamr.account_id', 'in', $customerIds); // 添加 customerIds 条件 // 如果传入了 status 参数,按状态筛选 // if ($status !== 0) { // $query->where('a.status', '=', $status); @@ -1220,15 +1223,15 @@ class AdsInsightService // 添加关键字过滤条件 $query->where(function ($query) use ($keyword, $platformType) { if ($keyword) { - $query->whereRaw('LOWER(a.advertiser_name) LIKE ?', ['%' . strtolower($keyword) . '%']); + $query->whereRaw('LOWER(bamr.account_name) LIKE ?', ['%' . strtolower($keyword) . '%']); } if ($platformType) { - $a = (int)$platformType; - $platformTypeNames = [1 => 'facebook', 2 => 'google', 3 => 'tiktok']; - $query->where('u.third_type', '=', $platformTypeNames[$a]); +// $a = (int)$platformType; +// $platformTypeNames = [1 => 'facebook', 2 => 'google', 3 => 'tiktok']; + $query->where('bamr.platform', '=', $platformType); } }); - $query->order('u.third_type', 'asc'); + $query->order('bamr.platform', 'asc'); // 根据 $requireSpend 参数决定是否添加 SUM(d.spend) > 0 的条件 if ($requireSpend) { @@ -1289,11 +1292,12 @@ class AdsInsightService $net_profit_margin = $item['revenue'] > 0 ? round(($item['revenue'] - $item['total_cost']) / $item['revenue'], 2) * 100 . '%' : '-'; // Net Profit on Ad Spend 的计算:广告支出净利润 = (收入 - 总成本) / 广告支出 $net_profit_on_ad_spend = $item['spend'] > 0 ? round(($item['revenue'] - $item['total_cost']) / $item['spend'], 2) * 100 . '%' : '-'; - $platformTypeIds = ['facebook' => 1, 'google' => 2, 'tiktok' => 3]; +// $platformTypeIds = ['facebook' => 1, 'google' => 2, 'tiktok' => 3]; return [ - 'user_id' => $item['advertiser_id'], - 'platform_type' => $platformTypeIds[$item['third_type']], - 'advertiser_name' => $item['advertiser_name'] ?: '-', // 若 name 为空则显示 '-' + 'user_id' => $item['account_id'], +// 'platform_type' => $platformTypeIds[$item['third_type']], + 'platform_type' => $item['platform'], + 'advertiser_name' => $item['account_name'] ?: '-', // 若 name 为空则显示 '-' // 'ad_set_name' => $item['ad_set_name'] ?: '-', // 若 name 为空则显示 '-' // 'status' => $item['status'], 'platform_purchase' => number_format($item['platform_purchase']), @@ -1507,288 +1511,6 @@ class AdsInsightService ]; } - public static function getThirdUserList($platformType, $userIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null) - { - // 检查 userIds 是否为空,直接返回空结构 - if (empty($userIds)) { - return [ - 'pagination' => [ - 'startIndex' => 0, - 'maxResults' => $pageSize, - 'count' => 0, - 'pageNo' => $page, - 'pageSize' => $pageSize, - 'pages' => 0, - ], - 'statistics' => [], - 'data' => [], - ]; - } - $userCount = count($userIds); -// dump($userIds); - // 动态构建日期条件 - $dateCondition = '1=1'; // 默认没有日期限制 - if ($startDate && $endDate) { - $dateCondition = "d.date BETWEEN '{$startDate}' AND '{$endDate}'"; - } -// u.user_id as third_user_id, u.third_type, u.facebook_user_id, -// a.advertiser_id, a.advertiser_name, a.google_manager, a.google_test_account, - // 基础查询:第三方用户和广告商数据表联接 - $query = ThirdUser::alias('u') - ->cache(false) // 强制不使用缓存 - ->leftJoin('bps.bps_third_user_advertiser a', "u.id = a.doc_") - ->field('u.id as user_id,u.third_type,a.advertiser_name, - - COALESCE(SUM(d.platform_purchase), 0) as platform_purchase, - COALESCE(SUM(d.pixel_purchase), 0) as pixel_purchase, - COALESCE(SUM(d.spend) / 1000000, 0) as spend, - COALESCE(SUM(d.impressions), 0) as impressions, - COALESCE(SUM(d.clicks), 0) as clicks, - COALESCE(SUM(d.adds_to_cart), 0) as adds_to_cart, - COALESCE(SUM(d.cost_per_atc), 0) as cost_per_atc, - COALESCE(SUM(d.purchases), 0) as purchases, - COALESCE(SUM(d.purchases_value/1000000), 0) as purchases_value, - COALESCE(SUM(d.revenue/1000000), 0) as revenue, - COALESCE(SUM(d.total_cost)/1000000, 0) as total_cost') - ->leftJoin('bps.bps_ads_insights d', "a.advertiser_id = d.account_id AND {$dateCondition}") - ->where('u.id', 'in', $userIds); // 添加 userIds 条件 - - // 添加关键字过滤条件 - $query->where(function ($query) use ($keyword, $platformType) { - if ($keyword) { - $query->where('a.advertiser_name', 'like', '%' . $keyword . '%'); - } - if ($platformType) { - $query->where('d.platform', '=', $platformType); - } - }); - - // 添加 GROUP BY 子句 -// $query->group('u.id, u.user_id, u.third_type, u.facebook_user_id, -// a.advertiser_id, a.advertiser_name, a.google_manager, a.google_test_account'); - $query->group('u.id,u.third_type,a.advertiser_name'); - - // 调试打印 SQL - - - // 获取所有符合条件的数据(不分页) - $allUsers = $query->select()->toArray(); -// dump($query->getLastSql()); -// -// dump($allUsers); - - // 汇总统计数据 - $total_spend = array_sum(array_column($allUsers, 'spend')); - $total_impressions = array_sum(array_column($allUsers, 'impressions')); - $total_clicks = array_sum(array_column($allUsers, 'clicks')); - $total_adds_to_cart = array_sum(array_column($allUsers, 'adds_to_cart')); - $total_cost_per_atc = array_sum(array_column($allUsers, 'cost_per_atc')); - $total_purchases = array_sum(array_column($allUsers, 'purchases')); - $total_purchases_value = array_sum(array_column($allUsers, 'purchases_value')); - $total_revenue = array_sum(array_column($allUsers, 'revenue')); - $total_cost = array_sum(array_column($allUsers, 'total_cost')); - - // 计算 ROAS - $roas = $total_spend == 0 ? '-' : round($total_purchases_value / $total_spend, 2); - $cost_per_purchase = $total_purchases == 0 ? 0 : round($total_spend / $total_purchases, 2); - // 计算 CTR - $ctr = $total_impressions > 0 ? number_format(($total_clicks / $total_impressions) * 100, 2) . '%' : '-'; - - // 汇总统计字段初始化 - $statistics = [ - 'platform_purchase' => 0, - 'pixel_purchase' => 0, - 'roas' => $total_spend == 0 ? '-' : round($total_purchases_value / $total_spend, 2), - 'amount_spend' => '$' . number_format($total_spend, 2) ?: '$0.00', // 格式化支出 - 'clicks' => $total_clicks, - 'impressions' => $total_impressions, - 'adds_to_cart' => $total_adds_to_cart, - 'cost_per_atc' => $total_cost_per_atc, - 'purchases' => $total_purchases, - 'purchases_value' => '$' . number_format($total_purchases_value, 2) ?: '$0.00', // 格式化销售额$total_purchases_value, - 'cost_per_purchase' => '$' . number_format($cost_per_purchase, 2) ?: '$0.00', // 格式化销售额$total_purchases_value, - 'revenue' => '$' . number_format($total_revenue, 2) ?: '$0.00', // 格式化收入 - 'total_cost' => '$' . number_format($total_cost, 2) ?: '$0.00', // 格式化总成本 - 'conversion_rate' => $total_clicks == 0 ? '-' : round(($total_purchases / $total_clicks) * 100, 2) . '%', // 转换率 - 'net_profit' => ($total_revenue - $total_cost) >= 0 ? '+$' . number_format($total_revenue - $total_cost, 2) : '-$' . number_format(abs($total_revenue - $total_cost), 2), // 净利润 - 'net_profit_margin' => $total_revenue == 0 ? '-' : round(($total_revenue - $total_cost) / $total_revenue, 2) * 100 . '%', // 净利润率 - 'net_profit_on_ad_spend' => $total_spend == 0 ? '-' : round(($total_revenue - $total_cost) / $total_spend, 2) * 100 . '%', // 广告支出净利润 - 'ctr' => $ctr, // CTR 字段 - ]; - - // 获取分页数据 - $users = $query->paginate($pageSize, false, ['page' => $page]); - - // 按照 third_user_id 聚合统计字段 - $aggregatedUsers = []; - -// 遍历每个用户的统计数据 - foreach ($users->items() as $item) { - $thirdUserId = $item['user_id']; - - if (!isset($aggregatedUsers[$thirdUserId])) { - $aggregatedUsers[$thirdUserId] = [ - 'user_id' => $item['user_id'], - 'platform_type' => self::getPlatformType($item['third_type']), - 'advertiser_name' => $item['advertiser_name'], - 'platform_purchase' => 0, - 'pixel_purchase' => 0, - 'roas' => 0, - 'spend' => 0, - 'impressions' => 0, - 'clicks' => 0, - 'adds_to_cart' => 0, - 'cost_per_atc' => 0, - 'purchases' => 0, - 'purchases_value' => 0, - 'cost_per_purchase' => 0, - 'revenue' => 0, - 'total_cost' => 0, - 'net_profit' => '-', // 没有提供 net_profit,保持为 '-' - 'net_profit_margin' => '-', // 没有提供 net_profit_margin,保持为 '-' - 'net_profit_on_ad_spend' => '-', // 没有提供 net_profit_on_ad_spend,保持为 '-' - - ]; - } - - // 汇总统计 - $aggregatedUsers[$thirdUserId]['spend'] += $item['spend']; - $aggregatedUsers[$thirdUserId]['impressions'] += $item['impressions']; - $aggregatedUsers[$thirdUserId]['clicks'] += $item['clicks']; - $aggregatedUsers[$thirdUserId]['adds_to_cart'] += $item['adds_to_cart']; - $aggregatedUsers[$thirdUserId]['cost_per_atc'] += $item['cost_per_atc']; - $aggregatedUsers[$thirdUserId]['purchases'] += $item['purchases']; - $aggregatedUsers[$thirdUserId]['purchases_value'] += $item['purchases_value']; - $aggregatedUsers[$thirdUserId]['revenue'] += $item['revenue']; - $aggregatedUsers[$thirdUserId]['total_cost'] += $item['total_cost']; - $aggregatedUsers[$thirdUserId]['platform_purchase'] += $item['platform_purchase']; - $aggregatedUsers[$thirdUserId]['pixel_purchase'] += $item['pixel_purchase']; - } - -// 计算统计口径字段:ROAS, CTR等 - foreach ($aggregatedUsers as $userId => $data) { - $total_spend = $data['spend']; - $total_purchases_value = $data['purchases_value']; - $total_revenue = $data['revenue']; - $total_cost = $data['total_cost']; - $total_clicks = $data['clicks']; - $total_impressions = $data['impressions']; - - // CTR 的计算:点击率 = 点击数 / 展示数 - $ctr = $data['impressions'] > 0 ? number_format(($data['clicks'] / $data['impressions']) * 100, 2) . '%' : '-'; - // Conversion Rate 的计算:转换率 = 购买数 / 点击数 - $conversion_rate = $data['clicks'] > 0 ? round(($data['purchases'] / $data['clicks']) * 100, 2) . '%' : '-'; - // Net Profit 的计算:净利润 = 收入 - 总成本 - $net_profit = ($data['revenue'] - $data['total_cost']) >= 0 ? '+$' . number_format($data['revenue'] - $data['total_cost'], 2) : '-$' . number_format(abs($data['revenue'] - $data['total_cost']), 2); - // Net Profit Margin 的计算:净利润率 = 净利润 / 收入 - $net_profit_margin = $data['revenue'] > 0 ? round(($data['revenue'] - $data['total_cost']) / $data['revenue'], 2) * 100 . '%' : '-'; - // Net Profit on Ad Spend 的计算:广告支出净利润 = (收入 - 总成本) / 广告支出 - $net_profit_on_ad_spend = $data['spend'] > 0 ? round(($data['revenue'] - $data['total_cost']) / $data['spend'], 2) * 100 . '%' : '-'; - - // 计算 ROAS, CTR 和其他需要的字段 - $aggregatedUsers[$userId]['roas'] = $total_spend == 0 ? '-' : round($total_purchases_value / $total_spend, 2); - $aggregatedUsers[$userId]['amount_spend'] = '$' . number_format($total_spend, 2) ?: '$0.00'; - $aggregatedUsers[$userId]['purchases_value'] = '$' . number_format($total_purchases_value, 2) ?: '$0.00'; - $aggregatedUsers[$userId]['cost_per_purchase'] = $data['purchases'] == 0 ? '$0.00' : '$' . number_format($total_purchases_value / $data['purchases'], 2); - $aggregatedUsers[$userId]['revenue'] = '$' . number_format($total_revenue, 2) ?: '$0.00'; - $aggregatedUsers[$userId]['total_cost'] = '$' . number_format($total_cost, 2) ?: '$0.00'; - $aggregatedUsers[$userId]['conversion_rate'] = $conversion_rate; - $aggregatedUsers[$userId]['ctr'] = $ctr; - $aggregatedUsers[$userId]['net_profit'] = $net_profit; - $aggregatedUsers[$userId]['net_profit_margin'] = $net_profit_margin; - $aggregatedUsers[$userId]['net_profit_on_ad_spend'] = $net_profit_on_ad_spend; - } - // 如果 aggregatedUsers 为空,返回默认的数据结构 - if (empty($aggregatedUsers) && !$keyword) { - $emptyUser = []; - $query = ThirdUser::alias('u') - ->cache(false) // 强制不使用缓存 - ->leftJoin('bps.bps_third_user_advertiser a', "u.id = a.doc_") - ->field('u.id as user_id,u.third_type,a.advertiser_name'); - // 添加关键字过滤条件 - $query->where(function ($query) use ($platformType) { -// if ($keyword) { -// $query->where('a.advertiser_name', 'like', '%' . $keyword . '%'); -// } - if ($platformType) { - $a = (int)$platformType; - $platformTypeNames = [1 => 'facebook', 2 => 'google', 3 => 'tiktok']; - $query->where('u.third_type', '=', $platformTypeNames[$a]); - } - }); - - // 获取所有符合条件的数据(不分页) - $allUsers = $query->select()->toArray(); - foreach ($allUsers as $user) { - if (in_array($user['user_id'], $userIds)) { - $emptyUser[] = [ - 'user_id' => $user['user_id'], - 'platform_type' => (int)$platformType, - 'advertiser_name' => $user['advertiser_name'], - 'platform_purchase' => 0, - 'pixel_purchase' => 0, - 'spend' => 0, - 'impressions' => 0, - 'clicks' => 0, - 'adds_to_cart' => 0, - 'cost_per_atc' => 0, - 'purchases' => 0, - 'purchases_value' => 0, - 'revenue' => 0, - 'total_cost' => 0, - 'conversion_rate' => '-', - 'net_profit' => '-', - 'net_profit_margin' => '-', - 'net_profit_on_ad_spend' => '-', - 'ctr' => '-', - ]; - } - } -// dump($allUsers,'222'); - - return [ - 'pagination' => [ - 'startIndex' => ($page - 1) * $pageSize, - 'maxResults' => $pageSize, - 'count' => count($emptyUser), - 'pageNo' => $page, - 'pageSize' => $pageSize, - 'pages' => 0, - ], - 'statistics' => $statistics, - 'data' => $emptyUser - ]; - } - - - // 使用 array_values 移除键名 - $dataWithoutKeys = array_values($aggregatedUsers); - // 最终分页信息 - $pagination = [ -// 'startIndex' => ($page - 1) * $pageSize, -// 'maxResults' => $pageSize, -//// 'count' => $users->total(), -// 'count' => $userCount, -// 'pageNo' => $page, -// 'pageSize' => $pageSize, -// 'pages' => ceil($users->total() / $pageSize), - - 'startIndex' => ($page - 1) * $pageSize + 1, // 确保索引从 1 开始 - 'maxResults' => count($dataWithoutKeys), // 当前页实际返回数据数量 - 'count' => count($dataWithoutKeys), // 符合条件的总记录数 - 'pageNo' => $page, // 当前页码 - 'pageSize' => $pageSize, // 每页条数 - 'pages' => (int)ceil(count($dataWithoutKeys) / $pageSize), // 总页数 - ]; - - return [ - 'pagination' => $pagination, - 'statistics' => $statistics, - 'data' => $dataWithoutKeys, - ]; - } - - public static function getCreativeInsightData($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null, $requireSpend = false, $countOnly = false) { // 1. 创建查询对象,初始化 BpsAdCreativeInsight 查询 diff --git a/app/service/BpsAdAccountService.php b/app/service/BpsAdAccountService.php index c48ed1f..073e558 100644 --- a/app/service/BpsAdAccountService.php +++ b/app/service/BpsAdAccountService.php @@ -2,10 +2,11 @@ namespace app\service; -use GuzzleHttp\Client; use think\facade\Db as ThinkDb; use app\model\ThirdUserAdvertiser; -use app\model\ThirdUser; + +//作废2025-2-13 +use app\model\BpsAdsMerchantRelation; //use Webman\RedisQueue\Redis; use Webman\RedisQueue\Client as QueueClient; @@ -14,38 +15,54 @@ use app\event\GoogleAdsCustomers; class BpsAdAccountService { - public function getCustomerList($third_user_id = 0) - { - $tableName = 'bps_third_user_advertiser'; - $tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName; - - $sql = "SELECT * FROM {$tableName} WHERE doc_ = :third_user_id"; - $data = ['third_user_id' => $third_user_id]; - - return ThinkDb::query($sql, $data); - } /** * 批量获取全部Google广告账号数据 - * + * 作废2025-2-13 + */ +// public function getGoogleAdAccounts($options = []) +// { +// if (!empty($options)) { +// $refreshToken = $options['refresh_token']; +// // 获取符合条件的客户ID数组 +// $customers = ThirdUserAdvertiser::alias('tua') +// ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 +// ->where('tu.third_type', 'google') // 筛选 third_type 为 google 的记录 +// ->where('tu.access_token', $refreshToken) // 筛选 third_type 为 google 的记录 +// ->field('tua.advertiser_id as account_id,tua.google_login_customer_id as login_customer_id,tua.google_test_account as test_account,tua.google_manager as manager, tu.access_token as refresh_token') // 获取 advertiser_id 字段 +// ->select(); // 执行查询 +// } else { +// // 获取符合条件的客户ID数组 +// $customers = ThirdUserAdvertiser::alias('tua') +// ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 +// ->where('tu.third_type', 'google') // 筛选 third_type 为 google 的记录 +// ->field('tua.advertiser_id as account_id,tua.google_login_customer_id as login_customer_id,tua.google_test_account as test_account,tua.google_manager as manager, tu.access_token as refresh_token') // 获取 advertiser_id 字段 +// ->select(); // 执行查询 +// } +// } + + /** + * 批量获取全部Google广告账号数据 + *作废2025-2-13 */ public function getGoogleAdAccounts($options = []) { if (!empty($options)) { - $refreshToken = $options['refresh_token']; - // 获取符合条件的客户ID数组 - $customers = ThirdUserAdvertiser::alias('tua') - ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 - ->where('tu.third_type', 'google') // 筛选 third_type 为 google 的记录 - ->where('tu.access_token', $refreshToken) // 筛选 third_type 为 google 的记录 - ->field('tua.advertiser_id as account_id,tua.google_login_customer_id as login_customer_id,tua.google_test_account as test_account,tua.google_manager as manager, tu.access_token as refresh_token') // 获取 advertiser_id 字段 + $merchant_id = $options['merchant_id']; + $customers = BpsAdsMerchantRelation::alias('bamr') + ->where('bamr.platform', 2) + ->where('bamr.merchant_id', $merchant_id) + ->where('bamr.is_unbind', 'f') + ->where('bamr.is_del', 'f') + ->field('bamr.account_id, bamr.refresh_token') ->select(); // 执行查询 } else { // 获取符合条件的客户ID数组 - $customers = ThirdUserAdvertiser::alias('tua') - ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 - ->where('tu.third_type', 'google') // 筛选 third_type 为 google 的记录 - ->field('tua.advertiser_id as account_id,tua.google_login_customer_id as login_customer_id,tua.google_test_account as test_account,tua.google_manager as manager, tu.access_token as refresh_token') // 获取 advertiser_id 字段 + $customers = ThirdUserAdvertiser::alias('bamr') + ->where('bamr.platform', 2) + ->where('bamr.is_unbind', 'f') + ->where('bamr.is_del', 'f') + ->field('bamr.account_id, bamr.refresh_token') ->select(); // 执行查询 } @@ -63,25 +80,61 @@ class BpsAdAccountService /** * 批量获取全部meta广告账号数据 - * + * 作废2025-2-13 + */ +// public function getMetaAdAccounts($options = []) +// { +// if (!empty($options)) { +// $refreshToken = $options['refresh_token']; +// // 获取符合条件的客户ID数组 +// $customers = ThirdUserAdvertiser::alias('tua') +// ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 +// ->where('tu.third_type', 'facebook') // 筛选 third_type 为 google 的记录 +// ->where('tu.access_token', $refreshToken) // 筛选 third_type 为 google 的记录 +// ->field('tua.advertiser_id as account_id, tu.access_token as refresh_token') // 获取 advertiser_id 字段 +// ->select(); // 执行查询 +// } else { +// // 获取符合条件的客户ID数组 +// $customers = ThirdUserAdvertiser::alias('tua') +// ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 +// ->where('tu.third_type', 'facebook') // 筛选 third_type 为 google 的记录 +// ->field('tua.advertiser_id as account_id, tu.access_token as refresh_token') // 获取 advertiser_id 字段 +// ->select(); // 执行查询 +// } +// +// +// // 如果没有找到符合条件的广告主,抛出异常 +// if ($customers->isEmpty()) { +// return []; +//// throw new ApiException('No customers found for google third type'); +// } +// +// // 转换为简单的数组(提取 advertiser_id) +// return $customers->toArray(); +// +// } + + /** + * 批量获取全部meta广告账号数据 + *作废2025-2-13 */ public function getMetaAdAccounts($options = []) { if (!empty($options)) { - $refreshToken = $options['refresh_token']; + $merchant_id = $options['merchant_id']; // 获取符合条件的客户ID数组 - $customers = ThirdUserAdvertiser::alias('tua') - ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 - ->where('tu.third_type', 'facebook') // 筛选 third_type 为 google 的记录 - ->where('tu.access_token', $refreshToken) // 筛选 third_type 为 google 的记录 - ->field('tua.advertiser_id as account_id, tu.access_token as refresh_token') // 获取 advertiser_id 字段 + $customers = BpsAdsMerchantRelation::alias('bamr') + ->where('bamr.platform', 1) + ->where('bamr.merchant_id', $merchant_id) + ->field('bamr.account_id, bamr.access_token as refresh_token') ->select(); // 执行查询 } else { // 获取符合条件的客户ID数组 - $customers = ThirdUserAdvertiser::alias('tua') - ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 - ->where('tu.third_type', 'facebook') // 筛选 third_type 为 google 的记录 - ->field('tua.advertiser_id as account_id, tu.access_token as refresh_token') // 获取 advertiser_id 字段 + $customers = BpsAdsMerchantRelation::alias('bamr') + ->where('bamr.platform', 1) + ->where('bamr.is_unbind', 'f') + ->where('bamr.is_del', 'f') + ->field('bamr.account_id, bamr.access_token as refresh_token') ->select(); // 执行查询 } @@ -99,29 +152,66 @@ class BpsAdAccountService /** * 批量获取全部meta广告账号数据 - * + * 作废2025-2-13 + */ +// public function getTiktokAdAccounts($options = []) +// { +// if (!empty($options)) { +// $refreshToken = $options['refresh_token']; +// // 获取符合条件的客户ID数组 +// $customers = ThirdUserAdvertiser::alias('tua') +// ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 +// ->where('tu.third_type', 'tiktok') // 筛选 third_type 为 google 的记录 +// ->where('tu.access_token', $refreshToken) // 筛选 third_type 为 google 的记录 +// ->field('tua.advertiser_id as account_id, tu.access_token as refresh_token') // 获取 advertiser_id 字段 +// ->select(); // 执行查询 +// } else { +// // 获取符合条件的客户ID数组 +// $customers = ThirdUserAdvertiser::alias('tua') +// ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 +// ->where('tu.third_type', 'tiktok') // 筛选 third_type 为 google 的记录 +// ->field('tua.advertiser_id as account_id, tu.access_token as refresh_token') // 获取 advertiser_id 字段 +// ->select(); // 执行查询 +// } +// +// +// // 如果没有找到符合条件的广告主,抛出异常 +// if ($customers->isEmpty()) { +// return []; +//// throw new ApiException('No customers found for google third type'); +// } +// +// // 转换为简单的数组(提取 advertiser_id) +// return $customers->toArray(); +// +// } + + /** + * 批量获取全部tiktok广告账号数据 + *作废2025-2-13 */ public function getTiktokAdAccounts($options = []) { if (!empty($options)) { - $refreshToken = $options['refresh_token']; // 获取符合条件的客户ID数组 - $customers = ThirdUserAdvertiser::alias('tua') - ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 - ->where('tu.third_type', 'tiktok') // 筛选 third_type 为 google 的记录 - ->where('tu.access_token', $refreshToken) // 筛选 third_type 为 google 的记录 - ->field('tua.advertiser_id as account_id, tu.access_token as refresh_token') // 获取 advertiser_id 字段 + $merchant_id = $options['merchant_id']; + $customers = BpsAdsMerchantRelation::alias('bamr') + ->where('bamr.platform', 3) + ->where('bamr.merchant_id', $merchant_id) + ->where('bamr.is_unbind', 'f') + ->where('bamr.is_del', 'f') + ->field('bamr.account_id, bamr.refresh_token') ->select(); // 执行查询 } else { // 获取符合条件的客户ID数组 - $customers = ThirdUserAdvertiser::alias('tua') - ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 - ->where('tu.third_type', 'tiktok') // 筛选 third_type 为 google 的记录 - ->field('tua.advertiser_id as account_id, tu.access_token as refresh_token') // 获取 advertiser_id 字段 + $customers = BpsAdsMerchantRelation::alias('bamr') + ->where('bamr.platform', 3) + ->where('bamr.is_unbind', 'f') + ->where('bamr.is_del', 'f') + ->field('bamr.account_id, bamr.access_token as refresh_token') ->select(); // 执行查询 } - // 如果没有找到符合条件的广告主,抛出异常 if ($customers->isEmpty()) { return []; @@ -135,20 +225,57 @@ class BpsAdAccountService /** * 批量获取全部广告账号数据 - * + * 作废2025-2-13 + */ +// public function getAllAdAccounts($options = []) +// { +// // 获取符合条件的客户ID数组 +// $customers = ThirdUserAdvertiser::alias('tua') +// ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 +// ->where('tu.merchant_id', $options['merchant_id']) // 筛选 third_type 为 google 的记录 +// ->where('tu.access_token', '<>', '') // 筛选 access_token 不为空的记录 +// ->field('tua.advertiser_id as account_id, tu.access_token as refresh_token') // 获取 advertiser_id 字段 +// ->order('tu.third_type', 'asc') // 获取 advertiser_id 字段 +// ->select(); // 执行查询 +// +// +// // 如果没有找到符合条件的广告主,抛出异常 +// if ($customers->isEmpty()) { +// return []; +//// throw new ApiException('No customers found for google third type'); +// } +// +// // 转换为简单的数组(提取 advertiser_id) +// return $customers->toArray(); +// +// } + + /** + * 批量获取全部广告账号数据 + * TODO 增加fields入参 */ public function getAllAdAccounts($options = []) { - // 获取符合条件的客户ID数组 - $customers = ThirdUserAdvertiser::alias('tua') - ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 - ->where('tu.merchant_id', $options['merchant_id']) // 筛选 third_type 为 google 的记录 - ->where('tu.access_token', '<>', '') // 筛选 access_token 不为空的记录 - ->field('tua.advertiser_id as account_id, tu.access_token as refresh_token') // 获取 advertiser_id 字段 - ->order('tu.third_type', 'asc') // 获取 advertiser_id 字段 - ->select(); // 执行查询 - - + $merchant_id = $options['merchant_id']; + $platform = $options['platform'] ?? 0; + if ($platform > 0) { + // 获取某广告平台符合条件的客户ID数组 + $customers = BpsAdsMerchantRelation::alias('bamr') + ->where('bamr.platform', $platform) + ->where('bamr.merchant_id', $merchant_id) + ->where('bamr.is_unbind', 'f') + ->where('bamr.is_del', 'f') + ->field('bamr.account_id, bamr.access_token as refresh_token') + ->select(); // 执行查询 + } else { + // 获取全部广告平台符合条件的客户ID数组 + $customers = BpsAdsMerchantRelation::alias('bamr') + ->where('bamr.merchant_id', $merchant_id) + ->where('bamr.is_unbind', 'f') + ->where('bamr.is_del', 'f') + ->field('bamr.account_id, bamr.access_token as refresh_token') + ->select(); // 执行查询 + } // 如果没有找到符合条件的广告主,抛出异常 if ($customers->isEmpty()) { return []; @@ -160,120 +287,25 @@ class BpsAdAccountService } - // 获取 Facebook 第三方用户数据 - public function getMetaThirdUsers($options = []) - { - $merchant_id = $options['merchant_id'] ?? null; - if ($merchant_id) { - // 根据 UID 获取符合条件的用户数据 - $users = ThirdUserAdvertiser::alias('tua') - ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 - ->where('tu.third_type', 'facebook') // 筛选 third_type 为 facebook 的记录 - ->where('tu.merchant_id', $merchant_id) // 筛选 merchant_id 的记录 - ->where('tu.access_token', '<>', '') // 筛选 access_token 不为空的记录 - ->field('tu.id, tu.access_token as refresh_token') // 获取相关字段 - ->select(); - } else { - // 获取符合条件的用户数据(如果没有 UID) - $users = ThirdUserAdvertiser::alias('tua') - ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps.bps_third_user 表 - ->where('tu.third_type', 'facebook') // 筛选 third_type 为 facebook 的记录 - ->field('tu.id, tu.access_token as refresh_token') // 获取相关字段 - ->select(); - } - // 如果没有找到符合条件的用户,返回空数组 - if ($users->isEmpty()) { - return []; - } - - return $users->toArray(); - } - - -// 获取 Google 第三方用户数据 - public function getGoogleThirdUsers($options = []) - { - $merchant_id = $options['merchant_id'] ?? null; - - if ($merchant_id) { - // 获取符合条件的用户数据 - $users = ThirdUserAdvertiser::alias('tua') - ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 - ->where('tu.third_type', 'google') // 筛选 third_type 为 google 的记录 - ->where('tu.merchant_id', $merchant_id) // 筛选 merchant_id 的记录 - ->where('tu.access_token', '<>', '') // 筛选 access_token 不为空的记录 - ->field('tu.id, tu.access_token as refresh_token') // 获取相关字段 - ->select(); - } else { - // 获取符合条件的用户数据 - $users = ThirdUserAdvertiser::alias('tua') - ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 - ->where('tu.third_type', 'google') // 筛选 third_type 为 google 的记录 - ->field('tu.id, tu.access_token as refresh_token') // 获取相关字段 - ->select(); - } - - // 如果没有找到符合条件的用户,返回空数组 - if ($users->isEmpty()) { - return []; - } - - return $users->toArray(); - } - -// 获取 TikTok 第三方用户数据 - public function getTiktokThirdUsers($options = []) - { - $merchant_id = $options['merchant_id'] ?? null; - - if ($merchant_id) { -// $refreshToken = $options['refresh_token']; - // 获取符合条件的用户数据 - $users = ThirdUserAdvertiser::alias('tua') - ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 - ->where('tu.third_type', 'tiktok') // 筛选 third_type 为 tiktok 的记录 - ->where('tu.merchant_id', $merchant_id) // 筛选 merchant_id 的记录 - ->where('tu.access_token', '<>', '') // 筛选 access_token 不为空的记录 - ->field('tu.id, tu.access_token as refresh_token') // 获取相关字段 - ->select(); - } else { - // 获取符合条件的用户数据 - $users = ThirdUserAdvertiser::alias('tua') - ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 - ->where('tu.third_type', 'tiktok') // 筛选 third_type 为 tiktok 的记录 - ->field('tu.id, tu.access_token as refresh_token') // 获取相关字段 - ->select(); - } - - // 如果没有找到符合条件的用户,返回空数组 - if ($users->isEmpty()) { - return []; - } - - return $users->toArray(); - } - -// 获取所有平台的第三方用户数据 + // 获取所有平台的第三方用户数据 public function getAllThirdUsers($options = []) { // $userId = $options['uid']; // 获取用户ID - $merchantId = $options['merchant_id']; // 获取用户ID - - // 获取符合条件的用户数据 - $users = ThirdUserAdvertiser::alias('tua') - ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 - ->where('tu.merchant_id', $merchantId) // 筛选 merchant_id 的记录 - ->where('tu.access_token', '<>', '') // 筛选 access_token 不为空的记录 - ->field('tu.id, tu.third_type, tu.access_token as refresh_token') // 获取相关字段 - ->select(); + $merchant_id = $options['merchant_id']; // 获取用户ID + $customers = BpsAdsMerchantRelation::alias('bamr') + ->where('bamr.merchant_id', $merchant_id) + ->where('bamr.is_unbind', 'f') + ->where('bamr.is_del', 'f') + ->field('bamr.account_id, bamr.access_token as refresh_token') + ->select(); // 执行查询 // 如果没有找到符合条件的用户,返回空数组 - if ($users->isEmpty()) { + if ($customers->isEmpty()) { return []; } -//dump($users->toArray()); - return $users->toArray(); + //dump($customers->toArray()); + return $customers->toArray(); } diff --git a/app/service/GoogleAdsAccountService.php b/app/service/GoogleAdsAccountService.php index 382bbcd..b246ed6 100644 --- a/app/service/GoogleAdsAccountService.php +++ b/app/service/GoogleAdsAccountService.php @@ -362,7 +362,7 @@ class GoogleAdsAccountService extends BaseService /** - * Runs the example. + * Runs the example. 没调用 * * @param GoogleAdsClient $googleAdsClient the Google Ads API client * @param int $customerId the customer ID @@ -378,10 +378,10 @@ class GoogleAdsAccountService extends BaseService // $thirdUserId = (int)$option['third_user_id']; // Creates a client with the manager customer ID as login customer ID. - $googleAdsClient = $this->createGoogleAdsClientWithloginCustomerId($refreshToken,$loginCustomerId); + $googleAdsClient = $this->createGoogleAdsClientWithloginCustomerId($refreshToken, $loginCustomerId); $customerId = 8452924576; - $userId = $this->getUserAccess($googleAdsClient, $customerId,'s5O0z@example.com'); + $userId = $this->getUserAccess($googleAdsClient, $customerId, 's5O0z@example.com'); // if (!is_null($userId)) { // $this->modifyUserAccess($googleAdsClient, $customerId, $userId, $accessRole); // } @@ -735,16 +735,19 @@ class GoogleAdsAccountService extends BaseService { // Store the current customer ID and descriptive name in the result array $customerId = $customerClient->getId(); - $result[] = [ - 'customer_id' => $customerId, - 'descriptive_name' => $customerClient->getDescriptiveName(), - 'manager' => $customerClient->getManager(), - 'test_account' => $customerClient->getTestAccount(), - 'currency' => $customerClient->getCurrencyCode(), - 'status' => $customerClient->getStatus(), - 'level' => $customerClient->getLevel(), - 'time_zone' => $customerClient->getTimeZone(), - ]; + //如果$customerClient->getManager()是true则不记录到$result数组中 + if (!$customerClient->getManager()) { + $result[] = [ + 'customer_id' => $customerId, + 'descriptive_name' => $customerClient->getDescriptiveName(), + 'manager' => $customerClient->getManager(), + 'test_account' => $customerClient->getTestAccount(), + 'currency' => $customerClient->getCurrencyCode(), + 'status' => $customerClient->getStatus(), + 'level' => $customerClient->getLevel(), + 'time_zone' => $customerClient->getTimeZone(), + ]; + } // Recursively call this function for all child accounts of $customerClient. if (array_key_exists($customerId, $customerIdsToChildAccounts)) { diff --git a/app/service/GoogleOAuthService.php b/app/service/GoogleOAuthService.php index 9408654..f9506ea 100644 --- a/app/service/GoogleOAuthService.php +++ b/app/service/GoogleOAuthService.php @@ -4,6 +4,7 @@ namespace app\service; use GuzzleHttp\Client; use think\facade\Db as ThinkDb; +use app\model\BpsAdsMerchantRelation; use app\model\ThirdUserAdvertiser; use app\model\ThirdUser; use Webman\Event\Event; @@ -13,6 +14,45 @@ use app\event\GoogleAdsCustomers; class GoogleOAuthService { + /* + * 获取google主体账号信息 + * + */ + + public function getGoogleAccountInfo($accessToken) + { +// 'id' => '用户的Google ID', +// 'email' => '用户的电子邮件地址', +// 'verified_email' => true, // 邮箱是否已验证 +// 'name' => '用户的全名', +// 'given_name' => '用户的名字', +// 'family_name' => '用户的姓氏', +// 'picture' => '用户头像的URL', +// 'locale' => '用户的语言偏好', + + + $client = new Client(); + + try { + // 调用Google的userinfo API + $response = $client->get('https://www.googleapis.com/oauth2/v2/userinfo', [ + 'headers' => [ + 'Authorization' => 'Bearer ' . $accessToken, + ], + ]); + + // 解析API返回的JSON数据 + $userInfo = json_decode($response->getBody(), true); + + // 返回用户信息 + return $userInfo; + } catch (\Exception $e) { + // 处理异常情况 + throw new \Exception("Failed to fetch Google account info: " . $e->getMessage()); + } + } + + public function getAuthUrl($state = '') { $clientId = getenv('GOOGLE_CLIENT_ID'); @@ -80,15 +120,27 @@ class GoogleOAuthService ThinkDb::execute($sql, $data); } - public function getCustomerList($third_user_id = 0) + public function getCustomerListNew(string $merchant_id = '') { - $tableName = 'bps_third_user_advertiser'; - $tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName; - - $sql = "SELECT * FROM {$tableName} WHERE doc_ = :third_user_id"; - $data = ['third_user_id' => $third_user_id]; - - return ThinkDb::query($sql, $data); +// dump($merchant_id,555); + //$userId = $options['uid']; // 获取用户ID + $customers = BpsAdsMerchantRelation::alias('bamr') + ->where('bamr.merchant_id', $merchant_id) + ->where('bamr.is_unbind', 'f') + ->where('bamr.is_del', 'f') + ->where('bamr.platform', 2) + ->field('bamr.account_id, bamr.access_token as refresh_token') + ->select(); // 执行查询 +// dump($customers,555); + // 打印调试 SQL 查询 +// $sql = $customers->getLastSql(); +// dump($sql); + // 如果没有找到符合条件的用户,返回空数组 + if ($customers->isEmpty()) { + return []; + } +// dump($customers->toArray()); + return $customers->toArray(); } //保存或更新某个主体部广告账号 @@ -183,7 +235,7 @@ class GoogleOAuthService "; } else { $data['merchant_id'] = $state; - $sql = " + $sql = " INSERT INTO {$tableName} (access_token, is_default, third_type, merchant_id) VALUES (:access_token, :is_default, :third_type, :merchant_id) @@ -198,12 +250,20 @@ class GoogleOAuthService } ThinkDb::execute($sql, $data); - $options = []; + $options = []; $options['refresh_token'] = $refreshToken; Event::emit(GoogleAdsCustomers::add_queue, $data); $this->queue($options); } + public function initNewGoogleAdsAccountData($refreshToken) + { + + $options = []; + $options['refresh_token'] = $refreshToken; +// Event::emit(GoogleAdsCustomers::add_queue, $data); + $this->queue($options); + } public function revokeToken($accessToken, $third_user_id) { @@ -249,7 +309,7 @@ class GoogleOAuthService /** * 批量获取全部Google广告账号数据 - * + * 作废2025-2-13 */ public function getGoogleAdCustomers($options = []) { @@ -296,7 +356,7 @@ class GoogleOAuthService // 投递延迟消息,消息会在60秒后处理 // Redis::send($queue, $options['data'], 60); - return $queue2.' redis queue ok'; + return $queue2 . ' redis queue ok'; } diff --git a/config/event.php b/config/event.php index 63fd9c0..3ce3809 100644 --- a/config/event.php +++ b/config/event.php @@ -3,6 +3,7 @@ use app\event\TiktokAds; use app\event\TiktokAdsDetails; +use app\event\ShopifyOrders; use app\event\GoogleAdsCampaigns; use app\event\GoogleAdsGroups; use app\event\GoogleAdsAds; @@ -81,5 +82,12 @@ return [ [GoogleAdsCustomers::class, 'addRootCustomers'], ], + ShopifyOrders::event => [ + [ShopifyOrders::class, 'fetchOrderIds'], + ], + ShopifyOrders::event_customer => [ + [ShopifyOrders::class, 'fetchCustomerIds'], + ], + ];