First Commit
This commit is contained in:
@@ -0,0 +1,419 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\AffiliatesAdmin\Controllers;
|
||||
|
||||
use App\Controllers\BaseAdminController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Modules\AffiliatesAdmin\Models\Affiliate;
|
||||
use Modules\AffiliatesAdmin\Models\AffiliateCommission;
|
||||
use Modules\AffiliatesAdmin\Models\AffiliateBanner;
|
||||
use Modules\AffiliatesAdmin\Models\AffiliateClick;
|
||||
use Modules\Auth\Models\User;
|
||||
|
||||
class AffiliatesAdminController extends BaseAdminController
|
||||
{
|
||||
/**
|
||||
* Check if user has permission.
|
||||
*
|
||||
* @param string $permission
|
||||
* @return void
|
||||
*/
|
||||
protected function checkPermission(string $permission)
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
if (!$user || !$user->hasPermission($permission)) {
|
||||
$this->addFlash('error', 'Você não tem permissão para acessar esta área.');
|
||||
$this->redirect('admin/dashboard')->send();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the affiliates.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function index(Request $request): Response
|
||||
{
|
||||
$this->checkPermission('affiliatesadmin.view');
|
||||
$affiliates = Affiliate::all();
|
||||
return $this->renderAdminView('@affiliatesadmin/index.twig', ['affiliates' => $affiliates]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new affiliate.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function create(Request $request): Response
|
||||
{
|
||||
$this->checkPermission('affiliatesadmin.manage');
|
||||
return $this->renderAdminView('@affiliatesadmin/form.twig');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created affiliate in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function store(Request $request): Response
|
||||
{
|
||||
$this->checkPermission('affiliatesadmin.manage');
|
||||
$data = $request->request->all();
|
||||
|
||||
if (empty($data['affiliates_name']) || empty($data['affiliates_email'])) {
|
||||
$this->addFlash('error', __('affiliatesadmin.validation_name_email_required'));
|
||||
return $this->redirect('/admin/affiliatesadmin/create');
|
||||
}
|
||||
|
||||
if (!filter_var($data['affiliates_email'], FILTER_VALIDATE_EMAIL)) {
|
||||
$this->addFlash('error', __('affiliatesadmin.validation_invalid_email'));
|
||||
return $this->redirect('/admin/affiliatesadmin/create');
|
||||
}
|
||||
|
||||
if (Affiliate::where('affiliates_email', $data['affiliates_email'])->exists()) {
|
||||
$this->addFlash('error', __('affiliatesadmin.validation_email_exists'));
|
||||
return $this->redirect('/admin/affiliatesadmin/create');
|
||||
}
|
||||
|
||||
// Check if user already exists in the system
|
||||
$existingUser = User::where('users_email', $data['affiliates_email'])->first();
|
||||
|
||||
if (!$existingUser && empty($data['password'])) {
|
||||
$this->addFlash('error', 'A senha é obrigatória para criar um novo usuário no sistema.');
|
||||
return $this->redirect('/admin/affiliatesadmin/create');
|
||||
}
|
||||
|
||||
// Create the Affiliate record
|
||||
Affiliate::create($data);
|
||||
|
||||
if ($existingUser) {
|
||||
// Only change role if user is a standard 'user'
|
||||
// Prevent downgrading admins or super_admins
|
||||
if (in_array($existingUser->users_role, ['user', ''])) {
|
||||
$existingUser->users_role = 'member';
|
||||
$existingUser->save();
|
||||
$this->addFlash('success', __('affiliatesadmin.affiliate_created_successfully') . ' O usuário existente foi promovido para "member".');
|
||||
} else {
|
||||
$this->addFlash('success', __('affiliatesadmin.affiliate_created_successfully') . ' O usuário existente manteve seu nível de acesso privilegiado: ' . $existingUser->users_role);
|
||||
}
|
||||
} else {
|
||||
// Create a new System User
|
||||
$user = new User();
|
||||
$user->users_name = $data['affiliates_name'];
|
||||
$user->users_email = $data['affiliates_email'];
|
||||
$user->users_password = password_hash($data['password'], PASSWORD_DEFAULT);
|
||||
$user->users_role = 'member';
|
||||
$user->users_status = 'active';
|
||||
$user->save();
|
||||
$this->addFlash('success', __('affiliatesadmin.affiliate_created_successfully') . ' Um novo usuário com nível "member" foi criado.');
|
||||
}
|
||||
|
||||
return $this->redirect('/admin/affiliatesadmin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified affiliate.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function show(Request $request, int $id): Response
|
||||
{
|
||||
$this->checkPermission('affiliatesadmin.view');
|
||||
$affiliate = Affiliate::findOrFail($id);
|
||||
return $this->renderAdminView('@affiliatesadmin/show.twig', ['affiliate' => $affiliate]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified affiliate.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function edit(Request $request, int $id): Response
|
||||
{
|
||||
$this->checkPermission('affiliatesadmin.manage');
|
||||
$affiliate = Affiliate::findOrFail($id);
|
||||
return $this->renderAdminView('@affiliatesadmin/form.twig', ['affiliate' => $affiliate]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified affiliate in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function update(Request $request, int $id): Response
|
||||
{
|
||||
$this->checkPermission('affiliatesadmin.manage');
|
||||
$affiliate = Affiliate::findOrFail($id);
|
||||
$data = $request->request->all();
|
||||
|
||||
if (empty($data['affiliates_name']) || empty($data['affiliates_email'])) {
|
||||
$this->addFlash('error', __('affiliatesadmin.validation_name_email_required'));
|
||||
return $this->redirect('/admin/affiliatesadmin/' . $id . '/edit');
|
||||
}
|
||||
|
||||
if (!filter_var($data['affiliates_email'], FILTER_VALIDATE_EMAIL)) {
|
||||
$this->addFlash('error', __('affiliatesadmin.validation_invalid_email'));
|
||||
return $this->redirect('/admin/affiliatesadmin/' . $id . '/edit');
|
||||
}
|
||||
|
||||
if (Affiliate::where('affiliates_email', $data['affiliates_email'])->where('affiliates_id', '!=', $id)->exists()) {
|
||||
$this->addFlash('error', __('affiliatesadmin.validation_email_exists'));
|
||||
return $this->redirect('/admin/affiliatesadmin/' . $id . '/edit');
|
||||
}
|
||||
|
||||
$affiliate->update($data);
|
||||
$this->addFlash('success', __('affiliatesadmin.affiliate_updated_successfully'));
|
||||
return $this->redirect('/admin/affiliatesadmin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified affiliate from storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function destroy(Request $request, int $id): Response
|
||||
{
|
||||
$this->checkPermission('affiliatesadmin.manage');
|
||||
Affiliate::destroy($id);
|
||||
$this->addFlash('success', __('affiliatesadmin.affiliate_deleted_successfully'));
|
||||
return $this->redirect('/admin/affiliatesadmin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of commissions.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function commissions(Request $request): Response
|
||||
{
|
||||
$this->checkPermission('affiliatesadmin.view_commissions');
|
||||
$commissions = AffiliateCommission::all();
|
||||
return $this->renderAdminView('@affiliatesadmin/commissions.twig', ['commissions' => $commissions]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Approve a commission.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function approveCommission(Request $request, int $id): Response
|
||||
{
|
||||
$this->checkPermission('affiliatesadmin.manage_commissions');
|
||||
$commission = AffiliateCommission::findOrFail($id);
|
||||
$commission->affiliate_commissions_status = 'approved';
|
||||
$commission->save();
|
||||
$this->addFlash('success', __('affiliatesadmin.commission_approved_successfully'));
|
||||
return $this->redirect('/admin/affiliatesadmin/commissions');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reject a commission.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function rejectCommission(Request $request, int $id): Response
|
||||
{
|
||||
$this->checkPermission('affiliatesadmin.manage_commissions');
|
||||
$commission = AffiliateCommission::findOrFail($id);
|
||||
$commission->affiliate_commissions_status = 'rejected';
|
||||
$commission->save();
|
||||
$this->addFlash('success', __('affiliatesadmin.commission_rejected_successfully'));
|
||||
return $this->redirect('/admin/affiliatesadmin/commissions');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of banners.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function banners(Request $request): Response
|
||||
{
|
||||
$this->checkPermission('affiliatesadmin.view_banners');
|
||||
$banners = AffiliateBanner::all();
|
||||
return $this->renderAdminView('@affiliatesadmin/banners.twig', ['banners' => $banners]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new banner.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function createBanner(Request $request): Response
|
||||
{
|
||||
$this->checkPermission('affiliatesadmin.manage_banners');
|
||||
return $this->renderAdminView('@affiliatesadmin/banner-form.twig');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created banner in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function storeBanner(Request $request): Response
|
||||
{
|
||||
$this->checkPermission('affiliatesadmin.manage_banners');
|
||||
$data = $request->request->all();
|
||||
|
||||
if (empty($data['affiliate_banners_name']) || empty($data['affiliate_banners_target_url'])) {
|
||||
$this->addFlash('error', __('affiliatesadmin.validation_banner_fields_required'));
|
||||
return $this->redirect('/admin/affiliatesadmin/banners/create');
|
||||
}
|
||||
|
||||
if ($request->files->has('banner_file')) {
|
||||
$file = $request->files->get('banner_file');
|
||||
if ($file && $file->isValid()) {
|
||||
$data['affiliate_banners_image_url'] = $this->handleBannerUpload($file);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($data['affiliate_banners_image_url'])) {
|
||||
$this->addFlash('error', 'O arquivo de imagem do banner é obrigatório.');
|
||||
return $this->redirect('/admin/affiliatesadmin/banners/create');
|
||||
}
|
||||
|
||||
AffiliateBanner::create($data);
|
||||
$this->addFlash('success', __('affiliatesadmin.banner_created_successfully'));
|
||||
return $this->redirect('/admin/affiliatesadmin/banners');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified banner.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function editBanner(Request $request, int $id): Response
|
||||
{
|
||||
$banner = AffiliateBanner::findOrFail($id);
|
||||
return $this->renderAdminView('@affiliatesadmin/banner-form.twig', ['banner' => $banner]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified banner in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function updateBanner(Request $request, int $id): Response
|
||||
{
|
||||
$banner = AffiliateBanner::findOrFail($id);
|
||||
$data = $request->request->all();
|
||||
|
||||
if (empty($data['affiliate_banners_name']) || empty($data['affiliate_banners_target_url'])) {
|
||||
$this->addFlash('error', __('affiliatesadmin.validation_banner_fields_required'));
|
||||
return $this->redirect('/admin/affiliatesadmin/banners/' . $id . '/edit');
|
||||
}
|
||||
|
||||
if ($request->files->has('banner_file')) {
|
||||
$file = $request->files->get('banner_file');
|
||||
if ($file && $file->isValid()) {
|
||||
// Delete old file if exists
|
||||
if ($banner->affiliate_banners_image_url) {
|
||||
$oldPath = dirname(__DIR__, 4) . '/storage/uploads/affiliatesadmin/' . $banner->affiliate_banners_image_url;
|
||||
if (file_exists($oldPath) && is_file($oldPath)) {
|
||||
unlink($oldPath);
|
||||
}
|
||||
}
|
||||
$data['affiliate_banners_image_url'] = $this->handleBannerUpload($file);
|
||||
}
|
||||
}
|
||||
|
||||
$banner->update($data);
|
||||
$this->addFlash('success', __('affiliatesadmin.banner_updated_successfully'));
|
||||
return $this->redirect('/admin/affiliatesadmin/banners');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle banner image upload.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\File\UploadedFile $file
|
||||
* @return string|null
|
||||
*/
|
||||
private function handleBannerUpload($file): ?string
|
||||
{
|
||||
$uploadDir = dirname(__DIR__, 4) . '/storage/uploads/affiliatesadmin';
|
||||
if (!is_dir($uploadDir)) {
|
||||
if (!mkdir($uploadDir, 0777, true)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
$filename = uniqid('banner_') . '.' . $file->guessExtension();
|
||||
$file->move($uploadDir, $filename);
|
||||
|
||||
// Store ONLY the filename in the database
|
||||
// The view will prepend /storage/uploads/affiliatesadmin/
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified banner from storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function destroyBanner(Request $request, int $id): Response
|
||||
{
|
||||
$banner = AffiliateBanner::findOrFail($id);
|
||||
if ($banner->affiliate_banners_image_url) {
|
||||
$path = dirname(__DIR__, 4) . '/storage/uploads/affiliatesadmin/' . $banner->affiliate_banners_image_url;
|
||||
if (file_exists($path) && is_file($path)) {
|
||||
unlink($path);
|
||||
}
|
||||
}
|
||||
AffiliateBanner::destroy($id);
|
||||
$this->addFlash('success', __('affiliatesadmin.banner_deleted_successfully'));
|
||||
return $this->redirect('/admin/affiliatesadmin/banners');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display affiliate statistics.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function statistics(Request $request): Response
|
||||
{
|
||||
$this->checkPermission('affiliatesadmin.view_statistics');
|
||||
|
||||
$stats = [
|
||||
'total_affiliates' => Affiliate::count(),
|
||||
'total_commissions_approved' => AffiliateCommission::where('affiliate_commissions_status', 'approved')->sum('affiliate_commissions_amount'),
|
||||
'total_clicks' => AffiliateClick::count(),
|
||||
'conversion_rate' => 0,
|
||||
];
|
||||
|
||||
if ($stats['total_clicks'] > 0) {
|
||||
$approvedCount = AffiliateCommission::where('affiliate_commissions_status', 'approved')->count();
|
||||
$stats['conversion_rate'] = round(($approvedCount / $stats['total_clicks']) * 100, 2);
|
||||
}
|
||||
|
||||
return $this->renderAdminView('@affiliatesadmin/statistics.twig', [
|
||||
'stats' => $stats
|
||||
]);
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\AffiliatesAdmin\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Affiliate extends Model
|
||||
{
|
||||
protected $table = 'affiliates';
|
||||
|
||||
protected $primaryKey = 'affiliates_id';
|
||||
|
||||
protected $fillable = [
|
||||
'affiliates_code',
|
||||
'affiliates_name',
|
||||
'affiliates_email',
|
||||
'affiliates_phone',
|
||||
'affiliates_address',
|
||||
'affiliates_website',
|
||||
'affiliates_commission_rate',
|
||||
'affiliates_total_earned',
|
||||
'affiliates_total_paid',
|
||||
'affiliates_status',
|
||||
];
|
||||
|
||||
/**
|
||||
* The "booting" method of the model.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
// Ensure affiliates_code is generated before creating
|
||||
static::creating(function ($affiliate) {
|
||||
if (empty($affiliate->affiliates_code)) {
|
||||
$affiliate->affiliates_code = static::generateUniqueAffiliateCode();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique affiliate code.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function generateUniqueAffiliateCode(): string
|
||||
{
|
||||
$code = \Illuminate\Support\Str::random(10); // Using Laravel's Str helper
|
||||
while (static::where('affiliates_code', $code)->exists()) {
|
||||
$code = \Illuminate\Support\Str::random(10);
|
||||
}
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the commissions for the affiliate.
|
||||
*/
|
||||
public function commissions()
|
||||
{
|
||||
return $this->hasMany(AffiliateCommission::class, 'affiliate_commissions_affiliate_id', 'affiliates_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the banners created by the affiliate.
|
||||
*/
|
||||
public function banners()
|
||||
{
|
||||
return $this->hasMany(AffiliateBanner::class, 'affiliate_banners_affiliate_id', 'affiliates_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the clicks for the affiliate's banners.
|
||||
*/
|
||||
public function clicks()
|
||||
{
|
||||
return $this->hasMany(AffiliateClick::class, 'affiliate_clicks_affiliate_id', 'affiliates_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\AffiliatesAdmin\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class AffiliateBanner extends Model
|
||||
{
|
||||
protected $table = 'affiliate_banners';
|
||||
|
||||
protected $primaryKey = 'affiliate_banners_id';
|
||||
|
||||
protected $fillable = [
|
||||
'affiliate_banners_name',
|
||||
'affiliate_banners_description',
|
||||
'affiliate_banners_image_url',
|
||||
'affiliate_banners_target_url',
|
||||
'affiliate_banners_width',
|
||||
'affiliate_banners_height',
|
||||
'affiliate_banners_is_active',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the affiliate that owns the banner.
|
||||
*/
|
||||
public function affiliate()
|
||||
{
|
||||
return $this->belongsTo(Affiliate::class, 'affiliate_banners_affiliate_id', 'affiliates_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the clicks for the banner.
|
||||
*/
|
||||
public function clicks()
|
||||
{
|
||||
return $this->hasMany(AffiliateClick::class, 'affiliate_clicks_banner_id', 'affiliate_banners_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\AffiliatesAdmin\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class AffiliateClick extends Model
|
||||
{
|
||||
protected $table = 'affiliate_clicks';
|
||||
|
||||
protected $primaryKey = 'affiliate_clicks_id';
|
||||
|
||||
protected $fillable = [
|
||||
'affiliate_clicks_affiliate_id',
|
||||
'affiliate_clicks_banner_id',
|
||||
'affiliate_clicks_ip_address',
|
||||
'affiliate_clicks_user_agent',
|
||||
'affiliate_clicks_referrer',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the affiliate that generated the click.
|
||||
*/
|
||||
public function affiliate()
|
||||
{
|
||||
return $this->belongsTo(Affiliate::class, 'affiliate_clicks_affiliate_id', 'affiliates_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the banner that was clicked.
|
||||
*/
|
||||
public function banner()
|
||||
{
|
||||
return $this->belongsTo(AffiliateBanner::class, 'affiliate_clicks_banner_id', 'affiliate_banners_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\AffiliatesAdmin\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class AffiliateCommission extends Model
|
||||
{
|
||||
protected $table = 'affiliate_commissions';
|
||||
|
||||
protected $primaryKey = 'affiliate_commissions_id';
|
||||
|
||||
protected $fillable = [
|
||||
'affiliate_commissions_affiliate_id',
|
||||
'affiliate_commissions_order_id',
|
||||
'affiliate_commissions_amount',
|
||||
'affiliate_commissions_commission_rate',
|
||||
'affiliate_commissions_status',
|
||||
'affiliate_commissions_notes',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the affiliate that owns the commission.
|
||||
*/
|
||||
public function affiliate()
|
||||
{
|
||||
return $this->belongsTo(Affiliate::class, 'affiliate_commissions_affiliate_id', 'affiliates_id');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user