T12: Depublikations-Checkout mit Tombstone (config-gated)
Kunden koennen eigene veroeffentlichte PMs kostenpflichtig aus der oeffentlichen Ansicht nehmen: Panel auf der PM-Detailseite (inkl. T1neu-Unternehmer-Checkbox und Doppelausweis netto/brutto), Stripe- Ad-hoc-Checkout wie Credit-Topups, Erfuellung im Webhook — die PM wechselt auf archived + depublished_at, die oeffentliche URL zeigt dauerhaft einen Tombstone (410 Gone, ohne Inhalte, mit ehrlichem Drittarchive-Hinweis). Doppelbuchungs-Bremse pro PM; Status-Log mit Quelle "depublication". Gate: ohne BILLING_DEPUBLICATION_PRICE_CENTS bleibt der Weg deaktiviert und /melden zeigt die neutrale Preisformulierung [EXTERN: Preis festlegen, O6]. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
2a9be7a9af
commit
198be381d6
16 changed files with 522 additions and 7 deletions
|
|
@ -121,6 +121,26 @@ class StripeCheckoutService
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stripe-Checkout für eine Depublikation (T12). Ad-hoc-Charge über den
|
||||
* konfigurierten Netto-Preis (wie Credit-Topups, keine Stripe-Price-ID);
|
||||
* der Webhook depubliziert die PM nach Zahlungseingang.
|
||||
*/
|
||||
public function forDepublication(User $user, SinglePurchase $purchase): Checkout
|
||||
{
|
||||
$this->syncTaxIdFromBillingAddress($user);
|
||||
|
||||
return $user->checkoutCharge(
|
||||
$purchase->price_cents,
|
||||
'Depublikation einer Pressemitteilung',
|
||||
1,
|
||||
[
|
||||
...$this->sessionOptions(),
|
||||
'metadata' => ['single_purchase_id' => (string) $purchase->id],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stripe-Checkout für eine Wallet-Aufladung. Ad-hoc-Charge über den
|
||||
* Netto-Paketpreis (Stripe Tax ergänzt die USt.); die `credit_topup_id`
|
||||
|
|
|
|||
|
|
@ -321,6 +321,25 @@ class PressReleaseService
|
|||
$this->logStatusChange($pressRelease, $previous, PressReleaseStatus::Archived, null, 'admin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Depublikation (T12): kostenpflichtige Entfernung aus der öffentlichen
|
||||
* Ansicht auf Wunsch des Absenders. Die PM wechselt auf "archived" und
|
||||
* erhält den Depublikations-Marker — die öffentliche Detail-URL zeigt
|
||||
* fortan einen Tombstone (410).
|
||||
*/
|
||||
public function depublish(PressRelease $pressRelease): void
|
||||
{
|
||||
$this->assertStatus($pressRelease, [PressReleaseStatus::Published]);
|
||||
|
||||
$previous = $pressRelease->status;
|
||||
|
||||
$pressRelease->update([
|
||||
'status' => PressReleaseStatus::Archived->value,
|
||||
'depublished_at' => now(),
|
||||
]);
|
||||
$this->logStatusChange($pressRelease, $previous, PressReleaseStatus::Archived, 'Depublikation auf Wunsch des Absenders (kostenpflichtige Serviceleistung)', 'depublication');
|
||||
}
|
||||
|
||||
public function changeStatusFromAdmin(PressRelease $pressRelease, PressReleaseStatus $status, ?string $reason = null): void
|
||||
{
|
||||
$previous = $pressRelease->status;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,21 @@ class ReleaseDetailPageData
|
|||
->first();
|
||||
|
||||
if (! $release) {
|
||||
// T12-Tombstone: depublizierte PMs (kostenpflichtige Entfernung
|
||||
// auf Wunsch des Absenders) melden 410 statt 404 — die URL gab
|
||||
// es, der Inhalt wurde bewusst entfernt.
|
||||
$depublished = PressRelease::query()
|
||||
->withoutGlobalScope(PortalScope::class)
|
||||
->forPortalValues($portalValues)
|
||||
->forLanguage($language)
|
||||
->whereNotNull('depublished_at')
|
||||
->where('slug', $slug)
|
||||
->exists();
|
||||
|
||||
if ($depublished) {
|
||||
return ['tombstone' => true];
|
||||
}
|
||||
|
||||
abort(404);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue