Skip to content

Commit

Permalink
feat: record daily account usage for each account (#855)
Browse files Browse the repository at this point in the history
  • Loading branch information
djaiss committed Jun 30, 2021
1 parent 01db44c commit 07901c2
Show file tree
Hide file tree
Showing 19 changed files with 642 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ CURRENCY_LAYER_API_KEY=
UPLOADCARE_PUBLIC_KEY=
UPLOADCARE_PRIVATE_KEY=

# Activate paid plan in the instance
ENABLE_PAID_PLAN=true

# API key for analytics
# We use Fathom (https://usefathom.com) to manage analytics.
# Fathom is not free but is completely privacy friendly and we trust them.
Expand Down
5 changes: 5 additions & 0 deletions app/Console/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
use App\Jobs\StopRateYourManagerProcess;
use App\Jobs\StartRateYourManagerProcess;
use Illuminate\Console\Scheduling\Schedule;
use App\Jobs\Invoicing\CreateMonthlyInvoiceForCompanies;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use App\Jobs\Invoicing\LogDailyMaxNumberOfActiveEmployeesInCompanies;

class Kernel extends ConsoleKernel
{
Expand Down Expand Up @@ -37,6 +39,9 @@ protected function schedule(Schedule $schedule)
$schedule->job(new StartRateYourManagerProcess())->lastDayOfMonth('01:00');
$schedule->job(new StopRateYourManagerProcess())->hourly();

$schedule->job(new LogDailyMaxNumberOfActiveEmployeesInCompanies())->dailyAt($midnight);
$schedule->job(new CreateMonthlyInvoiceForCompanies())->lastDayOfMonth('22:00');

// disabled until PTOs will be finally implemented
//$schedule->command('timeoff:calculate '.Carbon::today()->format('Y-m-d'))->daily();

Expand Down
47 changes: 47 additions & 0 deletions app/Jobs/Invoicing/CreateMonthlyInvoiceForCompanies.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace App\Jobs\Invoicing;

use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use App\Models\Company\Company;
use App\Models\Company\CompanyInvoice;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Models\Company\CompanyDailyUsageHistory;

class CreateMonthlyInvoiceForCompanies implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

/**
* Create the monthly invoice for the company, based on the usage in the
* account.
*/
public function handle(): void
{
if (! config('officelife.enable_paid_plan')) {
return;
}

Company::chunk(100, function ($companies) {
foreach ($companies as $company) {
$usage = CompanyDailyUsageHistory::where('company_id', $company->id)
->whereBetween('created_at', [Carbon::now()->startOfMonth(), Carbon::now()->endOfMonth()])
->orderBy('number_of_active_employees', 'desc')
->first();

if (! $usage) {
continue;
}

CompanyInvoice::create([
'company_id' => $company->id,
'usage_history_id' => $usage->id,
]);
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace App\Jobs\Invoicing;

use Illuminate\Bus\Queueable;
use App\Models\Company\Company;
use App\Models\Company\Employee;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Models\Company\CompanyDailyUsageHistory;
use App\Models\Company\CompanyUsageHistoryDetails;

class LogDailyMaxNumberOfActiveEmployeesInCompanies implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

/**
* Record the number of active employee for all the companies in the
* instance.
*/
public function handle(): void
{
if (! config('officelife.enable_paid_plan')) {
return;
}

Company::addSelect([
'max_employees' => Employee::selectRaw('count(*)')
->whereColumn('company_id', 'companies.id')
->where('locked', false),
])
->chunk(100, function ($companies) {
foreach ($companies as $company) {
$usage = CompanyDailyUsageHistory::create([
'company_id' => $company->id,
'number_of_active_employees' => $company->max_employees,
]);

Employee::where('company_id', $company->id)
->where('locked', false)
->chunk(100, function ($employees) use ($usage) {
foreach ($employees as $employee) {
CompanyUsageHistoryDetails::create([
'usage_history_id' => $usage->id,
'employee_name' => $employee->name,
'employee_email' => $employee->email,
]);
}
});
}
});
}
}
20 changes: 20 additions & 0 deletions app/Models/Company/Company.php
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,26 @@ public function groups()
return $this->hasMany(Group::class);
}

/**
* Get all company usage history records in the company.
*
* @return HasMany
*/
public function usageHistory()
{
return $this->hasMany(CompanyDailyUsageHistory::class);
}

/**
* Get all company invoice records in the company.
*
* @return HasMany
*/
public function invoices()
{
return $this->hasMany(CompanyInvoice::class);
}

/**
* Get all softwares in the company.
*
Expand Down
47 changes: 47 additions & 0 deletions app/Models/Company/CompanyDailyUsageHistory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace App\Models\Company;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class CompanyDailyUsageHistory extends Model
{
use HasFactory;

protected $table = 'company_daily_usage_history';

/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'company_id',
'number_of_active_employees',
'created_at',
];

/**
* Get the Company record associated with the company usage history object.
*
* @return BelongsTo
*/
public function company()
{
return $this->belongsTo(Company::class);
}

/**
* Get the company usage history details records associated with the company
* usage history.
*
* @return HasMany
*/
public function details()
{
return $this->hasMany(CompanyUsageHistoryDetails::class, 'usage_history_id', 'id');
}
}
58 changes: 58 additions & 0 deletions app/Models/Company/CompanyInvoice.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

namespace App\Models\Company;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class CompanyInvoice extends Model
{
use HasFactory;

protected $table = 'company_invoices';

/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'company_id',
'usage_history_id',
'sent_to_customer',
'customer_has_paid',
'email_address_invoice_sent_to',
];

/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'sent_to_customer' => 'boolean',
'customer_has_paid' => 'boolean',
];

/**
* Get the Company record associated with the company invoice object.
*
* @return BelongsTo
*/
public function company()
{
return $this->belongsTo(Company::class);
}

/**
* Get the Company usage history record associated with the company invoice
* object.
*
* @return BelongsTo
*/
public function companyUsageHistory()
{
return $this->belongsTo(CompanyDailyUsageHistory::class, 'usage_history_id');
}
}
36 changes: 36 additions & 0 deletions app/Models/Company/CompanyUsageHistoryDetails.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace App\Models\Company;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class CompanyUsageHistoryDetails extends Model
{
use HasFactory;

protected $table = 'company_usage_history_details';

/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'usage_history_id',
'employee_name',
'employee_email',
];

/**
* Get the Company usage history record associated with the company
* usage history detail.
*
* @return BelongsTo
*/
public function companyUsageHistory()
{
return $this->belongsTo(CompanyDailyUsageHistory::class, 'usage_history_id');
}
}
11 changes: 11 additions & 0 deletions config/officelife.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,17 @@
*/
'location_iq_url' => env('LOCATION_IQ_URL', 'https://us1.locationiq.com/v1/'),

/*
|--------------------------------------------------------------------------
| Enable payment in the instance
|--------------------------------------------------------------------------
|
| This is used to bill the customers of the OfficeLife instance.
| You most likely don't need to touch this variable if you self-host.
|
*/
'enable_paid_plan' => env('ENABLE_PAID_PLAN', false),

/*
|--------------------------------------------------------------------------
| Mapbox API key
Expand Down
30 changes: 30 additions & 0 deletions database/factories/Company/CompanyDailyUsageHistoryFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Database\Factories\Company;

use App\Models\Company\Company;
use App\Models\Company\CompanyDailyUsageHistory;
use Illuminate\Database\Eloquent\Factories\Factory;

class CompanyDailyUsageHistoryFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = CompanyDailyUsageHistory::class;

/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'company_id' => Company::factory(),
'number_of_active_employees' => 3,
];
}
}
38 changes: 38 additions & 0 deletions database/factories/Company/CompanyInvoiceFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace Database\Factories\Company;

use App\Models\Company\Company;
use App\Models\Company\CompanyInvoice;
use App\Models\Company\CompanyDailyUsageHistory;
use Illuminate\Database\Eloquent\Factories\Factory;

class CompanyInvoiceFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = CompanyInvoice::class;

/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'company_id' => Company::factory(),
'usage_history_id' => function (array $attributes) {
return CompanyDailyUsageHistory::factory()->create([
'company_id' => $attributes['company_id'],
]);
},
'sent_to_customer' => false,
'customer_has_paid' => false,
'email_address_invoice_sent_to' => $this->faker->email,
];
}
}

0 comments on commit 07901c2

Please sign in to comment.