Fixes for tests (#3082)

* Update client paid to date job:

* Backup Invoice HTML when invoice is marked as sent and paid

* Store HTML of invoice when invoice was paid

* Fix foreign keys in db schema

* V2 Endpoints for Company Migrations

* Fixes for tests
This commit is contained in:
David Bomba 2019-11-20 16:41:49 +11:00 committed by GitHub
parent 6d225b7fe7
commit f59585dd62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 641 additions and 230 deletions

1
.gitignore vendored
View File

@ -21,3 +21,4 @@ yarn-error.log
.env.dusk.local
/public/vendors/*
public/mix-manifest.json
*.log

View File

@ -119,8 +119,10 @@ class CreateTestData extends Command
private function createClient($company, $user)
{
$client = ClientFactory::create($company->id, $user->id);
$client->save();
$client = factory(\App\Models\Client::class)->create([
'user_id' => $user->id,
'company_id' => $company->id
]);
factory(\App\Models\ClientContact::class,1)->create([

View File

@ -0,0 +1,38 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2019. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Events\Invoice;
use App\Models\Invoice;
use Illuminate\Queue\SerializesModels;
/**
* Class InvoiceWasPaid.
*/
class InvoiceWasPaid
{
use SerializesModels;
/**
* @var Invoice
*/
public $invoice;
/**
* Create a new event instance.
*
* @param Invoice $invoice
*/
public function __construct(Invoice $invoice)
{
$this->invoice = $invoice;
}
}

View File

@ -0,0 +1,144 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2019. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Controllers;
use App\Http\Requests\Account\CreateAccountRequest;
use App\Jobs\Account\CreateAccount;
use App\Models\Account;
use App\Models\Company;
use App\Models\CompanyUser;
use App\Transformers\AccountTransformer;
use App\Transformers\CompanyUserTransformer;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class MigrationController extends BaseController
{
use DispatchesJobs;
public function __construct()
{
parent::__construct();
}
/**
*
* Purge Company
*
* @OA\Post(
* path="/api/v1/migration/purge/{company}",
* operationId="postPurgeCompany",
* tags={"migration"},
* summary="Attempts to purge a company record and all its child records",
* description="Attempts to purge a company record and all its child records",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(
* name="company",
* in="path",
* description="The Company Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Success",
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function purgeCompany(Company $company)
{
$company->delete();
return response()->json(['message'=>'Company purged'], 200);
}
/**
*
* Purge Company but save settings
*
* @OA\Post(
* path="/api/v1/migration/purge_save_settings/{company}",
* operationId="postPurgeCompanySaveSettings",
* tags={"migration"},
* summary="Attempts to purge a companies child records but save the company record and its settings",
* description="Attempts to purge a companies child records but save the company record and its settings",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(
* name="company",
* in="path",
* description="The Company Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Success",
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function purgeCompanySaveSettings(Company $company)
{
$company->client->delete()
$company->save()
return response()->json(['message'=>'Setting preserved'], 200);
}
}

View File

@ -0,0 +1,50 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2019. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Client;
use App\Models\Client;
use Illuminate\Foundation\Bus\Dispatchable;
class UpdateClientPaidToDate
{
use Dispatchable;
protected $amount;
protected $client;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Client $client, $amount)
{
$this->amount = $amount;
$this->client = $client;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$this->client->paid_to_date += $this->amount;
$this->client->save();
}
}

View File

@ -11,6 +11,7 @@
namespace App\Jobs\Invoice;
use App\Events\Invoice\InvoiceWasPaid;
use App\Jobs\Invoice\ApplyInvoiceNumber;
use App\Models\Invoice;
use App\Models\Payment;
@ -95,8 +96,11 @@ class ApplyPaymentToInvoice implements ShouldQueue
$this->invoice->balance = $this->invoice->balance + $adjustment;
/* Update Invoice Status */
if($this->invoice->balance == 0)
if($this->invoice->balance == 0){
$this->invoice->status_id = Invoice::STATUS_PAID;
$this->invoice->save();
event(new InvoiceWasPaid($this->invoice));
}
elseif($this->payment->amount > 0 && $this->invoice->balance > 0)
$this->invoice->status_id = Invoice::STATUS_PARTIAL;

View File

@ -16,13 +16,13 @@ use App\Models\Payment;
use App\Models\PaymentTerm;
use App\Repositories\InvoiceRepository;
use App\Utils\Traits\NumberFormatter;
use App\Utils\Traits\MakesInvoiceHtml;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Spatie\Browsershot\Browsershot;
@ -30,7 +30,7 @@ use Symfony\Component\Debug\Exception\FatalThrowableError;
class CreateInvoicePdf implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, NumberFormatter;
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, NumberFormatter, MakesInvoiceHtml;
public $invoice;
@ -89,67 +89,5 @@ class CreateInvoicePdf implements ShouldQueue
//->savePdf('test.pdf');
}
/**
* Generate the HTML invoice parsing variables
* and generating the final invoice HTML
*
* @param string $design either the path to the design template, OR the full design template string
* @param Collection $invoice The invoice object
*
* @return string The invoice string in HTML format
*/
private function generateInvoiceHtml($design, $invoice) :string
{
$variables = array_merge($invoice->makeLabels(), $invoice->makeValues());
$design = str_replace(array_keys($variables), array_values($variables), $design);
$data['invoice'] = $invoice;
return $this->renderView($design, $data);
//return view($design, $data)->render();
}
/**
* Parses the blade file string and processes the template variables
*
* @param string $string The Blade file string
* @param array $data The array of template variables
* @return string The return HTML string
*
*/
private function renderView($string, $data) :string
{
if (!$data) {
$data = [];
}
$data['__env'] = app(\Illuminate\View\Factory::class);
$php = Blade::compileString($string);
$obLevel = ob_get_level();
ob_start();
extract($data, EXTR_SKIP);
try {
eval('?' . '>' . $php);
} catch (\Exception $e) {
while (ob_get_level() > $obLevel) {
ob_end_clean();
}
throw $e;
} catch (\Throwable $e) {
while (ob_get_level() > $obLevel) {
ob_end_clean();
}
throw new FatalThrowableError($e);
}
return ob_get_clean();
}
}

View File

@ -72,8 +72,8 @@ class MarkInvoicePaid implements ShouldQueue
event(new PaymentWasCreated($payment));
UpdateCompanyLedgerWithPayment::dispatchNow($payment, ($payment->amount*-1));
UpdateClientBalance::dispatchNow($payment->client, $this->payment->amount*-1);
UpdateClientPaidToDate::dispatchNow($payment->client, $this->payment->amount);
UpdateClientBalance::dispatchNow($payment->client, $payment->amount*-1);
UpdateClientPaidToDate::dispatchNow($payment->client, $payment->amount);
return $this->invoice;
}

View File

@ -0,0 +1,50 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2019. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Invoice;
use App\Models\Activity;
use App\Repositories\ActivityRepository;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class CreateInvoiceHtmlBackup implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @return void
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
$fields = new \stdClass;
$fields->invoice_id = $event->invoice->id;
$fields->user_id = $event->invoice->user_id;
$fields->company_id = $event->invoice->company_id;
$fields->activity_type_id = Activity::MARK_SENT_INVOICE;
$this->activity_repo->save($fields, $event->invoice);
}
}

View File

@ -45,8 +45,6 @@ class UpdateInvoiceInvitations implements ShouldQueue
*/
$invoices->each(function ($invoice) use($payment) {
$invoice->status_id = Invoice::STATUS_PAID;
$invoice->save();
$invoice->invitations()->update(['transaction_reference' => $payment->transaction_reference]);
});

View File

@ -67,7 +67,9 @@ class Activity extends StaticModel
const ARCHIVE_USER=50;
const DELETE_USER=51;
const RESTORE_USER=52;
const MARK_SENT_INVOICE=53;
const PAID_INVOICE=54;
protected $casts = [
'is_system' => 'boolean',
'updated_at' => 'timestamp',

View File

@ -23,7 +23,6 @@ class CompanyUser extends Pivot
* @var array
*/
protected $casts = [
'settings' => 'object',
'permissions' => 'object',
'updated_at' => 'timestamp',
'created_at' => 'timestamp',

View File

@ -11,6 +11,8 @@
namespace App\Models;
use App\Events\Invoice\InvoiceWasMarkedSent;
use App\Events\Invoice\InvoiceWasPaid;
use App\Events\Invoice\InvoiceWasUpdated;
use App\Helpers\Invoice\InvoiceSum;
use App\Helpers\Invoice\InvoiceSumInclusive;
@ -370,8 +372,13 @@ class Invoice extends BaseModel
$this->balance = $this->balance + $balance_adjustment;
if($this->balance == 0)
if($this->balance == 0) {
$this->status_id = self::STATUS_PAID;
$this->save();
event(new InvoiceWasPaid($this));
return;
}
$this->save();
}
@ -399,6 +406,8 @@ class Invoice extends BaseModel
$this->markInvitationsSent();
event(new InvoiceWasMarkedSent($this));
UpdateClientBalance::dispatchNow($this->client, $this->balance);
$this->save();

View File

@ -327,7 +327,11 @@ class User extends Authenticatable implements MustVerifyEmail
public function hasPermission($permission) : bool
{
return $this->permissionsFlat()->contains($permission);
return (stripos($this->user_company()->permissions, $permission) !== false);
// return $this->permissionsFlat()->contains($permission);
}

View File

@ -15,6 +15,7 @@ use App\Events\Client\ClientWasCreated;
use App\Events\Contact\ContactLoggedIn;
use App\Events\Invoice\InvoiceWasCreated;
use App\Events\Invoice\InvoiceWasMarkedSent;
use App\Events\Invoice\InvoiceWasPaid;
use App\Events\Invoice\InvoiceWasUpdated;
use App\Events\Payment\PaymentWasCreated;
use App\Events\Payment\PaymentWasDeleted;
@ -25,6 +26,7 @@ use App\Listeners\Activity\PaymentCreatedActivity;
use App\Listeners\Activity\PaymentDeletedActivity;
use App\Listeners\Contact\UpdateContactLastLogin;
use App\Listeners\Invoice\CreateInvoiceActivity;
use App\Listeners\Invoice\CreateInvoiceHtmlBackup;
use App\Listeners\Invoice\CreateInvoiceInvitation;
use App\Listeners\Invoice\CreateInvoicePdf;
use App\Listeners\Invoice\UpdateInvoiceActivity;
@ -59,10 +61,10 @@ class EventServiceProvider extends ServiceProvider
PaymentWasCreated::class => [
PaymentCreatedActivity::class,
//UpdateInvoicePayment::class,
UpdateInvoiceInvitations::class,
//UpdateInvoiceInvitations::class,
],
PaymentWasDeleted::class => [
PaymentDeletedActivity::class
PaymentDeletedActivity::class,
],
'App\Events\ClientWasArchived' => [
'App\Listeners\ActivityListener@archivedClient',
@ -82,7 +84,7 @@ class EventServiceProvider extends ServiceProvider
//Invoices
InvoiceWasMarkedSent::class => [
CreateInvoiceInvitation::class,
CreateInvoiceHtmlBackup::class,
],
InvoiceWasUpdated::class => [
UpdateInvoiceActivity::class,
@ -92,6 +94,9 @@ class EventServiceProvider extends ServiceProvider
CreateInvoiceActivity::class,
CreateInvoicePdf::class,
],
InvoiceWasPaid::class => [
CreateInvoiceHtmlBackup::class,
]
];
/**

View File

@ -14,6 +14,8 @@ namespace App\Repositories;
use App\Models\Activity;
use App\Models\Backup;
use App\Models\Client;
use App\Models\Invoice;
use App\Utils\Traits\MakesInvoiceHtml;
use Illuminate\Support\Facades\Log;
/**
@ -21,7 +23,7 @@ use Illuminate\Support\Facades\Log;
*/
class ActivityRepository extends BaseRepository
{
use MakesInvoiceHtml;
/**
* Save the Activity
*
@ -66,6 +68,11 @@ class ActivityRepository extends BaseRepository
else
$entity->load('company','client');
if(get_class($entity) == Invoice::class && ($activity->activity_type_id == Activity::MARK_SENT_INVOICE || $activity->activity_type_id == Activity::PAID_INVOICE))
$backup->html_backup = $this->generateInvoiceHtml($entity->design(), $entity);
$backup->activity_id = $activity->id;
$backup->json_backup = $entity->toJson();
$backup->save();

View File

@ -18,7 +18,6 @@ use App\Models\Quote;
use App\Models\RecurringInvoice;
use App\Models\Timezone;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log;
/**
* Class GeneratesCounter
@ -43,7 +42,6 @@ trait GeneratesCounter
//todo handle if we have specific client patterns in the future
$pattern = $client->getSetting('invoice_number_pattern');
//Determine if we are using client_counters
if(strpos($pattern, 'clientCounter'))
{
@ -65,10 +63,12 @@ trait GeneratesCounter
$pattern = $client->getSetting('invoice_number_pattern');
$prefix = $client->getSetting('invoice_number_prefix');
$padding = $client->getSetting('counter_padding');
$invoice_number = $this->checkEntityNumber(Invoice::class, $client, $counter, $padding, $prefix, $pattern);
$this->incrementCounter($counter_entity, 'invoice_number_counter');
return $invoice_number;
}
@ -173,7 +173,7 @@ trait GeneratesCounter
public function hasSharedCounter(Client $client) : bool
{
return $client->getSettingsByKey('shared_invoice_quote_counter') === TRUE;
return $client->getSetting('shared_invoice_quote_counter') === TRUE;
}
@ -213,6 +213,7 @@ trait GeneratesCounter
} while ($check);
return $number;
}
@ -235,6 +236,7 @@ trait GeneratesCounter
private function prefixCounter($counter, $prefix) : string
{
if(strlen($prefix) == 0)
return $counter;
@ -330,6 +332,7 @@ trait GeneratesCounter
*/
private function applyNumberPattern(Client $client, string $counter, $pattern) :string
{
if(!$pattern)
return $counter;

View File

@ -0,0 +1,88 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2019. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Utils\Traits;
use Illuminate\Support\Facades\Blade;
use Symfony\Component\Debug\Exception\FatalThrowableError;
/**
* Class MakesInvoiceHtml.
*/
trait MakesInvoiceHtml
{
/**
* Generate the HTML invoice parsing variables
* and generating the final invoice HTML
*
* @param string $design either the path to the design template, OR the full design template string
* @param Collection $invoice The invoice object
*
* @return string The invoice string in HTML format
*/
public function generateInvoiceHtml($design, $invoice) :string
{
$variables = array_merge($invoice->makeLabels(), $invoice->makeValues());
$design = str_replace(array_keys($variables), array_values($variables), $design);
$data['invoice'] = $invoice;
return $this->renderView($design, $data);
//return view($design, $data)->render();
}
/**
* Parses the blade file string and processes the template variables
*
* @param string $string The Blade file string
* @param array $data The array of template variables
* @return string The return HTML string
*
*/
public function renderView($string, $data) :string
{
if (!$data) {
$data = [];
}
$data['__env'] = app(\Illuminate\View\Factory::class);
$php = Blade::compileString($string);
$obLevel = ob_get_level();
ob_start();
extract($data, EXTR_SKIP);
try {
eval('?' . '>' . $php);
} catch (\Exception $e) {
while (ob_get_level() > $obLevel) {
ob_end_clean();
}
throw $e;
} catch (\Throwable $e) {
while (ob_get_level() > $obLevel) {
ob_end_clean();
}
throw new FatalThrowableError($e);
}
return ob_get_clean();
}
}

View File

@ -41,11 +41,11 @@ return [
'username' => env('DB_USERNAME1', 'forge'),
'password' => env('DB_PASSWORD1', ''),
'port' => env('DB_PORT1', '3306'),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => env('DB_STRICT', false),
'engine' => 'InnoDB',
'engine' => 'InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8',
],
'sqlite' => [
@ -92,7 +92,7 @@ return [
'prefix' => '',
'prefix_indexes' => true,
'strict' => env('DB_STRICT', false),
'engine' => 'InnoDB',
'engine' => 'InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8',
],
'db-ninja-02' => [
@ -107,7 +107,7 @@ return [
'prefix' => '',
'prefix_indexes' => true,
'strict' => env('DB_STRICT', false),
'engine' => 'InnoDB',
'engine' => 'InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8',
],
],

View File

@ -15,6 +15,9 @@ class CreateUsersTable extends Migration
public function up()
{
DB::raw("SET GLOBAL innodb_file_per_table=1;");
DB::raw("SET GLOBAL innodb_file_format=Barracuda;");
Schema::create('languages', function ($table) {
$table->increments('id');
$table->string('name');
@ -179,7 +182,7 @@ class CreateUsersTable extends Migration
});
DB::statement('ALTER table companies key_block_size=8 row_format=compressed');
//DB::statement('ALTER table companies key_block_size=8 row_format=compressed');
Schema::create('company_user', function (Blueprint $table) {
@ -195,6 +198,7 @@ class CreateUsersTable extends Migration
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->index(['account_id', 'company_id']);
@ -255,8 +259,7 @@ class CreateUsersTable extends Migration
$table->unique(['oauth_user_id', 'oauth_provider_id']);
// $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
$table->foreign('user_id')->references('user_id')->on('company_users')->onDelete('cascade');
});
@ -364,7 +367,6 @@ class CreateUsersTable extends Migration
$table->timestamps(6);
$table->softDeletes('deleted_at', 6);
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
$table->foreign('client_id')->references('id')->on('clients')->onDelete('cascade');
//$table->unique(['company_id', 'email']);
});
@ -755,7 +757,7 @@ class CreateUsersTable extends Migration
$t->foreign('client_contact_id')->references('id')->on('client_contacts')->onDelete('cascade');
$t->foreign('company_gateway_id')->references('id')->on('company_gateways')->onDelete('cascade');
$t->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
;
$t->foreign('payment_type_id')->references('id')->on('payment_types');
});
@ -766,6 +768,9 @@ class CreateUsersTable extends Migration
$table->unsignedInteger('paymentable_id');
$table->decimal('amount', 16, 4)->default(0);
$table->string('paymentable_type');
$table->foreign('payment_id')->references('id')->on('payments')->onDelete('cascade');
});
Schema::create('payment_libraries', function ($t) {
@ -896,7 +901,8 @@ class CreateUsersTable extends Migration
Schema::create('backups', function ($table) {
$table->increments('id');
$table->unsignedInteger('activity_id');
$table->mediumText('json_backup')->nullable();
$table->longText('json_backup')->nullable();
$table->longText('html_backup')->nullable();
$table->timestamps(6);
$table->foreign('activity_id')->references('id')->on('activities')->onDelete('cascade');

View File

@ -73,6 +73,9 @@ Route::group(['middleware' => ['api_db','api_secret_check','token_auth'], 'prefi
Route::post('users/bulk', 'UserController@bulk')->name('users.bulk')->middleware('password_protected');
Route::post('migration/purge/{company}', 'MigrationController@purgeCompany');
Route::post('migration/purge_save_settings/{company}', 'MigrationController@purgeCompanySaveSettings');
Route::resource('companies', 'CompanyController'); // name = (companies. index / create / show / update / destroy / edit
Route::resource('company_gateways', 'CompanyGatewayController');

View File

@ -0,0 +1,96 @@
<?php
namespace Feature;
use App\Jobs\Account\CreateAccount;
use App\Models\Account;
use App\Models\Client;
use App\Models\Company;
use App\Models\Invoice;
use App\Models\User;
use App\Utils\Traits\UserSessionAttributes;
use Faker\Factory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Tests\MockAccountData;
use Tests\TestCase;
/**
* @test
* @covers App\Http\Controllers\MigrationController
*/
class MigrationTest extends TestCase
{
use DatabaseTransactions;
use MockAccountData;
public function setUp() :void
{
parent::setUp();
Session::start();
$this->faker = \Faker\Factory::create();
Model::reguard();
$this->makeTestData();
}
public function testCompanyExists()
{
$co = Company::find($this->company->id);
// $this->assertNull($this->company);
$this->assertNotNull($co);
}
public function testThatCompanyDeletesCompletely()
{
$company_id = $this->company->id;
$this->company->delete();
$this->company->fresh();
$co = Company::find($company_id);
// $this->assertNull($this->company);
$this->assertNull($co);
}
public function testCompanyChildDeletes()
{
$this->makeTestData();
$this->assertNotNull($this->company);
$co = Client::whereCompanyId($this->company->id)->get();
$inv = Invoice::whereCompanyId($this->company->id)->get();
$this->assertEquals($co->count(),1);
$this->assertEquals($inv->count(),1);
DB::statement( 'DELETE FROM `clients` WHERE `company_id`=:company_id', array('company_id' => $this->company->id) );
$co = Client::whereCompanyId($this->company->id)->get();
$inv = Invoice::whereCompanyId($this->company->id)->get();
$this->assertEquals($co->count(),0);
$this->assertEquals($inv->count(),0);
$this->assertNotNull($this->company);
$this->assertNotNull($this->company->settings);
$this->assertNotNull($this->company->settings->timezone_id);
}
}

View File

@ -28,6 +28,7 @@ use App\Models\GroupSetting;
use App\Models\Invoice;
use App\Models\Quote;
use App\Models\RecurringInvoice;
use App\Models\User;
use App\Utils\Traits\GeneratesCounter;
use App\Utils\Traits\MakesHash;
use Illuminate\Support\Carbon;
@ -93,11 +94,15 @@ trait MockAccountData
$this->account->default_company_id = $this->company->id;
$this->account->save();
$this->user = factory(\App\Models\User::class)->create([
// 'account_id' => $account->id,
'confirmation_code' => $this->createDbHash(config('database.default'))
]);
$this->user = User::whereEmail('user@example.com')->first();
if(!$this->user){
$this->user = factory(\App\Models\User::class)->create([
// 'account_id' => $account->id,
'confirmation_code' => $this->createDbHash(config('database.default'))
]);
}
$this->token = \Illuminate\Support\Str::random(64);
$company_token = CompanyToken::create([

View File

@ -9,10 +9,12 @@ use App\Factory\InvoiceFactory;
use App\Factory\ProductFactory;
use App\Factory\UserFactory;
use App\Models\Client;
use App\Models\User;
use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Session;
use Tests\MockAccountData;
use Tests\TestCase;
/**
@ -22,6 +24,7 @@ class FactoryCreationTest extends TestCase
{
use MakesHash;
use DatabaseTransactions;
use MockAccountData;
public function setUp() :void
{
@ -34,21 +37,8 @@ class FactoryCreationTest extends TestCase
Model::reguard();
$this->account = factory(\App\Models\Account::class)->create();
$this->company = factory(\App\Models\Company::class)->create([
'account_id' => $this->account->id,
'domain' => 'ninja.test',
]);
$this->account->default_company_id = $this->company->id;
$this->account->save();
$this->user = factory(\App\Models\User::class)->create([
// 'account_id' => $account->id,
'confirmation_code' => $this->createDbHash(config('database.default'))
]);
$this->makeTestData();
}
/**
@ -120,13 +110,13 @@ class FactoryCreationTest extends TestCase
*/
public function testClientCreate()
{
$client = ClientFactory::create($this->company->id, $this->user->id);
$cliz = ClientFactory::create($this->company->id, $this->user->id);
$client->save();
$cliz->save();
$this->assertNotNull($client);
$this->assertNotNull($cliz);
$this->assertInternalType("int", $client->id);
$this->assertInternalType("int", $cliz->id);
}
/**
@ -136,33 +126,13 @@ class FactoryCreationTest extends TestCase
public function testClientContactCreate()
{
factory(\App\Models\Client::class)->create(['user_id' => $this->user->id, 'company_id' => $this->company->id])->each(function ($c){
$cliz = ClientFactory::create($this->company->id, $this->user->id);
factory(\App\Models\ClientContact::class,1)->create([
'user_id' => $this->user->id,
'client_id' => $c->id,
'company_id' => $this->company->id,
'is_primary' => 1
]);
$cliz->save();
factory(\App\Models\ClientContact::class,2)->create([
'user_id' => $this->user->id,
'client_id' => $c->id,
'company_id' => $this->company->id
]);
});
$client = Client::whereUserId($this->user->id)->whereCompanyId($this->company->id)->first();
$contact = ClientContactFactory::create($this->company->id, $this->user->id);
$contact->client_id = $client->id;
$contact->save();
$this->assertNotNull($contact);
$this->assertInternalType("int", $contact->id);
$this->assertNotNull($cliz->contacts);
$this->assertEquals(1, $cliz->contacts->count());
$this->assertInternalType("int", $cliz->contacts->first()->id);
}

View File

@ -2,12 +2,15 @@
namespace Tests\Unit;
use App\DataMapper\ClientSettings;
use App\DataMapper\DefaultSettings;
use App\Factory\ClientFactory;
use App\Models\Client;
use App\Models\Company;
use App\Models\Credit;
use App\Models\Invoice;
use App\Models\RecurringInvoice;
use App\Models\User;
use App\Utils\Traits\GeneratesCounter;
use App\Utils\Traits\GeneratesNumberCounter;
use App\Utils\Traits\MakesHash;
@ -15,6 +18,7 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;
use Tests\MockAccountData;
use Tests\TestCase;
/**
@ -26,7 +30,7 @@ class GeneratesCounterTest extends TestCase
use GeneratesCounter;
use DatabaseTransactions;
use MakesHash;
//use MockAccountData;
use MockAccountData;
public function setUp() :void
{
@ -36,49 +40,8 @@ class GeneratesCounterTest extends TestCase
Session::start();
$this->faker = \Faker\Factory::create();
Model::reguard();
$account = factory(\App\Models\Account::class)->create();
$company = factory(\App\Models\Company::class)->create([
'account_id' => $account->id,
'domain' => 'ninja.test',
]);
$account->default_company_id = $company->id;
$account->save();
$user = factory(\App\Models\User::class)->create([
// 'account_id' => $account->id,
'confirmation_code' => $this->createDbHash(config('database.default'))
]);
$userPermissions = collect([
'view_invoice',
'view_client',
'edit_client',
'edit_invoice',
'create_invoice',
'create_client'
]);
$userSettings = DefaultSettings::userSettings();
$user->companies()->attach($company->id, [
'account_id' => $account->id,
'is_owner' => 1,
'is_admin' => 1,
'permissions' => $userPermissions->toJson(),
'settings' => json_encode($userSettings),
'is_locked' => 0,
]);
factory(\App\Models\Client::class)->create(['user_id' => $user->id, 'company_id' => $company->id])->each(function ($c) use ($user, $company){
factory(\App\Models\ClientContact::class,1)->create([
'user_id' => $user->id,
'client_id' => $c->id,
'company_id' => $company->id,
'is_primary' => 1
]);
factory(\App\Models\ClientContact::class,2)->create([
'user_id' => $user->id,
'client_id' => $c->id,
'company_id' => $company->id
]);
});
$this->client = Client::whereUserId($user->id)->whereCompanyId($company->id)->first();
$this->makeTestData();
}
@ -92,11 +55,11 @@ class GeneratesCounterTest extends TestCase
$invoice_number = $this->getNextInvoiceNumber($this->client);
$this->assertEquals($invoice_number, 1);
$this->assertEquals($invoice_number, 0007);
$invoice_number = $this->getNextInvoiceNumber($this->client);
$this->assertEquals($invoice_number, 2);
$this->assertEquals($invoice_number, '0008');
}
@ -110,6 +73,10 @@ class GeneratesCounterTest extends TestCase
$this->client->company->settings = $settings;
$this->client->company->save();
$this->client->settings = $settings;
$this->client->save();
$this->client->fresh();
$invoice_number = $this->getNextInvoiceNumber($this->client);
$invoice_number2 = $this->getNextInvoiceNumber($this->client);
@ -121,70 +88,86 @@ class GeneratesCounterTest extends TestCase
public function testInvoiceClientNumberPattern()
{
$settings = $this->client->company->settings;
$settings = $this->company->settings;
$settings->client_number_prefix = '';
$settings->client_number_pattern = '{$year}-{$clientCounter}';
$settings->client_number_counter = 10;
$settings->invoice_number_prefix = '';
$settings->invoice_number_pattern = '{$year}-{$clientCounter}';
$this->client->company->settings = $settings;
$this->client->company->save();
$this->company->settings = $settings;
$this->company->save();
$settings = $this->client->settings;
$settings->invoice_number_counter = 10;
$settings->client_number_pattern = '{$year}-{$clientCounter}';
$settings->client_number_counter = 10;
$this->client->settings = $settings;
$this->client->save();
$this->client->fresh();
$this->assertEquals($this->client->settings->invoice_number_counter,10);
$this->assertEquals($this->client->settings->client_number_counter,10);
$this->assertEquals($this->client->getSetting('client_number_pattern'), '{$year}-{$clientCounter}');
$invoice_number = $this->getNextInvoiceNumber($this->client);
$invoice_number = $this->getNextClientNumber($this->client);
$this->assertEquals($invoice_number, '2019-0010');
$this->assertEquals($invoice_number, '2019-0001');
$invoice_number = $this->getNextInvoiceNumber($this->client);
$this->assertEquals($invoice_number, '2019-0011');
$invoice_number = $this->getNextClientNumber($this->client);
$this->assertEquals($invoice_number, '2019-0002');
}
public function testInvoicePadding()
{
$settings = $this->client->company->settings;
$settings = $this->company->settings;
$settings->counter_padding = 5;
$this->client->company->settings = $settings;
$this->client->push();
$settings->invoice_number_counter = 7;
//$this->client->settings = $settings;
$this->company->settings = $settings;
$this->company->save();
$invoice_number = $this->getNextInvoiceNumber($this->client);
$cliz = ClientFactory::create($this->company->id, $this->user->id);
$cliz->settings = ClientSettings::defaults();
$cliz->save();
$invoice_number = $this->getNextInvoiceNumber($cliz);
$this->assertEquals($this->client->company->settings->counter_padding, 5);
$this->assertEquals($cliz->getSetting('counter_padding'), 5);
$this->assertEquals($invoice_number, '00007');
$this->assertEquals(strlen($invoice_number), 5);
$this->assertEquals($invoice_number, '00001');
$settings = $this->client->company->settings;
$settings = $this->company->settings;
$settings->counter_padding = 10;
$this->client->company->settings = $settings;
$this->client->push();
$this->company->settings = $settings;
$this->company->save();
$cliz = ClientFactory::create($this->company->id, $this->user->id);
$cliz->settings = ClientSettings::defaults();
$cliz->save();
$invoice_number = $this->getNextInvoiceNumber($this->client);
$invoice_number = $this->getNextInvoiceNumber($cliz);
$this->assertEquals($this->client->company->settings->counter_padding, 10);
$this->assertEquals($cliz->getSetting('counter_padding'), 10);
$this->assertEquals(strlen($invoice_number), 10);
$this->assertEquals($invoice_number, '0000000002');
$this->assertEquals($invoice_number, '0000000007');
}
public function testInvoicePrefix()
{
$settings = $this->client->company->settings;
$settings = $this->company->settings;
$settings->invoice_number_prefix = 'X';
$this->client->company->settings = $settings;
$this->client->company->save();
$this->company->settings = $settings;
$this->company->save();
$invoice_number = $this->getNextInvoiceNumber($this->client);
$cliz = ClientFactory::create($this->company->id, $this->user->id);
$cliz->settings = ClientSettings::defaults();
$cliz->save();
$invoice_number = $this->getNextInvoiceNumber($cliz);
$this->assertEquals($invoice_number, 'X0001');
$invoice_number = $this->getNextInvoiceNumber($this->client);
$invoice_number = $this->getNextInvoiceNumber($cliz);
$this->assertEquals($invoice_number, 'X0002');
@ -206,16 +189,20 @@ class GeneratesCounterTest extends TestCase
public function testClientNumberPrefix()
{
$settings = $this->client->company->settings;
$settings = $this->company->settings;
$settings->client_number_prefix = 'C';
$this->client->company->settings = $settings;
$this->client->company->save();
$this->company->settings = $settings;
$this->company->save();
$client_number = $this->getNextClientNumber($this->client);
$cliz = ClientFactory::create($this->company->id, $this->user->id);
$cliz->settings = ClientSettings::defaults();
$cliz->save();
$client_number = $this->getNextClientNumber($cliz);
$this->assertEquals($client_number, 'C0001');
$client_number = $this->getNextClientNumber($this->client);
$client_number = $this->getNextClientNumber($cliz);
$this->assertEquals($client_number, 'C0002');
@ -224,21 +211,23 @@ class GeneratesCounterTest extends TestCase
public function testClientNumberPattern()
{
$settings = $this->client->company->settings;
$settings = $this->company->settings;
$settings->client_number_prefix = '';
$settings->client_number_pattern = '{$year}-{$user_id}-{$counter}';
$this->client->company->settings = $settings;
$this->client->company->save();
$this->client->save();
$this->client->fresh();
$this->company->settings = $settings;
$this->company->save();
$client_number = $this->getNextClientNumber($this->client);
$this->assertEquals($client_number, date('Y') . '-' . $this->client->user_id . '-0001');
$cliz = ClientFactory::create($this->company->id, $this->user->id);
$cliz->settings = ClientSettings::defaults();
$cliz->save();
$client_number = $this->getNextClientNumber($this->client);
$client_number = $this->getNextClientNumber($cliz);
$this->assertEquals($client_number, date('Y') . '-' . $this->client->user_id . '-0002');
$this->assertEquals($client_number, date('Y') . '-' . str_pad($this->client->user_id, 2, '0', STR_PAD_LEFT) . '-0001');
$client_number = $this->getNextClientNumber($cliz);
$this->assertEquals($client_number, date('Y') . '-' . str_pad($this->client->user_id, 2, '0', STR_PAD_LEFT) . '-0002');
}
/*