added invoice profile

This commit is contained in:
Peter Papp
2021-04-27 10:16:31 +02:00
parent f7135c9b27
commit e7c4048258
11 changed files with 232 additions and 145 deletions

View File

@@ -46,7 +46,7 @@ class InvoiceController extends Controller
*/
public function get_invoice(Invoice $invoice)
{
if (! Storage::exists(invoice_path($invoice))) {
if (!Storage::exists(invoice_path($invoice))) {
abort(404, 'Not Found');
}
@@ -79,9 +79,10 @@ class InvoiceController extends Controller
public function store(StoreInvoiceRequest $request)
{
$client = $this->getOrStoreClient($request);
$user = $request->user();
$invoice = Invoice::create([
'user_id' => $request->user()->id,
'user_id' => $user->id,
'client_id' => $client->id ?? null,
'invoice_type' => $request->invoice_type,
'invoice_number' => $request->invoice_number,
@@ -90,6 +91,7 @@ class InvoiceController extends Controller
'discount_type' => $request->discount_type ?? null,
'discount_rate' => $request->discount_rate ?? null,
'items' => $request->items,
'user' => $user->invoiceProfile,
'client' => [
'email' => $client->email ?? $request->client_email,
'name' => $client->name ?? $request->client_name,
@@ -106,17 +108,17 @@ class InvoiceController extends Controller
// Generate PDF
\PDF::loadView('oasis.invoices.invoice', [
'invoice' => Invoice::find($invoice->id),
'user' => $request->user(),
'user' => $user,
])
->setPaper('a4')
->setOrientation('portrait')
->save(
storage_path("app/files/{$request->user()->id}/invoice-{$invoice->id}.pdf")
storage_path("app/files/{$user->id}/invoice-{$invoice->id}.pdf")
);
if ($request->send_invoice && $invoice->client['email']) {
Notification::route('mail', $invoice->client['email'])->notify(
new InvoiceDeliveryNotification($request->user(), $invoice)
new InvoiceDeliveryNotification($user, $invoice)
);
}

View File

@@ -37,11 +37,6 @@ class Invoice extends Model
return $this->hasOne(Client::class, 'id', 'user_id');
}
/**
* Index file
*
* @return array
*/
public function toSearchableArray()
{
$array = $this->toArray();
@@ -72,24 +67,6 @@ class Invoice extends Model
$invoice->total_tax = invoice_total_tax($invoice);
$invoice->currency = 'CZK';
$user = Auth::user() ?? User::find($invoice->user_id);
$invoice->author_name = $user->settings->name ?? null;
$invoice->author_stamp = ''; // TODO: doplnit
$invoice->user = [
'name' => $user->settings->name ?? null,
'address' => $user->settings->address ?? null,
'state' => $user->settings->state ?? null,
'city' => $user->settings->city ?? null,
'postal_code' => $user->settings->postcode ?? null,
'country' => $user->settings->country ?? null,
'phone_number' => $user->settings->phoneNumber ?? null,
'bank_name' => $user->settings->bank_name ?? null,
'iban' => $user->settings->iban ?? null,
'swift' => $user->settings->swift ?? null,
];
});
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Models\Oasis;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
class InvoiceProfile extends Model
{
use HasFactory;
public $guarded = ['id'];
public $incrementing = false;
protected $keyType = 'string';
public function user()
{
return $this->hasOne(User::class, 'id', 'user_id');
}
protected static function boot()
{
parent::boot();
static::creating(function ($invoice) {
$invoice->id = (string) Str::uuid();
});
}
}

View File

@@ -4,20 +4,21 @@ namespace App\Traits;
use App\Models\Oasis\Client;
use App\Models\Oasis\Invoice;
use App\Models\Oasis\InvoiceProfile;
use App\Models\Oasis\SubscriptionRequest;
trait Oasis
{
/**
* Get user subscription request
*
* @return mixed
*/
public function subscriptionRequest()
{
return $this->hasOne(SubscriptionRequest::class);
}
public function invoiceProfile()
{
return $this->hasOne(InvoiceProfile::class);
}
public function clients()
{
return $this->hasMany(Client::class, 'user_id', 'id');

View File

@@ -3,9 +3,6 @@
namespace Database\Factories\Oasis;
use App\Models\Oasis\Invoice;
use App\Models\User;
use Carbon\Carbon;
use Database\Factories\UserFactory;
use Illuminate\Database\Eloquent\Factories\Factory;
class InvoiceFactory extends Factory
@@ -32,7 +29,7 @@ class InvoiceFactory extends Factory
'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,
'user' => null,
'client' => [
'name' => $this->faker->company,
'email' => $this->faker->email,
@@ -47,21 +44,6 @@ class InvoiceFactory extends Factory
'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),
@@ -77,7 +59,7 @@ class InvoiceFactory extends Factory
],
],
'discount_type' => $this->faker->randomElement(['percent', 'value', null]),
'delivery_at' => $this->faker->dateTimeBetween(
'delivery_at' => $this->faker->dateTimeBetween(
$startDate = '-6 months', $endDate = 'now', $timezone = null
),
'created_at' => $this->faker->dateTimeBetween(

View File

@@ -0,0 +1,51 @@
<?php
namespace Database\Factories\Oasis;
use App\Models\Oasis\InvoiceProfile;
use Illuminate\Database\Eloquent\Factories\Factory;
class InvoiceProfileFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = InvoiceProfile::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'id' => $this->faker->uuid,
'user_id' => $this->faker->uuid,
'company' => $this->faker->company,
'logo' => '',
'email' => $this->faker->email,
'ico' => rand(11111111, 99999999),
'dic' => rand(11111111, 99999999),
'ic_dph' => 'SK' . rand(111111111111, 999999999999),
'registration_notes' => $this->faker->realText(80),
'author' => $this->faker->name,
'stamp' => '',
'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' => $this->faker->phoneNumber,
'bank' => $this->faker->randomElement([
'Fio Banka', 'Tatra Banka'
]),
'iban' => $this->faker->iban('CZ'),
'swift' => $this->faker->swiftBicNumber,
];
}
}

View File

@@ -18,7 +18,9 @@ class CreateInvoicesTable extends Migration
$table->uuid('user_id')->index();
$table->uuid('client_id')->nullable()->index();
$table->enum('invoice_type', ['regular-invoice', 'advance-invoice']);
$table->enum('invoice_type', [
'regular-invoice', 'advance-invoice'
]);
$table->text('invoice_number')->nullable();
$table->text('variable_number')->nullable();
@@ -39,9 +41,6 @@ class CreateInvoicesTable extends Migration
$table->string('total_net')->nullable();
$table->string('total_tax')->nullable();
$table->text('author_stamp')->nullable();
$table->text('author_name')->nullable();
$table->timestamps();
});
}

View File

@@ -1,39 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddBankDetailsToUserSettingsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('user_settings', function (Blueprint $table) {
$table->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']);
});
}
}

View File

@@ -0,0 +1,57 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateInvoiceProfilesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('invoice_profiles', function (Blueprint $table) {
$table->uuid('id')->primary()->index();
$table->uuid('user_id')->index();
$table->text('company')->nullable();
$table->string('logo')->nullable();
$table->string('email')->nullable();
$table->string('phone')->nullable();
$table->text('address')->nullable();
$table->text('state')->nullable();
$table->text('city')->nullable();
$table->text('postal_code')->nullable();
$table->text('country')->nullable();
$table->string('ico')->nullable();
$table->string('dic')->nullable();
$table->string('ic_dph')->nullable();
$table->text('registration_notes')->nullable();
$table->text('bank')->nullable();
$table->string('iban')->nullable();
$table->string('swift')->nullable();
$table->string('author')->nullable();
$table->string('stamp')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('invoice_profiles');
}
}

View File

@@ -30,8 +30,8 @@
{{--TODO: klientske logo--}}
<img class="logo" src="{{ base64_from_storage_image('system/5YDehSGh-vuefilemanager-horizontal-logo.svg') }}">
<b class="email">{{ $user->email }}</b>
<b class="phone">{{ $user->settings->phone_number }}</b>
<b class="email">{{ $user->invoiceProfile->email }}</b>
<b class="phone">{{ $user->invoiceProfile->phone }}</b>
</div>
<div class="col-right align-right">
@if($invoice->invoice_type === 'regular-invoice')
@@ -78,31 +78,31 @@
<div class="content-box">
<h3>Dodávateľ:</h3>
<p>{{ $user->settings->name }}</p>
<small>{{ $user->settings->registration_notes }}</small>
<p>{{ $invoice->user['company'] }}</p>
<small>{{ $invoice->user['registration_notes'] }}</small>
</div>
<div class="content-box">
<h3>Sídlo:</h3>
<p>{{ $user->settings->address }} {{ $user->settings->city }}</p>
<p>{{ $user->settings->postal_code }}, {{ $user->settings->country }}</p>
<p>{{ $invoice->user['address'] }} {{ $invoice->user['city'] }}</p>
<p>{{ $invoice->user['postal_code'] }}, {{ $invoice->user['country'] }}</p>
</div>
<div class="content-box">
<h3>Faktúračné údaje:</h3>
@isset($user->settings->ico)
<p>IČO: {{ $user->settings->ico }}</p>
@isset($invoice->user['ico'])
<p>IČO: {{ $invoice->user['ico'] }}</p>
@endisset
@isset($user->settings->dic)
<p>DIČ: {{ $user->settings->dic }}</p>
@isset($invoice->user['dic'])
<p>DIČ: {{ $invoice->user['dic'] }}</p>
@endisset
@isset($invoice->supplier_ic_dph)
<p>IČ DPH: {{ $user->settings->ic_dph }}</p>
@isset($invoice->user['ic_dph'])
<p>IČ DPH: {{ $invoice->user['ic_dph'] }}</p>
@endisset
<p>{{ $user->settings->bank_name }}</p>
<p>IBAN: {{ $user->settings->iban }}, BIC kód/SWIFT: {{ $user->settings->swift }}</p>
<p>{{ $invoice->user['bank'] }}</p>
<p>IBAN: {{ $invoice->user['iban'] }}, BIC kód/SWIFT: {{ $invoice->user['swift'] }}</p>
</div>
</section>
@@ -111,7 +111,7 @@
<div class="special-item">
<div class="padding">
<b>Číslo účtu:</b>
<span>{{ $user->settings->iban }}</span>
<span>{{ $invoice->user['iban'] }}</span>
</div>
</div>
<div class="special-item">
@@ -150,14 +150,10 @@
<td class="table-cell">
<span>Celkom</span>
</td>
{{--TODO: zmenit dph z klienta na usera--}}
@if($invoice->client['ic_dph'])
@if($invoice->user['ic_dph'])
<td class="table-cell">
<span>Sadzba DPH</span>
</td>
@endif
@if($invoice->client['ic_dph'])
<td class="table-cell">
<span>DPH</span>
</td>
@@ -185,13 +181,13 @@
<span>{{ format_to_currency($item['price'] * $item['amount']) }}</span>
</td>
@if($invoice->client['ic_dph'])
@if($invoice->user['ic_dph'])
<td class="table-cell">
<span>{{ $item['tax_rate'] }} %</span>
</td>
@endif
@if($invoice->client['ic_dph'])
@if($invoice->user['ic_dph'])
<td class="table-cell">
<span>{{ invoice_item_only_tax_price($item, true) }}</span>
</td>
@@ -218,7 +214,7 @@
@endif
{{--VAT Payer--}}
@if($invoice->client['ic_dph'] && ! $invoice->discount_type)
@if($invoice->user['ic_dph'] && ! $invoice->discount_type)
<li class="row">
<span>Cena bez DPH:</span>
<span>{{ format_to_currency($invoice->total_net) }}</span>
@@ -230,7 +226,7 @@
@endif
{{--VAT Payer with Discount--}}
@if($invoice->client['ic_dph'] && $invoice->discount_type)
@if($invoice->user['ic_dph'] && $invoice->discount_type)
<li class="row">
<span>Cena bez DPH:</span>
<span>
@@ -258,7 +254,7 @@
<li class="row">
<b>Spolu k úhrade:</b>
@if($invoice->client['ic_dph'])
@if($invoice->user['ic_dph'])
<b>{{ format_to_currency(invoice_total_net($invoice) + invoice_total_tax($invoice)) }}</b>
@else
<b>{{ format_to_currency(invoice_total_net($invoice)) }}</b>
@@ -274,7 +270,7 @@
{{--Invoice header--}}
<div class="invoice-author">
<div class="tax-note">
@if(! $invoice->client['ic_dph'])
@if(! $invoice->user['ic_dph'])
<p>Nie sme platci DPH</p>
@endif
</div>
@@ -283,7 +279,7 @@
<img src="{{ asset('/stamp.png') }}">
@endif
{{--<img src="{{ public_path('/stamp.png') }}">--}}
<span class="highlight">Faktúru vystavil:</span> {{ $invoice->user['name'] }}
<span class="highlight">Faktúru vystavil:</span> {{ $invoice->user['author'] }}
</div>
</div>

View File

@@ -3,6 +3,7 @@
namespace Tests\Feature\Oasis;
use App\Models\Oasis\Client;
use App\Models\Oasis\InvoiceProfile;
use App\Notifications\Oasis\InvoiceDeliveryNotification;
use PDF;
use Carbon\Carbon;
@@ -191,12 +192,19 @@ class OasisInvoiceTest extends TestCase
*/
public function it_test_invoice_factory()
{
$invoice = Invoice::factory(Invoice::class)
$invoice_profile = InvoiceProfile::factory(InvoiceProfile::class)
->create();
$invoice = Invoice::factory(Invoice::class)
->create(['user' => $invoice_profile->toArray()]);
$this->assertDatabaseHas('invoices', [
'id' => $invoice->id,
]);
$this->assertDatabaseMissing('invoices', [
'user' => null,
]);
}
/**
@@ -214,28 +222,21 @@ class OasisInvoiceTest extends TestCase
$user = User::factory(User::class)
->create(['role' => 'user']);
$user->settings()->update([
'ic_dph' => 'SK2023489457',
'dic' => '2023489457',
'ico' => '46530045',
'bank_name' => 'Fio a.s.',
'iban' => 'SK7583300000002000476497',
'swift' => 'FIOZSKBAXXX',
'registration_notes' => 'Registrácia na OR SR Bratislava I. oddiel: Sro vl. č 91906',
]);
InvoiceProfile::factory(InvoiceProfile::class)
->create(['user_id' => $user->id]);
Sanctum::actingAs($user);
$this->postJson('/api/oasis/invoices', [
'invoice_type' => 'regular-invoice',
'invoice_number' => '2120001',
'variable_number' => '2120001',
'items' => $this->items,
'discount_type' => 'percent',
'discount_rate' => 10,
'delivery_at' => Carbon::now()->addWeek(),
'store_client' => true,
'send_invoice' => true,
'invoice_type' => 'regular-invoice',
'invoice_number' => '2120001',
'variable_number' => '2120001',
'items' => $this->items,
'discount_type' => 'percent',
'discount_rate' => 10,
'delivery_at' => Carbon::now()->addWeek(),
'store_client' => true,
'send_invoice' => true,
'client' => 'others',
'client_avatar' => $avatar,
'client_name' => 'VueFileManager Inc.',
@@ -285,6 +286,9 @@ class OasisInvoiceTest extends TestCase
$user = User::factory(User::class)
->create(['role' => 'user']);
InvoiceProfile::factory(InvoiceProfile::class)
->create(['user_id' => $user->id]);
Sanctum::actingAs($user);
$this->postJson('/api/oasis/invoices', [
@@ -340,6 +344,9 @@ class OasisInvoiceTest extends TestCase
$user = User::factory(User::class)
->create(['role' => 'user']);
InvoiceProfile::factory(InvoiceProfile::class)
->create(['user_id' => $user->id]);
Sanctum::actingAs($user);
$this->postJson('/api/oasis/invoices', [
@@ -396,6 +403,9 @@ class OasisInvoiceTest extends TestCase
$user = User::factory(User::class)
->create(['role' => 'user']);
InvoiceProfile::factory(InvoiceProfile::class)
->create(['user_id' => $user->id]);
Sanctum::actingAs($user);
$this->postJson('/api/oasis/invoices', [
@@ -451,6 +461,9 @@ class OasisInvoiceTest extends TestCase
$user = User::factory(User::class)
->create(['role' => 'user']);
InvoiceProfile::factory(InvoiceProfile::class)
->create(['user_id' => $user->id]);
Sanctum::actingAs($user);
$client = Client::factory(Client::class)
@@ -492,6 +505,9 @@ class OasisInvoiceTest extends TestCase
$user = User::factory(User::class)
->create(['role' => 'user']);
InvoiceProfile::factory(InvoiceProfile::class)
->create(['user_id' => $user->id]);
Sanctum::actingAs($user);
$client = Client::factory(Client::class)
@@ -527,12 +543,16 @@ class OasisInvoiceTest extends TestCase
$user = User::factory(User::class)
->create(['role' => 'user']);
$profile = InvoiceProfile::factory(InvoiceProfile::class)
->create(['user_id' => $user->id]);
Sanctum::actingAs($user);
$invoice = Invoice::factory(Invoice::class)
->create([
'user_id' => $user->id,
'invoice_type' => 'regular-invoice'
'invoice_type' => 'regular-invoice',
'user' => $profile,
]);
$this->getJson('/api/oasis/invoices/regular')
@@ -549,12 +569,16 @@ class OasisInvoiceTest extends TestCase
$user = User::factory(User::class)
->create(['role' => 'user']);
$profile = InvoiceProfile::factory(InvoiceProfile::class)
->create(['user_id' => $user->id]);
Sanctum::actingAs($user);
$invoice = Invoice::factory(Invoice::class)
->create([
'user_id' => $user->id,
'invoice_type' => 'advance-invoice'
'invoice_type' => 'advance-invoice',
'user' => $profile,
]);
$this->getJson('/api/oasis/invoices/advance')
@@ -571,6 +595,9 @@ class OasisInvoiceTest extends TestCase
$user = User::factory(User::class)
->create(['role' => 'user']);
$profile = InvoiceProfile::factory(InvoiceProfile::class)
->create(['user_id' => $user->id]);
Sanctum::actingAs($user);
Invoice::factory(Invoice::class)
@@ -580,7 +607,8 @@ class OasisInvoiceTest extends TestCase
'invoice_number' => 2001212,
'client' => [
'name' => 'VueFileManager Inc.',
]
],
'user' => $profile,
]);
$this->getJson('/api/oasis/invoices/search?type=regular-invoice&query=2001212')