20-02-2026

This commit is contained in:
Kevin Adametz 2026-02-20 17:55:06 +01:00
parent a8b395e20d
commit a00c42e770
252 changed files with 28785 additions and 8907 deletions

View file

@ -1,8 +1,8 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateProductsTable extends Migration
{
@ -23,8 +23,7 @@ class CreateProductsTable extends Migration
$table->decimal('price', 8, 2)->nullable();
$table->decimal('price_ek', 8, 2)->nullable();
$table->decimal('tax', 5, 2)->nullable();
$table->decimal('price_old', 8, 2)->nullable(); //streichpreis
$table->decimal('price_old', 8, 2)->nullable(); // streichpreis
$table->unsignedInteger('points')->nullable()->default(0);
$table->unsignedInteger('weight')->nullable()->default(0);
@ -38,10 +37,10 @@ class CreateProductsTable extends Migration
$table->string('number')->nullable();
$table->string('ean')->nullable();
$table->unsignedInteger('wp_number')->nullable();
$table->string('icons')->nullable(); //as array cast
$table->string('icons')->nullable(); // as array cast
$table->text('description')->nullable();
@ -52,31 +51,28 @@ class CreateProductsTable extends Migration
$table->tinyInteger('pos')->unsigned()->nullable();
$table->boolean('active')->default(false);
$table->unsignedInteger('amount')->nullable(); //for shop
$table->unsignedInteger('amount')->nullable(); // for shop
$table->tinyInteger('show_at')->unsigned()->nullable()->default(0);
$table->string('show_on')->nullable();
$table->boolean('shipping_addon')->default(false);
$table->boolean('buying_restriction')->default(false);
$table->unsignedTinyInteger('buying_restriction_amount')->nullable();
$table->boolean('sponsor_buying_points')->default(false);
$table->unsignedTinyInteger('sponsor_buying_points_amount')->nullable();
$table->unsignedSmallInteger('sponsor_buying_points_amount')->nullable();
$table->string('identifier', 20)->nullable();
$table->string('action')->nullable();
//is an upgrade product, set this product id by payments API paid
// is an upgrade product, set this product id by payments API paid
$table->unsignedInteger('upgrade_to_id')->nullable();
$table->timestamps();
$table->softDeletes();
});
}

View file

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
/**
* Run the migrations.
*
* Fügt ein Sprachfeld für Benutzer hinzu, um deren bevorzugte Sprache
* für Rechnungen, Provisionsabrechnungen und Lieferscheine zu speichern.
*/
public function up(): void
{
Schema::table('user_accounts', function (Blueprint $table) {
$table->string('language', 5)->nullable()->default('de')->after('notice');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('user_accounts', function (Blueprint $table) {
$table->dropColumn('language');
});
}
};

View file

@ -0,0 +1,42 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* Ändert den Default von 'de' auf NULL, damit die App-Locale
* als Fallback verwendet wird wenn keine Sprache gesetzt ist.
*/
public function up(): void
{
// Default auf NULL ändern
Schema::table('user_accounts', function (Blueprint $table) {
$table->string('language', 5)->nullable()->default(null)->change();
});
// Alle bestehenden 'de' Werte auf NULL setzen,
// damit die App-Locale als Fallback greift
\DB::table('user_accounts')
->where('language', 'de')
->update(['language' => null]);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('user_accounts', function (Blueprint $table) {
$table->string('language', 5)->nullable()->default('de')->change();
});
\DB::table('user_accounts')
->whereNull('language')
->update(['language' => 'de']);
}
};

View file

@ -0,0 +1,60 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('datev_exports', function (Blueprint $table) {
$table->id();
// Abrechnungszeitraum
$table->date('period_from');
$table->date('period_to');
$table->unsignedTinyInteger('month');
$table->unsignedSmallInteger('year');
// Status: 0=draft, 1=generated, 2=downloaded, 3=locked
$table->unsignedTinyInteger('status')->default(0);
// DATEV Header-Daten
$table->string('berater_nr', 10)->nullable();
$table->string('mandant_nr', 10)->nullable();
// Statistik
$table->unsignedInteger('invoice_count')->default(0);
$table->unsignedInteger('credit_count')->default(0);
$table->unsignedInteger('cancellation_count')->default(0);
$table->decimal('total_revenue', 15, 2)->default(0);
$table->decimal('total_commissions', 15, 2)->default(0);
// Datei
$table->string('filename')->nullable();
$table->string('file_path')->nullable();
$table->string('file_hash', 64)->nullable();
// Admin der den Export erstellt hat
$table->unsignedBigInteger('created_by')->nullable();
// Validierungs-Zusammenfassung
$table->unsignedInteger('warning_count')->default(0);
$table->unsignedInteger('error_count')->default(0);
$table->json('validation_summary')->nullable();
$table->timestamps();
$table->softDeletes();
// Indices
$table->index(['month', 'year']);
$table->index('status');
});
}
public function down(): void
{
Schema::dropIfExists('datev_exports');
}
};

View file

@ -0,0 +1,56 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('datev_export_lines', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('datev_export_id');
$table->foreign('datev_export_id')
->references('id')
->on('datev_exports')
->onDelete('cascade');
// Quell-Referenz
$table->string('source_type', 30); // invoice, credit, cancellation
$table->unsignedBigInteger('source_id');
// Zeilennummer im CSV
$table->unsignedInteger('line_number')->default(0);
// DATEV-Buchungsfelder
$table->decimal('amount_gross', 13, 2); // Spalte A: Umsatz (Brutto)
$table->char('soll_haben', 1); // Spalte B: H oder S
$table->unsignedInteger('konto'); // Spalte G: Sachkonto
$table->unsignedInteger('gegenkonto'); // Spalte H: Gegenkonto
$table->unsignedSmallInteger('bu_schluessel'); // BU-Schlüssel (Steuerschlüssel)
$table->date('belegdatum'); // Spalte J: Belegdatum
$table->string('belegfeld1', 36); // Spalte K: Rechnungs-/Gutschriftsnummer
$table->string('buchungstext', 60); // Spalte N: Buchungstext (max 60 Zeichen DATEV)
// EU/USt Felder
$table->string('eu_ustid', 20)->nullable(); // Spalte AN: USt-ID
$table->char('eu_land', 2)->nullable(); // EU-Ländercode
// Fertig gerenderte CSV-Zeile (für exakte Reproduzierbarkeit)
$table->text('row_csv')->nullable();
$table->timestamps();
// Indices
$table->index(['datev_export_id', 'line_number']);
$table->index(['source_type', 'source_id']);
});
}
public function down(): void
{
Schema::dropIfExists('datev_export_lines');
}
};

View file

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('dhl_package_shipments', function (Blueprint $table) {
$table->timestamp('tracking_completed_at')->nullable()->after('last_tracked_at');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('dhl_package_shipments', function (Blueprint $table) {
$table->dropColumn('tracking_completed_at');
});
}
};

View file

@ -0,0 +1,62 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('user_abo_item_histories', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('user_abo_id');
$table->foreign('user_abo_id')
->references('id')
->on('user_abos')
->onDelete('cascade');
$table->unsignedInteger('user_abo_item_id')->nullable();
$table->unsignedInteger('product_id');
$table->foreign('product_id')
->references('id')
->on('products');
$table->string('action', 30);
$table->string('product_name', 255);
$table->string('product_number', 50)->nullable();
$table->decimal('unit_price', 10, 2);
$table->decimal('total_price', 10, 2);
$table->unsignedInteger('qty_before')->nullable();
$table->unsignedInteger('qty_after')->nullable();
$table->unsignedInteger('old_product_id')->nullable();
$table->string('old_product_name', 255)->nullable();
$table->unsignedTinyInteger('comp')->default(0);
$table->unsignedInteger('changed_by_user_id')->nullable();
$table->string('changed_by_name', 255)->nullable();
$table->string('channel', 30);
$table->uuid('batch_id')->nullable()->index();
$table->boolean('is_initial')->default(false);
$table->timestamps();
$table->index(['user_abo_id', 'created_at']);
$table->index(['user_abo_id', 'is_initial']);
});
}
public function down(): void
{
Schema::dropIfExists('user_abo_item_histories');
}
};

View file

@ -0,0 +1,63 @@
<?php
use App\Models\UserAbo;
use App\Models\UserAboItemHistory;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Str;
return new class extends Migration
{
public function up(): void
{
$userAbos = UserAbo::with('user_abo_items.product')
->where('status', '>', 0)
->get();
foreach ($userAbos as $userAbo) {
// Nur seeden wenn noch keine History existiert
if (UserAboItemHistory::where('user_abo_id', $userAbo->id)->exists()) {
continue;
}
$batchId = Str::uuid()->toString();
foreach ($userAbo->user_abo_items as $item) {
if (! $item->product) {
continue;
}
// is_for=me: Berater kauft netto mit UserFactor
// is_for=ot: Kunde kauft brutto
$isMe = $userAbo->is_for === 'me';
$unitPrice = (float) $item->product->getPriceWith($isMe, $isMe);
UserAboItemHistory::create([
'user_abo_id' => $userAbo->id,
'user_abo_item_id' => $item->id,
'product_id' => $item->product_id,
'action' => UserAboItemHistory::ACTION_INITIAL,
'product_name' => $item->product->getLang('name'),
'product_number' => $item->product->number ?? null,
'unit_price' => $unitPrice,
'total_price' => $unitPrice * $item->qty,
'qty_before' => null,
'qty_after' => $item->qty,
'comp' => $item->comp ?? 0,
'changed_by_user_id' => null,
'changed_by_name' => 'System (Migration)',
'channel' => UserAboItemHistory::CHANNEL_SYSTEM,
'batch_id' => $batchId,
'is_initial' => true,
'created_at' => $userAbo->created_at ?? now(),
'updated_at' => $userAbo->created_at ?? now(),
]);
}
}
}
public function down(): void
{
// Nur die durch Migration erstellten Einträge löschen
UserAboItemHistory::where('changed_by_name', 'System (Migration)')->delete();
}
};

View file

@ -0,0 +1,22 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('products', function (Blueprint $table) {
$table->boolean('free_shipping_consultant')->default(false)->after('no_free_shipping');
});
}
public function down(): void
{
Schema::table('products', function (Blueprint $table) {
$table->dropColumn('free_shipping_consultant');
});
}
};

View file

@ -0,0 +1,22 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('products', function (Blueprint $table) {
$table->boolean('is_membership_only')->default(false)->after('free_shipping_consultant');
});
}
public function down(): void
{
Schema::table('products', function (Blueprint $table) {
$table->dropColumn('is_membership_only');
});
}
};