adsService = $adsService; } // List all accounts under MCC public function accounts() { // $accounts = collect($this->adsService->listAccounts()) // ->map(function (array $account) { // $account['customer_id'] = (string) ($account['customer_id'] ?? $account['id']); // return $account; // }); // $customerMap = $accounts->keyBy('customer_id'); $localClients = $this->hierarchyService ->scopeClientsVisibleTo(Client::query(), Auth::user()) ->with('assignations.user', 'customers', 'invoices', 'invoiceAdjustments') ->get(); $customerMap = $localClients->map(function ($data) { $assignedPerson = $data->assignations->firstWhere('role', ClientUserAssignation::ROLE_ASSIGNED_PERSON); $salesPerson = $data->assignations->firstWhere('role', ClientUserAssignation::ROLE_SALES_PERSON); $data['industry'] = $data->industry; $data['sql_acc_code'] = implode(',', $data->customers->pluck('sql_acc_code')->toArray()); $data['assigned_person'] = $assignedPerson?->user?->name; $data['sales_person'] = $salesPerson?->user?->name; $data['latest_remaining_amount'] = $data->latestRemainingAmount(function (ClientInvoice $invoice) use ($data) { if (empty($invoice->start_date) || empty($invoice->end_date)) { return 0; } return GoogleCampaignMetric::query() ->join('google_campaigns', 'google_campaign_metrics.google_campaign_id', '=', 'google_campaigns.id') ->where('google_campaigns.client_id', $data->id) ->whereNull('google_campaigns.deleted_at') ->whereNull('google_campaign_metrics.deleted_at') ->whereBetween('google_campaign_metrics.date', [ $invoice->start_date?->toDateString(), $invoice->end_date?->toDateString(), ]) ->sum('google_campaign_metrics.actual_spend'); }); return $data; }); return Inertia::render('campaigns/index', [ 'clients' => $customerMap->values()->all(), 'googleCompanySyncRunning' => Cache::has(self::GOOGLE_COMPANY_SYNC_LOCK), ]); } public function syncGoogleCompanyDetails(): RedirectResponse { $started = Cache::add(self::GOOGLE_COMPANY_SYNC_LOCK, [ 'user_id' => Auth::id(), 'started_at' => now()->toDateTimeString(), ], now()->addHour()); if (! $started) { return redirect() ->back() ->with('message-warning', 'Google account sync is already running. Please wait for it to finish.'); } try { $exitCode = Artisan::call('google-ads:get-company-details'); if ($exitCode !== 0) { return redirect() ->back() ->with('message-error', 'Google account sync failed. Please check the logs.'); } return redirect() ->back() ->with('message-info', 'Google account records have been synced.'); } finally { Cache::forget(self::GOOGLE_COMPANY_SYNC_LOCK); } } public function show($id) { // $account = $this->adsService->getAccountDetails($id); $client = Client::where('customer_id', $id)->firstOrFail(); abort_unless($this->hierarchyService->canViewClient(Auth::user(), $client), 403); $account = [ 'id' => $client->customer_id, 'name' => $client->name, 'status' => $client->status, 'time_zone' => $client->time_zone, ]; [$localClient, $assignments, $users, $invoices, $activityList, $pendingActivities, $completedActivities, $lifeTimeSpending, $clientAdjustments] = $this->hydrateClient($account); $account = array_merge($account, [ 'industry' => $localClient->industry, 'sql_acc_code' => $localClient->sql_acc_code, 'activities_list' => $activityList, ]); return Inertia::render('campaigns/show', [ 'id' => $id, 'client' => $account, 'invoices' => $invoices, 'localClientId' => $localClient->id, 'clientAssignmentRoles' => ClientUserAssignation::roles(), 'clientAssignments' => $assignments, 'assignmentUsers' => $users, 'clientInvoices' => $invoices, 'clientAdjustments' => $clientAdjustments, 'pendingActivities' => $pendingActivities, 'completedActivities' => $completedActivities, 'lifeTimeSpending' => number_format($lifeTimeSpending, 2, '.', ','), ]); } public function edit($id) { $account = $this->adsService->getAccountDetails($id); [$localClient, $assignments, $users, $invoices] = $this->hydrateClient($account); abort_unless($this->hierarchyService->canViewClient(Auth::user(), $localClient), 403); $account = array_merge($account, [ 'name' => $localClient->name, 'customer_id' => $localClient->customer_id, 'status' => $localClient->status, 'time_zone' => $localClient->time_zone, 'industry' => $localClient->industry, 'sql_acc_code' => $localClient->sql_acc_code, ]); return Inertia::render('campaigns/account/edit', [ 'id' => $id, 'client' => $account, 'clientAssignmentRoles' => ClientUserAssignation::roles(), 'clientAssignments' => $assignments, 'assignmentUsers' => $users, 'clientInvoices' => $invoices, ]); } public function updateAccount(Request $request, $id) { [$localClient] = $this->hydrateClient($this->adsService->getAccountDetails($id)); abort_unless($this->hierarchyService->canViewClient(Auth::user(), $localClient), 403); $validated = $request->validate([ 'name' => ['required', 'string'], 'customer_id' => ['required', 'string', 'unique:clients,customer_id,'.$localClient->id], 'industry' => ['nullable', 'string'], 'sql_acc_code' => ['nullable', 'string'], 'assigned_person' => ['nullable', 'integer', 'exists:users,id'], 'sales_person' => ['nullable', 'integer', 'exists:users,id'], ]); $localClient->update([ 'name' => $validated['name'], 'customer_id' => $validated['customer_id'], 'industry' => $validated['industry'] ?? null, 'sql_acc_code' => $validated['sql_acc_code'] ?? null, ]); $localClient->customers()->delete(); if (! empty($validated['sql_acc_code'])) { collect(explode(',', $validated['sql_acc_code'])) ->map(fn (string $sqlAccCode) => trim($sqlAccCode)) ->filter() ->unique() ->each(function (string $sqlAccCode) use ($localClient) { ClientCustomer::create([ 'client_id' => $localClient->id, 'sql_acc_code' => $sqlAccCode, ]); }); } $assignmentValues = [ ClientUserAssignation::ROLE_ASSIGNED_PERSON => $validated['assigned_person'] ?? null, ClientUserAssignation::ROLE_SALES_PERSON => $validated['sales_person'] ?? null, ]; foreach ($assignmentValues as $role => $userId) { if ($userId === null) { $localClient->assignations()->where('role', $role)->delete(); continue; } $localClient->assignations()->updateOrCreate( ['role' => $role], ['user_id' => $userId] ); } return redirect() ->route('google-ads.accounts.edit', ['id' => $localClient->customer_id]) ->with('message-info', 'Account details updated.'); } public function campaigns($id) { $campaigns = $this->adsService->listCampaigns($id); return response()->json($campaigns); } public function listCampaignsMetrics($id, $startDate, $endDate) { $campaigns = $this->adsService->listCampaignsMetrics($id, $startDate, $endDate); return response()->json($campaigns); } private function hydrateClient(array $account): array { $localClient = Client::updateOrCreate( ['customer_id' => $account['id']], [ 'name' => $account['name'], 'status' => $account['status'], 'time_zone' => $account['time_zone'], ] ); $localClient->load(['assignations.user', 'invoices']); $assignments = $localClient->assignations ->mapWithKeys(function (ClientUserAssignation $assignation) { return [$assignation->role => $assignation->user_id]; }) ->toArray(); $users = User::orderBy('name') ->get(['id', 'name', 'email']) ->map(function (User $user) { return [ 'value' => (string) $user->id, 'label' => trim($user->name.' ('.$user->email.')'), ]; }) ->toArray(); $clientAdjustments = ClientInvoiceAdjustment::query() ->where('client_id', $localClient->id) ->orderByDesc('created_at') ->get() ->map(function (ClientInvoiceAdjustment $adjustment) { return [ 'id' => $adjustment->id, 'client_id' => $adjustment->client_id, 'entry_type' => $adjustment->entry_type, 'amount' => $adjustment->amount, 'remark' => $adjustment->remark, 'created_at' => $adjustment->created_at?->toDateTimeString(), ]; }) ->values() ->all(); $invoices = $localClient->invoices ->map(function ($invoice) use ($account) { $campaigns = $this->adsService->listCampaigns($account['id']); $totalInvoiceSpend = 0; FacadesLog::info('Hydrated client data', [ 'campaigns' => $campaigns, ]); foreach ($campaigns as $campaign) { FacadesLog::info('Hydrated client data', [ 'campaigns' => $campaign['id'], ]); if (empty($invoice->start_date) || empty($invoice->end_date)) { continue; } else { $metrics = $this->adsService->listCampaignsMetricsById( $account['id'], $campaign['id'], $invoice->start_date?->toDateString() ?? null, $invoice->end_date?->toDateString() ?? null ); FacadesLog::info('Hydrated client data', [ 'metrics' => $metrics, ]); $totalSpend = array_sum(array_column($metrics, 'actual_spend')); $totalInvoiceSpend += $totalSpend; } } return [ 'id' => $invoice->id, 'client_id' => $invoice->client_id, 'invoice_no' => $invoice->invoice_no, 'linked_invoice_id' => $invoice->linked_invoice_id, 'is_credit_card' => $invoice->is_credit_card, 'is_paid' => $invoice->is_paid, 'start_date' => $invoice->start_date?->toDateString(), 'end_date' => $invoice->end_date?->toDateString(), 'payment_no' => $invoice->payment_no, 'amount' => $invoice->amount, 'total_spend' => number_format($totalInvoiceSpend, 2, '.', ''), 'management_fee' => $invoice->management_fee, 'media_fee' => $invoice->media_fee, 'tax_percent' => $invoice->tax_percent, 'nett_amount' => $invoice->nett_amount, 'total_spending' => $invoice->total_spending, ]; }) ->toArray(); // dd($invoices); $campaigns = $this->adsService->listCampaigns($localClient->customer_id); $lifeTimeSpend = 0; if (! empty($campaigns)) { foreach ($campaigns as $campaign) { $metrics = $this->adsService->listCampaignsMetricsById( $localClient->customer_id, $campaign['id'], '1970-01-01', // Start date far in the past to capture all historical data now()->toDateString() // End date as today` ); $totalSpend = array_sum(array_column($metrics, 'actual_spend')); $lifeTimeSpend += number_format($totalSpend, 2, '.', ''); } } $activities = $localClient->activitiesList() ->orderByDesc('created_at') ->get() ->map(function (ClientProjectActivities $activity) { return [ 'id' => $activity->id, 'activity_no' => $activity->activity_no, 'activity_type' => $activity->activity_type, 'task_description' => $activity->task_description, 'estimated_completed_at' => data_get($activity, 'estimated_completed_at'), 'completed_at' => data_get($activity, 'completed_at'), 'notification_sent_at' => data_get($activity, 'notification_sent_at'), 'notification_status' => data_get($activity, 'notification_status'), 'note_to_customer' => data_get($activity, 'note_to_customer'), 'assignation' => null, ]; }); $activitiesList = $activities->values()->all(); $pendingActivities = $activities ->filter(function (array $activity) { return empty($activity['completed_at']) && ! empty($activity['estimated_completed_at']); }) ->values() ->all(); $completedActivities = $activities ->filter(function (array $activity) { return ! empty($activity['completed_at']); }) ->values() ->all(); FacadesLog::info('Hydrated client data', [ 'localClient' => $localClient->toArray(), 'assignments' => $assignments, 'users' => $users, 'invoices' => $invoices, ]); return [ $localClient, $assignments, $users, $invoices, $activitiesList, $pendingActivities, $completedActivities, $lifeTimeSpend, $clientAdjustments, ]; } public function insertCSVDataToDB() { $collection = (new FastExcel)->import(storage_path('app/public/csv/Fixed_HJ.csv')); $array = $collection->toArray(); foreach ($array as $row) { $startDate = Carbon::parse($row['start_date'])->format('Y-m-d'); $endDate = Carbon::parse($row['end_date'])->format('Y-m-d'); $client = Client::where('customer_id', str_replace('-', '', $row['customer_id']))->first(); // dd($row); if ($client) { $salesUser = User::where('name', $row['sales'])->first(); $pic = User::where('name', $row['pic'])->first(); if ($pic) { ClientUserAssignation::updateOrCreate( [ 'client_id' => $client->id, 'role' => ClientUserAssignation::ROLE_ASSIGNED_PERSON, ], [ 'user_id' => $pic->id, ] ); } if ($salesUser) { ClientUserAssignation::updateOrCreate( [ 'client_id' => $client->id, 'role' => ClientUserAssignation::ROLE_SALES_PERSON, ], [ 'user_id' => $salesUser->id, ] ); } $row['client_id'] = $client->id; $spend = 0; if ($client->status != 'CANCELED') { $campaigns = $this->adsService->listCampaigns($row['customer_id']); FacadesLog::info('Hydrated client data', [ 'campaigns' => $campaigns, ]); foreach ($campaigns as $campaign) { FacadesLog::info('Hydrated client data', [ 'campaigns' => $campaign['id'], ]); if (empty($startDate) || empty($endDate)) { continue; } else { $metrics = $this->adsService->listCampaignsMetricsById( $row['customer_id'], $campaign['id'], $startDate, $endDate ); FacadesLog::info('Hydrated client data', [ 'metrics' => $metrics, ]); $totalSpend = array_sum(array_column($metrics, 'actual_spend')); $spend += $totalSpend; } } } ClientInvoice::updateOrCreate( ['invoice_no' => $row['invoice_no']], [ 'client_id' => $row['client_id'], 'is_credit_card' => intval($row['media_fee']) == 0 ? 1 : 0, 'start_date' => $startDate, 'end_date' => $endDate, 'management_fee' => intval($row['management_fee']), 'media_fee' => intval($row['media_fee']), 'tax_percent' => 8, 'nett_amount' => intval($row['media_fee']) > 0 ? intval($row['media_fee']) / 1.08 : 0, 'total_spending' => $spend, ] ); } else { FacadesLog::warning('Client not found for customer_id: '.str_replace('-', '', $row['customer_id'])); continue; // Skip this row if client not found } } } }