Implement catalog CRUD overhaul, snapshot fallback activation, and billing/UX hardening
This commit is contained in:
@@ -8,7 +8,6 @@ use App\Http\Controllers\Api\V1\AdminSettingsController;
|
||||
use App\Http\Controllers\Api\V1\AdminSubscriptionController;
|
||||
use App\Http\Controllers\Api\V1\AdminAnalyticsController;
|
||||
use App\Http\Controllers\Api\V1\AdminWebhookController;
|
||||
use App\Http\Controllers\Api\V1\PaypalWebhookController;
|
||||
use App\Http\Controllers\Api\V1\ExtensionController;
|
||||
use App\Http\Controllers\Api\V1\UserController;
|
||||
use App\Http\Controllers\Api\V1\UserKeywordController;
|
||||
@@ -55,6 +54,7 @@ Route::prefix('v1')->group(function () {
|
||||
Route::get('/keywords', [UserKeywordController::class, 'index']);
|
||||
Route::post('/keywords', [UserKeywordController::class, 'store']);
|
||||
Route::put('/keywords/{id}', [UserKeywordController::class, 'update']);
|
||||
Route::put('/keywords/{id}/active', [UserKeywordController::class, 'toggleActive']);
|
||||
Route::delete('/keywords/{id}', [UserKeywordController::class, 'destroy']);
|
||||
Route::post('/keywords/import', [UserKeywordController::class, 'import']);
|
||||
Route::get('/keywords/export', [UserKeywordController::class, 'export']);
|
||||
@@ -76,7 +76,8 @@ Route::prefix('v1')->group(function () {
|
||||
Route::get('/admin/webhooks/{id}', [AdminWebhookController::class, 'show']);
|
||||
Route::post('/admin/webhooks/{id}/replay', [AdminWebhookController::class, 'replay']);
|
||||
|
||||
Route::post('/paypal/webhook', [PaypalWebhookController::class, 'handle']);
|
||||
// Keep /v1 alias for backward compatibility, but use the same canonical webhook handler.
|
||||
Route::post('/paypal/webhook', [PayPalController::class, 'webhook']);
|
||||
|
||||
Route::get('/health', [SystemController::class, 'health']);
|
||||
Route::get('/metrics-lite', [SystemController::class, 'metricsLite']);
|
||||
|
||||
@@ -6,6 +6,9 @@ use Illuminate\Support\Facades\Schedule;
|
||||
use App\Services\LiveSqlImportService;
|
||||
use App\Services\Billing\PaypalWebhookProcessor;
|
||||
use App\Services\Billing\PayPalPlanSyncService;
|
||||
use App\Models\Order;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Subscription;
|
||||
use App\Models\WebhookEvent;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use App\Mail\TestMailketing;
|
||||
@@ -99,3 +102,20 @@ Artisan::command('mailketing:test {email : Recipient email address}', function (
|
||||
return 1;
|
||||
}
|
||||
})->purpose('Send a Mailketing API test email');
|
||||
|
||||
Artisan::command('dewemoji:normalize-statuses', function () {
|
||||
$subs = Subscription::query()
|
||||
->where('status', 'cancelled')
|
||||
->update(['status' => 'canceled']);
|
||||
|
||||
$orders = Order::query()
|
||||
->where('status', 'cancelled')
|
||||
->update(['status' => 'canceled']);
|
||||
|
||||
$payments = Payment::query()
|
||||
->where('status', 'cancelled')
|
||||
->update(['status' => 'canceled']);
|
||||
|
||||
$this->info("Normalized statuses: subscriptions={$subs}, orders={$orders}, payments={$payments}");
|
||||
return 0;
|
||||
})->purpose('Normalize legacy cancelled status spelling to canceled');
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\Dashboard\AdminDashboardController;
|
||||
use App\Http\Controllers\Dashboard\AdminEmojiCatalogController;
|
||||
use App\Http\Controllers\Dashboard\UserDashboardController;
|
||||
use App\Http\Controllers\ProfileController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
@@ -12,6 +13,7 @@ Route::middleware('auth')->prefix('dashboard')->name('dashboard.')->group(functi
|
||||
Route::get('/keywords/search', [UserDashboardController::class, 'keywordSearch'])->name('keywords.search');
|
||||
Route::post('/keywords', [UserDashboardController::class, 'storeKeyword'])->name('keywords.store');
|
||||
Route::put('/keywords/{keyword}', [UserDashboardController::class, 'updateKeyword'])->name('keywords.update');
|
||||
Route::put('/keywords/{keyword}/active', [UserDashboardController::class, 'toggleKeywordActive'])->name('keywords.toggle_active');
|
||||
Route::delete('/keywords/{keyword}', [UserDashboardController::class, 'deleteKeyword'])->name('keywords.delete');
|
||||
Route::post('/keywords/import', [UserDashboardController::class, 'importKeywords'])->name('keywords.import');
|
||||
Route::get('/keywords/export', [UserDashboardController::class, 'exportKeywords'])->name('keywords.export');
|
||||
@@ -41,6 +43,16 @@ Route::middleware('auth')->prefix('dashboard')->name('dashboard.')->group(functi
|
||||
Route::post('/pricing/snapshot', [AdminDashboardController::class, 'createPricingSnapshot'])->name('pricing.snapshot');
|
||||
Route::post('/pricing/paypal-sync', [AdminDashboardController::class, 'syncPaypalPlans'])->name('pricing.paypal_sync');
|
||||
|
||||
Route::get('/catalog', [AdminEmojiCatalogController::class, 'index'])->name('catalog');
|
||||
Route::get('/catalog/create', [AdminEmojiCatalogController::class, 'create'])->name('catalog.create');
|
||||
Route::get('/catalog/{emojiId}/edit', [AdminEmojiCatalogController::class, 'edit'])->whereNumber('emojiId')->name('catalog.edit');
|
||||
Route::post('/catalog', [AdminEmojiCatalogController::class, 'store'])->name('catalog.store');
|
||||
Route::put('/catalog/{emojiId}', [AdminEmojiCatalogController::class, 'update'])->whereNumber('emojiId')->name('catalog.update');
|
||||
Route::delete('/catalog/{emojiId}', [AdminEmojiCatalogController::class, 'destroy'])->whereNumber('emojiId')->name('catalog.delete');
|
||||
Route::post('/catalog/import-json', [AdminEmojiCatalogController::class, 'importCurrentJson'])->name('catalog.import_json');
|
||||
Route::post('/catalog/publish', [AdminEmojiCatalogController::class, 'publish'])->name('catalog.publish');
|
||||
Route::post('/catalog/snapshots/activate', [AdminEmojiCatalogController::class, 'activateSnapshot'])->name('catalog.snapshot.activate');
|
||||
|
||||
Route::get('/webhooks', [AdminDashboardController::class, 'webhooks'])->name('webhooks');
|
||||
Route::post('/webhooks/{id}/replay', [AdminDashboardController::class, 'replayWebhook'])->name('webhooks.replay');
|
||||
Route::post('/webhooks/replay-failed', [AdminDashboardController::class, 'replayFailedWebhooks'])->name('webhooks.replay_failed');
|
||||
|
||||
@@ -4,6 +4,7 @@ use App\Http\Controllers\ProfileController;
|
||||
use App\Http\Controllers\Web\SiteController;
|
||||
use App\Http\Controllers\Billing\PayPalController;
|
||||
use App\Http\Controllers\Billing\PakasirController;
|
||||
use App\Http\Controllers\Billing\BillingPaymentController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('/', [SiteController::class, 'home'])->name('home');
|
||||
@@ -44,6 +45,9 @@ Route::middleware('auth')->group(function () {
|
||||
Route::post('/billing/pakasir/status', [PakasirController::class, 'paymentStatus'])
|
||||
->middleware('verified')
|
||||
->name('billing.pakasir.status');
|
||||
Route::post('/billing/payments/{payment}/resume', [BillingPaymentController::class, 'resume'])
|
||||
->middleware('verified')
|
||||
->name('billing.payments.resume');
|
||||
|
||||
Route::get('/dashboard/profile', [ProfileController::class, 'edit'])->name('profile.edit');
|
||||
Route::patch('/dashboard/profile', [ProfileController::class, 'update'])->name('profile.update');
|
||||
|
||||
Reference in New Issue
Block a user