diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php new file mode 100644 index 0000000..9d3c85e --- /dev/null +++ b/app/Http/Controllers/Api/ProjectController.php @@ -0,0 +1,66 @@ +json(Project::with(['customer'])->get()); + } + + /** + * Store a newly created resource in storage. + */ + public function store(Request $request): JsonResponse + { + $projectData = $request->validate([ + 'customer_id' => 'required|exists:customers,id', + 'name' => 'required|string', + 'project_number' => 'required|string', + 'description' => 'nullable|string', + 'start_date' => 'required|date', + 'end_date' => 'required|date', + ]); + + $project = new Project($projectData); + $project->save(); + + return response()->json($project); + } + + /** + * Update the specified resource in storage. + */ + public function update(Request $request, Project $project): JsonResponse + { + $projectData = $request->validate([ + 'customer_id' => 'required|exists:customers,id', + 'name' => 'required|string', + 'project_number' => 'required|string', + 'description' => 'nullable|string', + 'start_date' => 'required|date', + 'end_date' => 'required|date', + ]); + + $project->update($projectData); + + return response()->json($project); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(Project $project) + { + // + } +} diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php new file mode 100644 index 0000000..4a60d25 --- /dev/null +++ b/app/Http/Controllers/ProjectController.php @@ -0,0 +1,41 @@ + $project]); + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(Project $project): View + { + return view('projects.edit', ['project' => $project]); + } +} diff --git a/app/Models/Project.php b/app/Models/Project.php new file mode 100644 index 0000000..6db981a --- /dev/null +++ b/app/Models/Project.php @@ -0,0 +1,61 @@ + + */ + protected $fillable = [ + 'customer_id', + 'name', + 'project_number', + 'description', + 'start_date', + 'end_date', + ]; + + /** + * The attributes that are appended with attribute getters. + * + * @var string[] + */ + protected $appends = [ + 'start', + 'end', + ]; + + /** + * Get the end_date attribute in local format. + */ + public function getStartAttribute(): string + { + return (is_null($this->start_date)) ? '' : Carbon::createFromFormat('Y-m-d', $this->start_date)->format('d.m.Y'); + } + + /** + * Get the end_date attribute in local format. + */ + public function getEndAttribute(): string + { + return (is_null($this->end_date)) ? '' : Carbon::createFromFormat('Y-m-d', $this->end_date)->format('d.m.Y'); + } + + /** + * Get the customer this project belongs to. + */ + public function customer(): BelongsTo + { + return $this->belongsTo(Customer::class); + } +} diff --git a/database/migrations/2025_01_22_092556_create_projects_table.php b/database/migrations/2025_01_22_092556_create_projects_table.php new file mode 100644 index 0000000..551903e --- /dev/null +++ b/database/migrations/2025_01_22_092556_create_projects_table.php @@ -0,0 +1,36 @@ +id(); + $table->foreignId('customer_id')->constrained(); + + $table->string('name'); + $table->string('project_number'); + $table->text('description')->nullable(); + $table->date('start_date')->nullable(); + $table->date('end_date')->nullable(); + + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('projects'); + } +}; diff --git a/database/migrations/2025_01_22_094543_add_information_to_invoices_table.php b/database/migrations/2025_01_22_094543_add_information_to_invoices_table.php new file mode 100644 index 0000000..8a683ac --- /dev/null +++ b/database/migrations/2025_01_22_094543_add_information_to_invoices_table.php @@ -0,0 +1,34 @@ +foreignId('project_id')->nullable()->constrained(); + $table->integer('project_count')->nullable()->default(0); + $table->boolean('is_template')->default(false); + $table->string('currency_code')->default('EUR'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('invoices', function (Blueprint $table) { + $table->dropColumn('project_id'); + $table->dropColumn('project_count'); + $table->dropColumn('is_template'); + $table->dropColumn('currency_code'); + }); + } +}; diff --git a/lang/de/project.php b/lang/de/project.php new file mode 100644 index 0000000..29a3b0a --- /dev/null +++ b/lang/de/project.php @@ -0,0 +1,30 @@ + 'Projekt', + 'Projects' => 'Projekte', + 'Add new project' => 'Neues Projekt erstellen', + 'Add new project by clicking add' => 'Durch Klick auf "Anlegen" neue Rechnung erstellen', + 'Existing projects' => 'Bestehende Projekte', + 'Project Number' => 'Projektnummer', + 'Start date' => 'Projektstart', + 'End date' => 'Projektende', + 'Create new project' => 'Neues Projekt erstellen', + 'Select customer' => 'Kunde auswählen', + 'Select your customer' => 'Den Kunden des Projekts auswählen', + 'Project data' => 'Projektdaten', + 'Enter your project data. Klick Save to store the project.' => 'Gib die Daten des Projekts ein. Klicke auf "Speichern" um das Projekt zu erstellen.', + 'Edit existing project' => 'Projekt bearbeitet', + +]; diff --git a/resources/views/layouts/navigation.blade.php b/resources/views/layouts/navigation.blade.php index e880d91..80801c3 100644 --- a/resources/views/layouts/navigation.blade.php +++ b/resources/views/layouts/navigation.blade.php @@ -19,6 +19,10 @@ :active="\Illuminate\Support\Str::startsWith(request()->route()->getName(), 'customer.') || \Illuminate\Support\Str::startsWith(request()->route()->getName(), 'address.')"> {{ __('customer.Customers') }} + + {{ __('project.Projects') }} + {{ __('invoice.Invoices') }} diff --git a/resources/views/projects/create.blade.php b/resources/views/projects/create.blade.php new file mode 100644 index 0000000..fd04fd8 --- /dev/null +++ b/resources/views/projects/create.blade.php @@ -0,0 +1,203 @@ + + +

+ {{ __('project.Create new project') }} +

+
+ +
+
+ + +
+
+
+
+

+ {{ __('project.Select customer') }} +

+

+ {{ __("project.Select your customer") }} +

+
+ +
+ + +
+ +
+ +
+ +
+ +
+
+ +
+
+
+

+ {{ __('customer.Customer') }} +

+
+
+
+
+
+
+
+ + +
+
+
+
+

+ {{ __('project.Project data') }} +

+

+ {{ __("project.Enter your project data. Klick Save to store the project.") }} +

+
+
+ +
+

+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ {{ __('form.Save') }} +
+ +
+ +
+
+ +
+
+
+ + diff --git a/resources/views/projects/edit.blade.php b/resources/views/projects/edit.blade.php new file mode 100644 index 0000000..aeab20d --- /dev/null +++ b/resources/views/projects/edit.blade.php @@ -0,0 +1,197 @@ + + +

+ {{ __('project.Edit existing project') }} +

+
+ +
+
+ + +
+
+
+
+

+ {{ __('project.Select customer') }} +

+

+ {{ __("project.Select your customer") }} +

+
+ +
+ + +
+ +
+ +
+ +
+ +
+
+ +
+
+
+

+ {{ __('customer.Customer') }} +

+
+
+
+
+
+
+
+ + +
+
+
+
+

+ {{ __('project.Project data') }} +

+

+ {{ __("project.Enter your project data. Klick Save to store the project.") }} +

+
+
+ +
+

+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ {{ __('form.Save') }} +
+ +
+ +
+
+ +
+
+
+ + diff --git a/resources/views/projects/index.blade.php b/resources/views/projects/index.blade.php new file mode 100644 index 0000000..52e99ef --- /dev/null +++ b/resources/views/projects/index.blade.php @@ -0,0 +1,84 @@ + + +
+

+ {{ __('project.Projects') }} +

+
+
+ +
+
+
+
+
+
+

+ {{ __('project.Add new project') }} +

+ +

+ {{ __("project.Add new project by clicking add") }} +

+
+ {{ __('form.Add') }} +
+
+
+ +
+
+
+
+

+ {{ __('project.Existing projects') }} +

+
+ + +
{{ __('project.Project Number') }}
+
{{ __('customer.Customer') }}
+
{{ __('common.Name') }}
+
{{ __('project.Start date') }}
+
{{ __('project.End date') }}
+
+ + + +
+
+
+ +
+
+
+ + diff --git a/resources/views/projects/show.blade.php b/resources/views/projects/show.blade.php new file mode 100644 index 0000000..379d80e --- /dev/null +++ b/resources/views/projects/show.blade.php @@ -0,0 +1,69 @@ + + +

+ {{ __('project.Project') }} {{ $project->name }} ({{ $project->project_number }}) +

+
+ +
+
+ + +
+
+
+
+

+ {{ __('customer.Customer') }} +

+
+
{{ $project->customer->name }}
+
{{ $project->customer->email }}
+
+
+
+
+
+ + +
+
+
+
+

+ {{ __('project.Project data') }} +

+
+
+ +
{{ $project->name }}
+ + +
{{ $project->project_number }}
+ + +
{{ $project->description }}
+ + +
{{ $project->start }}
+ + +
{{ $project->end }}
+
+
+
+
+
+
+ +
+
+
+ {{ __('form.Edit') }} +
+
+
+ +
+
+
diff --git a/routes/api.php b/routes/api.php index 6d3f8c8..f289aec 100644 --- a/routes/api.php +++ b/routes/api.php @@ -10,6 +10,7 @@ use App\Http\Controllers\Api\InvoiceitemController; use App\Http\Controllers\Api\MailController; use App\Http\Controllers\Api\OptionController; use App\Http\Controllers\Api\PaymentController; +use App\Http\Controllers\Api\ProjectController; use App\Http\Controllers\Api\TaxrateController; use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; @@ -45,6 +46,7 @@ Route::group(['as' => 'api.'], function () { Route::get('/incoming-filter/{start}/{end}', [IncomingController::class, 'index'])->name('incoming.index'); Route::put('/incoming/{incoming}', [IncomingController::class, 'update'])->name('incoming.update'); Route::post('/incoming', [IncomingController::class, 'store'])->name('incoming.store'); + Route::apiResource('/project', ProjectController::class); }); diff --git a/routes/web.php b/routes/web.php index 053ece6..98a0002 100644 --- a/routes/web.php +++ b/routes/web.php @@ -9,6 +9,7 @@ use App\Http\Controllers\OptionController; use App\Http\Controllers\PaymentController; use App\Http\Controllers\PdfController; use App\Http\Controllers\ProfileController; +use App\Http\Controllers\ProjectController; use App\Http\Controllers\TaxrateController; use Illuminate\Support\Facades\Route; @@ -37,6 +38,7 @@ Route::middleware('auth')->group(function () { Route::get('/excel', function() { return view('excel'); })->name('excel'); Route::resource('/incoming', IncomingController::class)->only(['index', 'create', 'edit']); Route::get('/incoming-upload', [IncomingController::class, 'upload'])->name('incoming.upload'); + Route::resource('/project', ProjectController::class)->only(['index', 'create', 'show', 'edit']); }); require __DIR__.'/auth.php';