the promoseven group crm

This commit is contained in:
ghassan committed 2026-01-28 17:19:02 +03:00
commit 12e3a44046
88 files changed
+12923

No files matched your search

@@ -0,0 +1,66 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Campaign;
use App\Models\Guest;
use App\Models\Venue;
use App\Models\GuestVisit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class AdminController extends Controller
{
public function getKpis()
{
$today = now()->toDateString();
return response()->json([
'today_checkins' => GuestVisit::whereDate('visit_date', $today)->count(),
'active_members' => Guest::whereHas('visits', function($q) use ($today) {
$q->whereDate('visit_date', '>=', now()->subDays(30));
})->count(),
'total_guests' => Guest::count(),
'total_visits' => GuestVisit::count(),
'revenue_today' => GuestVisit::whereDate('visit_date', $today)->sum('spend_amount'),
]);
}
public function getCharts()
{
$visitsByVenue = GuestVisit::select('venues.name', DB::raw('count(*) as visits'))
->join('venues', 'guest_visits.venue_id', '=', 'venues.id')
->groupBy('venues.id', 'venues.name')
->get();
$tierDistribution = Guest::select('loyalty_tiers.name', DB::raw('count(*) as count'))
->join('loyalty_tiers', 'guests.tier_id', '=', 'loyalty_tiers.id')
->groupBy('loyalty_tiers.id', 'loyalty_tiers.name')
->get();
return response()->json([
'visits_by_venue' => $visitsByVenue,
'tier_distribution' => $tierDistribution,
]);
}
public function createCampaign(Request $request)
{
$request->validate([
'name' => 'required|string',
'segment_rules' => 'required|array',
'offer_text' => 'required|string',
'voucher_id' => 'required|exists:vouchers,id',
]);
$campaign = Campaign::create($request->all());
return response()->json($campaign, 201);
}
public function getVenues()
{
return response()->json(Venue::all());
}
}
@@ -0,0 +1,165 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Guest;
use App\Models\GuestVisit;
use App\Models\GuestTag;
use App\Models\GuestNote;
use App\Services\GuestSearch;
use App\Services\CrossSellEngine;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use SimpleSoftwareIO\QrCode\Facades\QrCode;
class GuestController extends Controller
{
protected $guestSearch;
protected $crossSellEngine;
public function __construct(GuestSearch $guestSearch, CrossSellEngine $crossSellEngine)
{
$this->guestSearch = $guestSearch;
$this->crossSellEngine = $crossSellEngine;
}
public function search(Request $request)
{
$query = $request->get('q');
if (!$query) {
return response()->json([]);
}
$guests = $this->guestSearch->search($query);
return response()->json($guests);
}
public function show($id)
{
$guest = Guest::with(['tier', 'visits.venue', 'tags', 'notes.staff'])->findOrFail($id);
return response()->json($guest);
}
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:255',
'phone' => 'required|string|max:20',
'venue_id' => 'required|exists:venues,id',
]);
if ($validator->fails()) {
return response()->json($validator->errors(), 422);
}
$guest = Guest::create([
'name' => $request->name,
'phone' => $request->phone,
'email' => $request->email,
'nationality' => $request->nationality,
'language' => $request->language,
'birthday' => $request->birthday,
'marketing_consent' => $request->marketing_consent ?? false,
]);
$guest->generateLoyaltyId();
// Create initial visit
GuestVisit::create([
'guest_id' => $guest->id,
'venue_id' => $request->venue_id,
'visit_date' => now(),
'visit_type' => 'registration',
]);
return response()->json($guest, 201);
}
public function checkin(Request $request, $id)
{
$validator = Validator::make($request->all(), [
'venue_id' => 'required|exists:venues,id',
'spend_amount' => 'numeric|min:0',
'visit_type' => 'required|in:stay,dining,bar,beach,pool,watersports',
'room_number' => 'nullable|string',
'notes' => 'nullable|string',
]);
if ($validator->fails()) {
return response()->json($validator->errors(), 422);
}
$visit = GuestVisit::create([
'guest_id' => $id,
'venue_id' => $request->venue_id,
'visit_date' => now(),
'spend_amount' => $request->spend_amount ?? 0,
'visit_type' => $request->visit_type,
'room_number' => $request->room_number,
'notes' => $request->notes,
]);
// Update lifetime spend
$guest = Guest::find($id);
$guest->lifetime_spend = $guest->visits()->sum('spend_amount');
$guest->save();
return response()->json($visit, 201);
}
public function getCrossSellSuggestions($id)
{
$suggestions = $this->crossSellEngine->getSuggestions($id);
return response()->json($suggestions);
}
public function addTags(Request $request, $id)
{
$validator = Validator::make($request->all(), [
'tags' => 'required|array',
'tags.*' => 'string',
]);
if ($validator->fails()) {
return response()->json($validator->errors(), 422);
}
foreach ($request->tags as $tagName) {
GuestTag::firstOrCreate([
'guest_id' => $id,
'tag_name' => $tagName,
]);
}
return response()->json(['message' => 'Tags added successfully']);
}
public function addNote(Request $request, $id)
{
$validator = Validator::make($request->all(), [
'note_text' => 'required|string',
]);
if ($validator->fails()) {
return response()->json($validator->errors(), 422);
}
$note = GuestNote::create([
'guest_id' => $id,
'note_text' => $request->note_text,
'staff_id' => auth()->id(),
]);
return response()->json($note, 201);
}
public function generateQrCode($id)
{
$guest = Guest::findOrFail($id);
$qrCode = QrCode::size(200)->generate($guest->loyalty_id);
return response($qrCode)->header('Content-Type', 'image/svg+xml');
}
}