Statistik: Stornos mindern die richtige Punktekategorie
Ein Storno einer Shop-Bestellung wurde als Eigenpunkt gebucht und liess damit die Shop-Provisionsbasis ungemindert. Betroffen sind 7 Faelle aus April bis August 2026 (178,82 EUR Differenz in der Provisionsbasis, gegen user_businesses geprueft). Ursache: `status_turnover` beschreibt nur, wohin der UMSATZ gehoert. Die Punkte folgen einer anderen Regel — eine Gutschrift (Status 4) bucht ihre Punkte immer auf KP/TP, auch wenn ihr Umsatz dem Shop zugeordnet ist. Die Gegenbuchung kann diese Aufteilung ohne die Ursprungsart nicht spiegeln, deshalb haelt `storno_origin_status` sie jetzt auf der Stornozeile fest. NULL heisst "Altzeile ohne Angabe" und faellt auf das bisherige Verhalten zurueck — abgeschlossene Monate aendern sich dadurch nicht. Stornoregel (Kundenentscheidung): Ein Storno mindert nur den Monat der Ursprungsbestellung. Ist der Monat abgeschlossen, passiert nichts mehr, denn Abrechnung und Gutschriften stehen. Ein Minus in den neuen Monat mitzunehmen waere nicht nachvollziehbar. Fuer den Ausnahmefall gibt es den Settings-Schalter `storno-points-current-month`, standardmaessig aus. Ausserdem: Die persoenliche Monatsstatistik summierte Status 0 (nicht zugeordnet) und 3 (pending) mit, die gemeinsame Punkteauswertung nicht. Beide nutzen jetzt dieselbe Statusliste, und ein Storno mindert das Segment seiner Ursprungsbuchung statt pauschal in "Sonstige" zu laufen. Die Migration fuer `status_turnover` zieht nur das Schema auf den tatsaechlichen Stand nach (nullable statt NOT NULL) — auf Produktion faktisch wirkungslos, aber Neuinstallationen und die Testdatenbank haben damit dieselbe Semantik. Audit-Befunde A02, A06, A15, R01-R03. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
75c2790bd2
commit
1900860c74
10 changed files with 733 additions and 24 deletions
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
use App\Services\Backoffice\SalesVolumePoints;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Schema und Daten waren auseinandergelaufen: die Ursprungsmigration definiert
|
||||
* `user_sales_volumes.status_turnover` als NOT NULL mit Default 1, in der
|
||||
* Produktionsdatenbank ist die Spalte dagegen nullable ohne Default — rund
|
||||
* 44.000 Zeilen stehen dort auf NULL, weil der regulaere Bestellweg das Feld
|
||||
* nie setzt.
|
||||
*
|
||||
* Diese Migration zieht die Definition auf den tatsaechlichen Stand nach. Auf
|
||||
* Produktion ist sie damit faktisch wirkungslos; sie sorgt aber dafuer, dass
|
||||
* frische Installationen und die Testdatenbank dieselbe Semantik haben —
|
||||
* NULL heisst "Herkunft nicht gesetzt" und wird von der Punkteauswertung
|
||||
* ({@see SalesVolumePoints}) ausdruecklich so behandelt.
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('user_sales_volumes', function (Blueprint $table) {
|
||||
$table->unsignedTinyInteger('status_turnover')->nullable()->default(null)->change();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// Bewusst ohne Rueckbau: NOT NULL liesse sich nicht wiederherstellen,
|
||||
// solange die vorhandenen NULL-Zeilen existieren.
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Haelt auf einer Stornobuchung fest, welche Buchungsart storniert wurde.
|
||||
*
|
||||
* `status_turnover` allein reicht dafuer nicht: Es beschreibt nur, wohin der
|
||||
* UMSATZ gehoert. Die Punkte folgen einer anderen Regel — eine Gutschrift
|
||||
* (Status 4) bucht ihre Punkte immer auf KP/TP, auch wenn ihr Umsatz dem Shop
|
||||
* zugeordnet ist. Ohne die Ursprungsart kann die Gegenbuchung diese Aufteilung
|
||||
* nicht spiegeln.
|
||||
*
|
||||
* NULL bedeutet "Altzeile ohne Angabe"; die Auswertung faellt dort auf das
|
||||
* bisherige Verhalten zurueck, damit abgeschlossene Monate unveraendert bleiben.
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('user_sales_volumes', function (Blueprint $table) {
|
||||
if (! Schema::hasColumn('user_sales_volumes', 'storno_origin_status')) {
|
||||
$table->unsignedTinyInteger('storno_origin_status')->nullable()->after('status_turnover');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('user_sales_volumes', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('user_sales_volumes', 'storno_origin_status')) {
|
||||
$table->dropColumn('storno_origin_status');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue