From 5a9583be5b493f8dd473c5dc86f7f601acdaa997 Mon Sep 17 00:00:00 2001 From: Peter Papp Date: Wed, 21 Apr 2021 15:22:54 +0200 Subject: [PATCH] - client and invoice scaffolding --- .../Controllers/Oasis/ClientController.php | 11 ++ .../Controllers/Oasis/InvoiceController.php | 11 ++ app/Http/custom-helpers.php | 73 ++++++++++ app/Models/Oasis/Client.php | 38 ++++++ app/Models/Oasis/Invoice.php | 44 ++++++ app/Traits/Oasis.php | 12 ++ composer.json | 3 +- database/factories/Oasis/ClientFactory.php | 44 ++++++ database/factories/Oasis/InvoiceFactory.php | 116 ++++++++++++++++ ...021_04_21_060812_create_invoices_table.php | 58 ++++++++ ...2021_04_21_061055_create_clients_table.php | 48 +++++++ ...dd_bank_details_to_user_settings_table.php | 39 ++++++ tests/Feature/Oasis/OasisClientTest.php | 25 ++++ tests/Feature/Oasis/OasisInvoiceTest.php | 127 ++++++++++++++++++ 14 files changed, 648 insertions(+), 1 deletion(-) create mode 100644 app/Http/Controllers/Oasis/ClientController.php create mode 100644 app/Http/Controllers/Oasis/InvoiceController.php create mode 100644 app/Http/custom-helpers.php create mode 100644 app/Models/Oasis/Client.php create mode 100644 app/Models/Oasis/Invoice.php create mode 100644 database/factories/Oasis/ClientFactory.php create mode 100644 database/factories/Oasis/InvoiceFactory.php create mode 100644 database/migrations/oasis/2021_04_21_060812_create_invoices_table.php create mode 100644 database/migrations/oasis/2021_04_21_061055_create_clients_table.php create mode 100644 database/migrations/oasis/2021_04_21_065756_add_bank_details_to_user_settings_table.php create mode 100644 tests/Feature/Oasis/OasisClientTest.php create mode 100644 tests/Feature/Oasis/OasisInvoiceTest.php diff --git a/app/Http/Controllers/Oasis/ClientController.php b/app/Http/Controllers/Oasis/ClientController.php new file mode 100644 index 00000000..cb25cc05 --- /dev/null +++ b/app/Http/Controllers/Oasis/ClientController.php @@ -0,0 +1,11 @@ +hasOne(User::class, 'id', 'user_id'); + } + + public function invoices() + { + return $this->hasMany(Invoice::class, 'client_id', 'id'); + } + + protected static function boot() + { + parent::boot(); + + static::creating(function ($order) { + $order->id = Str::uuid(); + }); + } +} diff --git a/app/Models/Oasis/Invoice.php b/app/Models/Oasis/Invoice.php new file mode 100644 index 00000000..7a3ad79b --- /dev/null +++ b/app/Models/Oasis/Invoice.php @@ -0,0 +1,44 @@ + 'array', + 'user' => 'array', + 'client' => 'array', + ]; + + public $guarded = ['id']; + + public $incrementing = false; + + protected $keyType = 'string'; + + public function user() + { + return $this->hasOne(User::class, 'id', 'user_id'); + } + + public function client() + { + return $this->hasOne(Client::class, 'id', 'user_id'); + } + + protected static function boot() + { + parent::boot(); + + static::creating(function ($order) { + $order->id = Str::uuid(); + }); + } +} diff --git a/app/Traits/Oasis.php b/app/Traits/Oasis.php index ceea98af..39dc0e12 100644 --- a/app/Traits/Oasis.php +++ b/app/Traits/Oasis.php @@ -2,6 +2,8 @@ namespace App\Traits; +use App\Models\Oasis\Client; +use App\Models\Oasis\Invoice; use App\Models\Oasis\SubscriptionRequest; trait Oasis @@ -15,4 +17,14 @@ trait Oasis { return $this->hasOne(SubscriptionRequest::class); } + + public function clients() + { + return $this->hasMany(Client::class); + } + + public function createdInvoices() + { + return $this->hasMany(Invoice::class); + } } diff --git a/composer.json b/composer.json index 2c4be2f1..12781933 100644 --- a/composer.json +++ b/composer.json @@ -61,7 +61,8 @@ "database/factories" ], "files": [ - "app/Http/helpers.php" + "app/Http/helpers.php", + "app/Http/custom-helpers.php" ] }, "autoload-dev": { diff --git a/database/factories/Oasis/ClientFactory.php b/database/factories/Oasis/ClientFactory.php new file mode 100644 index 00000000..5ba5edc7 --- /dev/null +++ b/database/factories/Oasis/ClientFactory.php @@ -0,0 +1,44 @@ + $this->faker->uuid, + 'user_id' => $this->faker->uuid, + 'name' => $this->faker->company, + 'email' => $this->faker->email, + 'phone_number' => $this->faker->phoneNumber, + 'address' => $this->faker->address, + 'city' => $this->faker->city, + 'postal_code' => $this->faker->postcode, + 'country' => $this->faker->randomElement( + ['SK', 'CZ', 'DE', 'FR'] + ), + 'ico' => $this->faker->numberBetween(11111111, 99999999), + 'dic' => $this->faker->numberBetween(11111111, 99999999), + 'ic_dph' => 'CZ' . $this->faker->numberBetween(1111111111, 9999999999), + 'created_at' => $this->faker->dateTimeBetween( + $startDate = '-36 months', $endDate = 'now', $timezone = null + ), + ]; + } +} diff --git a/database/factories/Oasis/InvoiceFactory.php b/database/factories/Oasis/InvoiceFactory.php new file mode 100644 index 00000000..6b52e908 --- /dev/null +++ b/database/factories/Oasis/InvoiceFactory.php @@ -0,0 +1,116 @@ + $this->faker->uuid, + 'user_id' => $this->faker->uuid, + 'client_id' => $this->faker->uuid, + 'invoice_type' => $this->faker->randomElement(['invoice', 'advance_invoice']), + 'invoice_number' => $this->faker->numberBetween(2120001, 2120999), + 'variable_number' => $this->faker->numberBetween(2120001, 2120999), + 'currency' => $this->faker->randomElement(['CZK', 'EUR']), + 'author_name' => $this->faker->name, + 'client' => [ + 'name' => $this->faker->company, + 'email' => $this->faker->email, + 'phone_number' => $this->faker->phoneNumber, + 'address' => $this->faker->address, + 'city' => $this->faker->city, + 'postal_code' => $this->faker->postcode, + 'country' => $this->faker->randomElement( + ['SK', 'CZ', 'DE', 'FR'] + ), + 'ico' => $this->faker->numberBetween(11111111, 99999999), + 'dic' => $this->faker->numberBetween(11111111, 99999999), + 'ic_dph' => 'CZ' . $this->faker->numberBetween(1111111111, 9999999999), + ], + 'user' => [ + 'name' => $this->faker->name, + 'address' => $this->faker->address, + 'state' => $this->faker->state, + 'city' => $this->faker->city, + 'postal_code' => $this->faker->postcode, + 'country' => $this->faker->randomElement( + ['SK', 'CZ', 'DE', 'FR'] + ), + 'phone_number' => $this->faker->phoneNumber, + + 'bank_name' => $this->faker->randomElement(['Fio Banka', 'Tatra Banka']), + 'iban' => $this->faker->iban('CZ'), + 'swift' => $this->faker->swiftBicNumber, + ], + 'items' => [ + [ + 'description' => $this->faker->realText(60), + 'amount' => $this->faker->numberBetween(1, 3), + 'tax_rate' => 20, + 'price' => $this->faker->randomElement([120, 360, 400, 80, 90, 45, 16, 8]), + ], + [ + 'description' => $this->faker->realText(60), + 'amount' => $this->faker->numberBetween(1, 3), + 'tax_rate' => 20, + 'price' => $this->faker->randomElement([120, 360, 400, 80, 90, 45, 16, 8]), + ], + ], + 'discount_type' => $this->faker->randomElement(['percent', 'value', null]), + 'delivery_at' => $this->faker->dateTimeBetween( + $startDate = '-36 months', $endDate = 'now', $timezone = null + ), + 'created_at' => $this->faker->dateTimeBetween( + $startDate = '-36 months', $endDate = 'now', $timezone = null + ), + ]; + } + + /** + * Configure the model factory. + * + * @return $this + */ + public function configure() + { + return $this->afterCreating(function (Invoice $invoice) { + + $invoice->delivery_at = $invoice->created_at; + $invoice->due_at = Carbon::parse($invoice->created_at)->addWeeks(2); + + if ($invoice->discount_type === 'percent') { + $invoice->discount_rate = $this->faker->randomElement([2, 5, 10, 15, 20]); + } + + if ($invoice->discount_type === 'value') { + $invoice->discount_rate = $this->faker->randomElement([20, 10]); + } + + $invoice->total_discount = invoice_total_discount($invoice); + $invoice->total_net = invoice_total_net($invoice); + $invoice->total_tax = invoice_total_tax($invoice); + + $invoice->save(); + }); + } +} diff --git a/database/migrations/oasis/2021_04_21_060812_create_invoices_table.php b/database/migrations/oasis/2021_04_21_060812_create_invoices_table.php new file mode 100644 index 00000000..dc42b33c --- /dev/null +++ b/database/migrations/oasis/2021_04_21_060812_create_invoices_table.php @@ -0,0 +1,58 @@ +uuid('id')->primary()->index(); + $table->uuid('user_id')->index(); + $table->uuid('client_id')->index(); + + $table->enum('invoice_type', ['invoice', 'advance_invoice']); + + $table->text('invoice_number')->nullable(); + $table->text('variable_number')->nullable(); + + $table->longText('client'); + $table->longText('user'); + $table->longText('items'); + + $table->dateTime('delivery_at')->nullable(); + $table->dateTime('due_at')->nullable(); + + $table->enum('discount_type', ['percent', 'value'])->nullable(); + $table->integer('discount_rate')->nullable(); + + $table->text('currency'); + + $table->integer('total_discount')->nullable(); + $table->integer('total_net')->nullable(); + $table->integer('total_tax')->nullable(); + + $table->text('author_stamp')->nullable(); + $table->text('author_name')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('invoices'); + } +} diff --git a/database/migrations/oasis/2021_04_21_061055_create_clients_table.php b/database/migrations/oasis/2021_04_21_061055_create_clients_table.php new file mode 100644 index 00000000..2e1d8412 --- /dev/null +++ b/database/migrations/oasis/2021_04_21_061055_create_clients_table.php @@ -0,0 +1,48 @@ +uuid('id')->primary()->index(); + $table->uuid('user_id')->index(); + + $table->text('name'); + $table->text('avatar')->nullable(); + + $table->text('email')->nullable(); + $table->text('phone_number')->nullable(); + + $table->text('address')->nullable(); + $table->text('city')->nullable(); + $table->text('postal_code')->nullable(); + $table->text('country')->nullable(); + + $table->text('ico')->nullable(); + $table->text('dic')->nullable(); + $table->text('ic_dph')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('clients'); + } +} diff --git a/database/migrations/oasis/2021_04_21_065756_add_bank_details_to_user_settings_table.php b/database/migrations/oasis/2021_04_21_065756_add_bank_details_to_user_settings_table.php new file mode 100644 index 00000000..71fdf2cd --- /dev/null +++ b/database/migrations/oasis/2021_04_21_065756_add_bank_details_to_user_settings_table.php @@ -0,0 +1,39 @@ +text('registration_notes')->nullable(); + + $table->text('dic')->nullable(); + $table->text('ic_dph')->nullable(); + + $table->text('bank_name')->nullable(); + $table->text('iban')->nullable(); + $table->text('swift')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('user_settings', function (Blueprint $table) { + $table->dropColumn(['bank_name','iban','swift']); + }); + } +} diff --git a/tests/Feature/Oasis/OasisClientTest.php b/tests/Feature/Oasis/OasisClientTest.php new file mode 100644 index 00000000..dfb364e8 --- /dev/null +++ b/tests/Feature/Oasis/OasisClientTest.php @@ -0,0 +1,25 @@ +create(); + + $this->assertDatabaseHas('clients', [ + 'name' => $client->name, + ]); + } +} diff --git a/tests/Feature/Oasis/OasisInvoiceTest.php b/tests/Feature/Oasis/OasisInvoiceTest.php new file mode 100644 index 00000000..27a302b7 --- /dev/null +++ b/tests/Feature/Oasis/OasisInvoiceTest.php @@ -0,0 +1,127 @@ +create(); + + $this->assertDatabaseHas('invoices', [ + 'id' => $invoice->id, + ]); + } + + /** + * @test + */ + public function it_test_invoice_total_net() + { + $invoice = [ + 'currency' => 'CZK', + 'items' => [ + [ + 'description' => 'Test 1', + 'amount' => 1, + 'tax_rate' => 20, + 'price' => 20, + ], + [ + 'description' => 'Test 2', + 'amount' => 3, + 'tax_rate' => 20, + 'price' => 50, + ], + ] + ]; + + $this->assertEquals(170, invoice_total_net($invoice)); + $this->assertEquals('170,00 Kč', invoice_total_net($invoice, true)); + } + + /** + * @test + */ + public function it_test_invoice_total_discount_as_percent() + { + $invoice = [ + 'currency' => 'CZK', + 'discount_type' => 'percent', + 'discount_rate' => 15, + 'items' => [ + [ + 'description' => 'Test 1', + 'amount' => 1, + 'tax_rate' => 20, + 'price' => 200, + ], + ] + ]; + + $this->assertEquals(30, invoice_total_discount($invoice)); + $this->assertEquals('30,00 Kč', invoice_total_discount($invoice, true)); + } + + /** + * @test + */ + public function it_test_invoice_total_discount_as_value() + { + $invoice = [ + 'currency' => 'CZK', + 'discount_type' => 'value', + 'discount_rate' => 18, + 'items' => [ + [ + 'description' => 'Test 1', + 'amount' => 1, + 'tax_rate' => 20, + 'price' => 100, + ], + ] + ]; + + $this->assertEquals(18, invoice_total_discount($invoice)); + $this->assertEquals('18,00 Kč', invoice_total_discount($invoice, true)); + } + + /** + * @test + */ + public function it_test_invoice_total_tax() + { + $invoice = [ + 'currency' => 'CZK', + 'discount_type' => 'value', + 'discount_rate' => 18, + 'items' => [ + [ + 'description' => 'Test 1', + 'amount' => 1, + 'tax_rate' => 20, + 'price' => 100, + ], + [ + 'description' => 'Test 2', + 'amount' => 2, + 'tax_rate' => 10, + 'price' => 100, + ], + ] + ]; + + $this->assertEquals(40, invoice_total_tax($invoice)); + $this->assertEquals('40,00 Kč', invoice_total_tax($invoice, true)); + } +}