Google Analytics (#3610)

* Working on google analytics

* google analytics implementation
This commit is contained in:
David Bomba 2020-04-09 22:04:26 +10:00 committed by GitHub
parent 05443d69ec
commit afee58f746
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 166 additions and 23 deletions

View File

@ -1,4 +1,5 @@
<?php <?php
/** /**
* Invoice Ninja (https://invoiceninja.com) * Invoice Ninja (https://invoiceninja.com)
* *
@ -49,9 +50,9 @@ class InvoiceController extends BaseController
{ {
use MakesHash; use MakesHash;
protected $entity_type = Invoice::class ; protected $entity_type = Invoice::class;
protected $entity_transformer = InvoiceTransformer::class ; protected $entity_transformer = InvoiceTransformer::class;
/** /**
* @var InvoiceRepository * @var InvoiceRepository
@ -211,7 +212,7 @@ class InvoiceController extends BaseController
$invoice = $this->invoice_repo->save($request->all(), InvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id)); $invoice = $this->invoice_repo->save($request->all(), InvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id));
$invoice = StoreInvoice::dispatchNow($invoice, $request->all(), $invoice->company);//todo potentially this may return mixed ie PDF/$invoice... need to revisit when we implement UI $invoice = StoreInvoice::dispatchNow($invoice, $request->all(), $invoice->company); //todo potentially this may return mixed ie PDF/$invoice... need to revisit when we implement UI
event(new InvoiceWasCreated($invoice, $invoice->company)); event(new InvoiceWasCreated($invoice, $invoice->company));
@ -527,7 +528,7 @@ class InvoiceController extends BaseController
if ($action == 'download' && $invoices->count() > 1) { if ($action == 'download' && $invoices->count() > 1) {
$invoices->each(function ($invoice) { $invoices->each(function ($invoice) {
if (auth()->user()->cannot('view', $invoice)) { if (auth()->user()->cannot('view', $invoice)) {
return response()->json(['message'=>'Insufficient privileges to access invoice '. $invoice->number]); return response()->json(['message' => 'Insufficient privileges to access invoice ' . $invoice->number]);
} }
}); });
@ -679,14 +680,14 @@ class InvoiceController extends BaseController
case 'cancel': case 'cancel':
$invoice = $invoice->service()->handleCancellation()->save(); $invoice = $invoice->service()->handleCancellation()->save();
if(!$bulk){ if (!$bulk) {
$this->itemResponse($invoice); $this->itemResponse($invoice);
} }
break; break;
case 'reverse': case 'reverse':
$invoice = $invoice->service()->handleReversal()->save(); $invoice = $invoice->service()->handleReversal()->save();
if(!$bulk){ if (!$bulk) {
$this->itemResponse($invoice); $this->itemResponse($invoice);
} }
break; break;

View File

@ -7,7 +7,7 @@
* @OA\Property(property="size_id", type="string", example="1", description="The company size ID"), * @OA\Property(property="size_id", type="string", example="1", description="The company size ID"),
* @OA\Property(property="industry_id", type="string", example="1", description="The company industry ID"), * @OA\Property(property="industry_id", type="string", example="1", description="The company industry ID"),
* @OA\Property(property="slack_webhook_url", type="string", example="https://slack.com/sh328sj", description="The slack webhook notification URL"), * @OA\Property(property="slack_webhook_url", type="string", example="https://slack.com/sh328sj", description="The slack webhook notification URL"),
* @OA\Property(property="google_analytics_url", type="string", example="1", description="The google analytics webhook notification URL"), * @OA\Property(property="google_analytics_key", type="string", example="1", description="The google analytics key"),
* @OA\Property(property="portal_mode", type="string", example="subdomain", description="Determines the client facing urls ie: subdomain,domain,iframe"), * @OA\Property(property="portal_mode", type="string", example="subdomain", description="Determines the client facing urls ie: subdomain,domain,iframe"),
* @OA\Property(property="subdomain", type="string", example="aceme", description="Specifies the first part of the company domain ie acme in acme.domain.com"), * @OA\Property(property="subdomain", type="string", example="aceme", description="Specifies the first part of the company domain ie acme in acme.domain.com"),
* @OA\Property(property="portal_domain", type="string", example="https://subdomain.invoicing.co", description="The fully qualified domain for client facing URLS"), * @OA\Property(property="portal_domain", type="string", example="https://subdomain.invoicing.co", description="The fully qualified domain for client facing URLS"),

View File

@ -1,4 +1,5 @@
<?php <?php
/** /**
* Invoice Ninja (https://invoiceninja.com) * Invoice Ninja (https://invoiceninja.com)
* *
@ -521,8 +522,8 @@ class SubscriptionController extends BaseController
$event_id = $request->input('event_id'); $event_id = $request->input('event_id');
$target_url = $request->input('target_url'); $target_url = $request->input('target_url');
if (! in_array($event_id, Subscription::$valid_events)) { if (!in_array($event_id, Subscription::$valid_events)) {
return response()->json("Invalid event",400); return response()->json("Invalid event", 400);
} }
$subscription = new Subscription; $subscription = new Subscription;
@ -537,7 +538,6 @@ class SubscriptionController extends BaseController
} }
return $this->itemResponse($subscription); return $this->itemResponse($subscription);
} }
/** /**

View File

@ -16,6 +16,7 @@ use App\Models\Invoice;
use App\Models\Payment; use App\Models\Payment;
use App\Notifications\Admin\NewPaymentNotification; use App\Notifications\Admin\NewPaymentNotification;
use App\Repositories\ActivityRepository; use App\Repositories\ActivityRepository;
use App\Utils\Ninja;
use App\Utils\Traits\Notifications\UserNotifies; use App\Utils\Traits\Notifications\UserNotifies;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
@ -43,7 +44,9 @@ class PaymentNotification implements ShouldQueue
{ {
$payment = $event->payment; $payment = $event->payment;
/*User notifications*/
foreach ($payment->company->company_users as $company_user) { foreach ($payment->company->company_users as $company_user) {
$user = $company_user->user; $user = $company_user->user;
$notification = new NewPaymentNotification($payment, $payment->company); $notification = new NewPaymentNotification($payment, $payment->company);
@ -52,11 +55,75 @@ class PaymentNotification implements ShouldQueue
if ($user) { if ($user) {
$user->notify($notification); $user->notify($notification);
} }
} }
/*Company Notifications*/
if (isset($payment->company->slack_webhook_url)) { if (isset($payment->company->slack_webhook_url)) {
Notification::route('slack', $payment->company->slack_webhook_url) Notification::route('slack', $payment->company->slack_webhook_url)
->notify(new NewPaymentNotification($payment, $payment->company, true)); ->notify(new NewPaymentNotification($payment, $payment->company, true));
} }
/*Google Analytics Track Revenue*/
if (isset($payment->company->google_analytics_key))
$this->trackRevenue($event);
}
private function trackRevenue($event)
{
$payment = $event->payment;
$invoice = $payment->invoice;
$company = $payment->company;
$analytics_id = $company->google_analytics_key;
$client = $payment->client;
$amount = $payment->amount;
if($invoice){
$items = $invoice->line_items;
$item = end($items)->product_key;
$entity_number = $invoice->number;
}
else{
$item = $payment->number;
$entity_number = $item;
}
$currency_code = $client->getCurrencyCode();
if (Ninja::isHosted()) {
$item .= ' [R]';
}
$base = "v=1&tid={$analytics_id}&cid={$client->id}&cu={$currency_code}&ti={$entity_number}";
$url = $base . "&t=transaction&ta=ninja&tr={$amount}";
$this->sendAnalytics($url);
$url = $base . "&t=item&in={$item}&ip={$amount}&iq=1";
$this->sendAnalytics($url);
}
/**
* @param $data
*/
private function sendAnalytics($data)
{
$data = utf8_encode($data);
$curl = curl_init();
$opts = [
CURLOPT_URL => config('ninja.google_analytics_url'),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => 'POST',
CURLOPT_POSTFIELDS => $data,
];
curl_setopt_array($curl, $opts);
curl_exec($curl);
curl_close($curl);
} }
} }

View File

@ -94,7 +94,7 @@ class Company extends BaseModel
'first_day_of_week', 'first_day_of_week',
'first_month_of_year', 'first_month_of_year',
'slack_webhook_url', 'slack_webhook_url',
'google_analytics_url', 'google_analytics_key',
]; ];

View File

@ -110,7 +110,7 @@ class CompanyTransformer extends EntityTransformer
'archived_at' => (int)$company->deleted_at, 'archived_at' => (int)$company->deleted_at,
'created_at' =>(int)$company->created_at, 'created_at' =>(int)$company->created_at,
'slack_webhook_url' => (string)$company->slack_webhook_url, 'slack_webhook_url' => (string)$company->slack_webhook_url,
'google_analytics_url' => (string)$company->google_analytics_url, 'google_analytics_key' => (string)$company->google_analytics_key,
]; ];
} }

View File

@ -16,6 +16,7 @@ return [
'terms_version' => '1.0.1', 'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''), 'api_secret' => env('API_SECRET', ''),
'google_maps_api_key' => env('GOOGLE_MAPS_API_KEY'), 'google_maps_api_key' => env('GOOGLE_MAPS_API_KEY'),
'google_analytics_url' => env('GOOGLE_ANALYTICS_URL', 'https://www.google-analytics.com/collect'),
'key_length' => 64, 'key_length' => 64,
'date_format' => 'Y-m-d', 'date_format' => 'Y-m-d',
'date_time_format' => 'Y-m-d H:i', 'date_time_format' => 'Y-m-d H:i',

View File

@ -32,6 +32,10 @@ class AddIsDeletedColumnToCompanyTokensTable extends Migration
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade'); $table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
}); });
Schema::table('companies', function (Blueprint $table) {
$table->renameColumn('google_analytics_url', 'google_analytics_key');
});
} }
/** /**

View File

@ -108,8 +108,6 @@ class SubscriptionAPITest extends TestCase
$arr = $response->json(); $arr = $response->json();
\Log::error(print_r($arr,1));
$this->assertEquals(0,$arr['data'][0]['archived_at']); $this->assertEquals(0,$arr['data'][0]['archived_at']);

View File

@ -0,0 +1,72 @@
<?php
namespace Tests\Unit;
use App\DataMapper\ClientSettings;
use App\DataMapper\CompanySettings;
use App\Models\GroupSetting;
use App\Utils\Ninja;
use App\Utils\Traits\ClientGroupSettingsSaver;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\MockAccountData;
use Tests\TestCase;
/**
* @test
* @covers App\Listeners\Payment\PaymentNotification
*/
class GoogleAnalyticsTest extends TestCase
{
use MockAccountData;
use DatabaseTransactions;
public function setUp() :void
{
parent::setUp();
$this->makeTestData();
}
public function testGoogleAnalyticsLogic()
{
$analytics_id = "analytics_id";
$invoice = $this->invoice;
$client = $this->client;
$invoice->service()->markPaid()->save();
$payment = $invoice->payments->first();
$amount = $payment->amount;
if($invoice){
$items = $invoice->line_items;
$item = end($items)->product_key;
$entity_number = $invoice->number;
}
else{
$item = $payment->number;
$entity_number = $item;
}
$currency_code = $client->getCurrencyCode();
if (Ninja::isHosted()) {
$item .= ' [R]';
}
$base = "v=1&tid={$analytics_id}&cid={$client->id}&cu={$currency_code}&ti={$entity_number}";
$url = $base . "&t=transaction&ta=ninja&tr={$amount}";
$url = $base . "&t=item&in={$item}&ip={$amount}&iq=1";
$this->assertNotNull($url);
}
}