Add BO Coupon page
This commit is contained in:
parent
f8b8524438
commit
3923f2a89d
32 changed files with 1251 additions and 67 deletions
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Console;
|
||||
|
||||
use App\Jobs\CouponCanBeUsedUpdate;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
|
||||
|
|
@ -15,6 +16,7 @@ class Kernel extends ConsoleKernel
|
|||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
$schedule->job(CouponCanBeUsedUpdate::class)->everyMinute();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -18,4 +18,4 @@ enum CampaignTypes: int
|
|||
self::WALL->name => "Mur",
|
||||
self::BASKET->name => "Panier",
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ use Illuminate\Http\Request;
|
|||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
|
||||
class BrandController extends Controller
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
156
app/Http/Controllers/Bo/CouponController.php
Normal file
156
app/Http/Controllers/Bo/CouponController.php
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Coupons\StoreCouponRequest;
|
||||
use App\Http\Requests\Bo\Coupons\UpdateCouponRequest;
|
||||
use App\Models\Brand;
|
||||
use App\Models\Coupon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Traits\Controllers\UpdateModelStatus;
|
||||
|
||||
class CouponController extends Controller
|
||||
{
|
||||
use UpdateModelStatus;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $coupon */
|
||||
$coupon = Coupon::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$coupon,
|
||||
$request->search,
|
||||
null,
|
||||
'name',
|
||||
);
|
||||
}
|
||||
|
||||
$this->sortQuery($coupon);
|
||||
$searchFields = trans('Name');
|
||||
|
||||
$couponModels = $coupon->paginate(10);
|
||||
|
||||
return view('bo.pages.coupons.index', compact('couponModels', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$brandModels = Brand::orderBy('name', 'ASC')->get();
|
||||
|
||||
return view('bo.pages.coupons.create', compact('brandModels'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Coupons\StoreCouponRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreCouponRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$coupon = new Coupon();
|
||||
$coupon->fill($request->validated());
|
||||
|
||||
if ($coupon->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.coupons.edit', $coupon)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_created',
|
||||
['model' => Str::singular(trans('models.classes.coupons'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_created',
|
||||
['model' => Str::singular(trans('models.classes.coupons'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \App\Models\Coupon $coupon
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function edit(Coupon $coupon)
|
||||
{
|
||||
$brandModels = Brand::orderBy('name', 'ASC')->get();
|
||||
|
||||
return view('bo.pages.coupons.edit', [
|
||||
'couponModel' => $coupon,
|
||||
'brandModels' => $brandModels
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Coupons\UpdateCouponRequest $request
|
||||
* @param \App\Models\Coupon $coupon
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateCouponRequest $request, Coupon $coupon)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $coupon) {
|
||||
$coupon->fill($request->validated());
|
||||
if ($coupon->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.coupons.edit', $coupon)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_updated',
|
||||
['model' => Str::singular(trans('models.classes.coupons'))]
|
||||
));
|
||||
} //end if
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_updated',
|
||||
['model' => Str::singular(trans('models.classes.coupons'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Coupon $coupon
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Coupon $coupon)
|
||||
{
|
||||
if ($coupon->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.coupons.index')
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_deleted',
|
||||
['model' => Str::singular(trans('models.classes.coupons'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':crud.messages.cannot_be_deleted',
|
||||
['model' => Str::singular(trans('models.classes.coupons'))]
|
||||
));
|
||||
}
|
||||
}
|
||||
67
app/Http/Requests/Bo/Coupons/StoreCouponRequest.php
Normal file
67
app/Http/Requests/Bo/Coupons/StoreCouponRequest.php
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Coupons;
|
||||
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreCouponRequest extends FormRequest
|
||||
{
|
||||
use HasPicture;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth('backend')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
{
|
||||
$this->mergePicture('decoration');
|
||||
$this->mergePicture('gs1');
|
||||
$this->mergePicture('website_picture');
|
||||
$this->mergePicture('website_picture_mobile');
|
||||
$this->merge([
|
||||
'status' => $this->status ? true : false
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'name' => 'required|string|min:3|max:255',
|
||||
'status' => 'required|boolean',
|
||||
'brand_id' => 'required|exists:brands,id',
|
||||
'process_code' => 'required|string|min:3|max:255',
|
||||
'amount' => 'required|numeric|min:0.1|max:3',
|
||||
'valid_on' => 'required|string',
|
||||
'validity_period' => 'required|numeric|min:1|max:31',
|
||||
'legal_notices' => 'required|string',
|
||||
'limit_qty' => 'required|numeric|digits_between:1,3',
|
||||
'limit_period' => 'required|numeric|digits_between:1,3',
|
||||
'start_diffusion_date' => 'nullable|date|before:end_diffusion_date',
|
||||
'end_diffusion_date' => 'nullable|date|after:start_diffusion_date'
|
||||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
$this->pictureRules('decoration', 280, 160, 280, 160, false),
|
||||
$this->pictureRules('gs1', 628, 360, 628, 360, true),
|
||||
$this->pictureRules('website_picture', 580, 190, 580, 1900, true),
|
||||
$this->pictureRules('website_picture_mobile', 570, 560, 570, 560, true),
|
||||
);
|
||||
}
|
||||
}
|
||||
7
app/Http/Requests/Bo/Coupons/UpdateCouponRequest.php
Normal file
7
app/Http/Requests/Bo/Coupons/UpdateCouponRequest.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Coupons;
|
||||
|
||||
class UpdateCouponRequest extends StoreCouponRequest
|
||||
{
|
||||
}
|
||||
24
app/Jobs/CouponCanBeUsedUpdate.php
Normal file
24
app/Jobs/CouponCanBeUsedUpdate.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\Coupon;
|
||||
|
||||
/**
|
||||
* Update can_be_used of the coupon.
|
||||
*/
|
||||
class CouponCanBeUsedUpdate
|
||||
{
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
foreach (Coupon::all() as $coupon) {
|
||||
$coupon->can_be_used = $coupon->checkIfCanBeUsed();
|
||||
$coupon->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ class Basket extends Model
|
|||
'campaign_id'
|
||||
];
|
||||
|
||||
public function content() : HasMany
|
||||
public function content(): HasMany
|
||||
{
|
||||
return $this->hasMany(BasketsContent::class);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ class BasketsContent extends Model
|
|||
{
|
||||
use HasFactory;
|
||||
|
||||
public function basket() : BelongsTo
|
||||
public function basket(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Basket::class);
|
||||
}
|
||||
|
||||
public function coupon() : BelongsTo
|
||||
public function coupon(): BelongsTo
|
||||
{
|
||||
return $this->BelongsTo(Coupon::class);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,17 +2,87 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
||||
/**
|
||||
* @property integer $id Model id.
|
||||
* @property integer $brand_id ID de la marque sur laquelle le coupon s'applique.
|
||||
* @property string $name Nom du coupon.
|
||||
* @property string $process_code Code de traitement.
|
||||
* @property double $amount Montant de la réduction - Max 3 euros.
|
||||
* @property string $valid_on Texte réduction valable sur.
|
||||
* @property integer $validity_period Période de validité en jours - default 30 j - max 1 mois.
|
||||
* @property string $legal_notices Mentions légales.
|
||||
* @property string $decoration Path de l'image de décoration
|
||||
* - 280x160px
|
||||
* - JPG.
|
||||
* @property string|null $gs1 Path de l'image GS1 pour coupon Benelux
|
||||
* - 628x360px
|
||||
* - JPG
|
||||
* @property string|null $website_picture Path de l'image a destination des sites internet
|
||||
* - 580x190px
|
||||
* - JPG/PNG
|
||||
* @property string|null $website_picture_mobile Path de l'image a destination des sites internet mobile
|
||||
* - 570x560px
|
||||
* - JPG/PNG
|
||||
* @property integer $limit_qty Limite de quantité d'impression / customer.
|
||||
* @property integer $limit_period Limite d'impression dans une periode (en jours) / customer.
|
||||
* @property integer $status Statut du coupon, Publié / Non Publié.
|
||||
* @property integer $can_be_used Statut d'utilisation du coupon, Utilisable / Non utilisable,
|
||||
* Modifié par calcul dans un Job en fonction des dates.
|
||||
* @property \Carbon\Carbon|null $start_diffusion_date Date de début de diffusion - diffusion immédiate si null.
|
||||
* @property \Carbon\Carbon|null $end_diffusion_date Date de fin de diffusion - diffusion sans fin si null.
|
||||
* @property \Carbon\Carbon|null $end_validity_date Date de fin de validité
|
||||
* - diffusion immédiate si null
|
||||
* - required si end_diffusion_date est set et date
|
||||
* au minimum egale à end_diffusion_date + validity_period jours.
|
||||
* @package App\Models
|
||||
*/
|
||||
class Coupon extends Model
|
||||
{
|
||||
// FIXME : Ajouter les mouvement de quantité, mettre juste une colonne et se servir des logs avec un type pour mouvement ?
|
||||
// FIXME / Ajouter logs impressions
|
||||
use HasFactory;
|
||||
|
||||
// FIXME : Ajouter les mouvement de quantité, mettre juste une colonne et se servir des logs avec un type pour mouvement ?
|
||||
// FIXME / Ajouter logs impressions.
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'status',
|
||||
'brand_id',
|
||||
'process_code',
|
||||
'amount',
|
||||
'valid_on',
|
||||
'validity_period',
|
||||
'legal_notices',
|
||||
'decoration',
|
||||
'gs1',
|
||||
'website_picture',
|
||||
'website_picture_mobile',
|
||||
'limit_qty',
|
||||
'limit_period',
|
||||
'start_diffusion_date',
|
||||
'end_diffusion_date',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that aren't mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $guarded = [
|
||||
'can_be_used',
|
||||
'end_validity_date',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
|
|
@ -22,38 +92,96 @@ class Coupon extends Model
|
|||
'start_diffusion_date' => 'date:Y-m-d',
|
||||
'end_diffusion_date' => 'date:Y-m-d',
|
||||
'end_validity_date' => 'date:Y-m-d',
|
||||
'status' => 'bool'
|
||||
];
|
||||
|
||||
public function campaigns() : BelongsToMany
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::creating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
});
|
||||
static::updated(function (self $model) {
|
||||
FileStorageHelper::removeOldFile($model, 'decoration');
|
||||
FileStorageHelper::removeOldFile($model, 'gs1');
|
||||
FileStorageHelper::removeOldFile($model, 'website_picture');
|
||||
FileStorageHelper::removeOldFile($model, 'website_picture_mobile');
|
||||
});
|
||||
static::deleted(function (self $model) {
|
||||
FileStorageHelper::removeFile($model, 'decoration');
|
||||
FileStorageHelper::removeFile($model, 'gs1');
|
||||
FileStorageHelper::removeFile($model, 'website_picture');
|
||||
FileStorageHelper::removeFile($model, 'website_picture_mobile');
|
||||
});
|
||||
}
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
* The campaigns that belong to the Coupon
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
*/
|
||||
public function campaigns(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Campaign::class);
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
* The "booted" method of the model.
|
||||
* Manage fields
|
||||
*
|
||||
* @param self $model
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted(): void
|
||||
private static function manageFields(self $model)
|
||||
{
|
||||
static::creating(function (Coupon $coupon) {
|
||||
$coupon->can_be_used = $this->checkIfCanBeUsed();
|
||||
});
|
||||
static::updating(function (Coupon $coupon) {
|
||||
$coupon->can_be_used = $this->checkIfCanBeUsed();
|
||||
});
|
||||
$model->decoration = FileStorageHelper::storeFile($model, $model->decoration, true);
|
||||
$model->gs1 = FileStorageHelper::storeFile($model, $model->gs1, true);
|
||||
$model->website_picture = FileStorageHelper::storeFile($model, $model->website_picture, true);
|
||||
$model->website_picture_mobile = FileStorageHelper::storeFile($model, $model->website_picture_mobile, true);
|
||||
|
||||
if (is_null($model->start_diffusion_date)) {
|
||||
$model->start_diffusion_date = Carbon::now();
|
||||
}
|
||||
if (isset($model->end_diffusion_date)) {
|
||||
$model->end_validity_date = $model->end_diffusion_date->addDays($model->validity_period);
|
||||
} else {
|
||||
$model->end_validity_date = Carbon::now()->addDays($model->validity_period);
|
||||
}
|
||||
// Last action is to test if model can be used.
|
||||
$model->can_be_used = $model->checkIfCanBeUsed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get can be used
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function checkIfCanBeUsed()
|
||||
{
|
||||
if (
|
||||
(is_null($this->start_diffusion_date) or $this->start_diffusion_date->lessThanOrEqualTo(Carbon::now())) and
|
||||
(is_null($this->end_diffusion_date) or $this->end_diffusion_date->greaterThanOrEqualTo(Carbon::now())) and
|
||||
(is_null($this->end_validity_date) or $this->end_validity_date->greaterThanOrEqualTo(Carbon::now()->addDays($this->validity_period)))
|
||||
){
|
||||
(!is_null($this->start_diffusion_date) and
|
||||
$this->start_diffusion_date->lessThanOrEqualTo(Carbon::now())
|
||||
) and
|
||||
(!is_null($this->end_diffusion_date) and
|
||||
$this->end_diffusion_date->greaterThanOrEqualTo(Carbon::now())
|
||||
) and
|
||||
(!is_null($this->end_validity_date) and
|
||||
$this->end_validity_date->greaterThanOrEqualTo(Carbon::now()->addDays($this->validity_period)))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME : Ajouter calendrier de diffusion et le prendre en compte dans la condition
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Providers;
|
||||
|
||||
use App\Models\Campaign;
|
||||
use App\Models\Coupon;
|
||||
use Illuminate\Cache\RateLimiting\Limit;
|
||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||
use Illuminate\Http\Request;
|
||||
|
|
@ -42,6 +43,7 @@ class RouteServiceProvider extends ServiceProvider
|
|||
});
|
||||
|
||||
Route::model('campaign', Campaign::class);
|
||||
Route::model('coupon', Coupon::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
60
database/factories/CouponFactory.php
Normal file
60
database/factories/CouponFactory.php
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use App\Models\Coupon;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Coupon>
|
||||
*/
|
||||
class CouponFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = Coupon::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
$coupon = new Coupon();
|
||||
|
||||
// Create a carbon instance date.
|
||||
$start_diffusion_date = Carbon::parse(fake()->date());
|
||||
|
||||
// Add random days to start diffusion date.
|
||||
$end_diffusion_date = Carbon::parse($start_diffusion_date)->addDays(fake()->numberBetween(30, 365));
|
||||
|
||||
// Add random days to end diddusion date.
|
||||
$end_validity_date = Carbon::parse($end_diffusion_date)->addDays(fake()->numberBetween(1, 30));
|
||||
|
||||
// Get a brand in DB to have is name and id.
|
||||
$random_brand = fake()->randomElement(DB::table('brands')->get());
|
||||
|
||||
return [
|
||||
'name' => fake()->unique()->word(),
|
||||
'process_code' => fake()->unique()->bothify('?????-#####'),
|
||||
'amount' => fake()->randomFloat(1, 0.1, 3),
|
||||
'valid_on' => $random_brand->name,
|
||||
'validity_period' => fake()->numberBetween(1, 30),
|
||||
'legal_notices' => fake()->text(100),
|
||||
'limit_qty' => fake()->numberBetween(0, 2),
|
||||
'limit_period' => fake()->numberBetween(0, 30),
|
||||
'status' => fake()->boolean(75),
|
||||
'can_be_used' => $coupon->checkIfCanBeUsed(),
|
||||
'start_diffusion_date' => fake()->boolean(75) ? $start_diffusion_date : null,
|
||||
'end_diffusion_date' => fake()->boolean(75) ? $end_diffusion_date : null,
|
||||
'end_validity_date' => fake()->boolean(75) ? $end_validity_date : null,
|
||||
'brand_id' => $random_brand->id
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ return new class extends Migration
|
|||
$table->string('process_code')->unique()->comment("Code de traitement");
|
||||
$table->float('amount')->comment("Montant de la réduction - Max 3 euros");
|
||||
$table->text('valid_on')->comment("Texte réduction valable sur ...");
|
||||
$table->unsignedInteger('validity_period')->default(30)->comment("Période de validité en jours - default 30 j - max 1 mois");
|
||||
$table->unsignedSmallInteger('validity_period')->default(30)->comment("Période de validité en jours - default 30 j - max 1 mois");
|
||||
$table->text('legal_notices')->comment("Mentions légales");
|
||||
$table->string('decoration')->comment("Path de l'image de décoration - 280x160px - JPG");
|
||||
$table->string('gs1')->nullable()->comment("Path de l'image GS1 pour coupon Benelux - 628x360px - JPG");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('coupons', function (Blueprint $table) {
|
||||
$table->foreignId('brand_id')->after('id')->comment('ID de la marque sur laquelle le coupon s\'applique')->constrained();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('coupons', function (Blueprint $table) {
|
||||
//
|
||||
$table->dropForeign(['brand_id']);
|
||||
});
|
||||
}
|
||||
};
|
||||
34
database/seeders/CouponSeeder.php
Normal file
34
database/seeders/CouponSeeder.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use App\Models\Coupon;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class CouponSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
Coupon::factory(25)->make()->each(function (Coupon $coupon) {
|
||||
$coupon->decoration = FileStorageHelper::storeFile($coupon, new \SplFileInfo(\resource_path(
|
||||
'../resources/assets/images/coupon/decoration.jpg'
|
||||
)));
|
||||
$coupon->gs1 = FileStorageHelper::storeFile($coupon, new \SplFileInfo(\resource_path(
|
||||
'../resources/assets/images/coupon/gs1.jpg'
|
||||
)));
|
||||
$coupon->website_picture = FileStorageHelper::storeFile($coupon, new \SplFileInfo(\resource_path(
|
||||
'../resources/assets/images/coupon/website_picture.jpg'
|
||||
)));
|
||||
$coupon->website_picture_mobile = FileStorageHelper::storeFile($coupon, new \SplFileInfo(\resource_path(
|
||||
'../resources/assets/images/coupon/website_picture_mobile.jpg'
|
||||
)));
|
||||
$coupon->saveOrFail();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,8 @@ class DatabaseSeeder extends Seeder
|
|||
{
|
||||
$this->call([
|
||||
BrandSeeder::class,
|
||||
CampaignSeeder::class
|
||||
CampaignSeeder::class,
|
||||
CouponSeeder::class
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
BIN
resources/assets/images/coupon/decoration.jpg
Normal file
BIN
resources/assets/images/coupon/decoration.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
BIN
resources/assets/images/coupon/gs1.jpg
Normal file
BIN
resources/assets/images/coupon/gs1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
BIN
resources/assets/images/coupon/website_picture.jpg
Normal file
BIN
resources/assets/images/coupon/website_picture.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
BIN
resources/assets/images/coupon/website_picture_mobile.jpg
Normal file
BIN
resources/assets/images/coupon/website_picture_mobile.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
|
|
@ -13,6 +13,7 @@ return [
|
|||
'storeregions' => 'Store Regions',
|
||||
'storetypes' => 'Store Types',
|
||||
'brands' => 'Brands',
|
||||
'campaigns' => 'Campaigns'
|
||||
'campaigns' => 'Campaigns',
|
||||
'coupons' => 'Coupons'
|
||||
]
|
||||
];
|
||||
|
|
|
|||
|
|
@ -119,15 +119,30 @@ return [
|
|||
"uuid" => "The :attribute must be a valid UUID.",
|
||||
"custom" => [],
|
||||
'attributes' => [
|
||||
'name' => 'Name',
|
||||
'contact_mail' => 'E-mail',
|
||||
'RCS' => 'RCS',
|
||||
'logo' => 'Logo',
|
||||
'crm_token' => 'CRM Token',
|
||||
'crm_password' => 'CRM Password',
|
||||
'type' => 'Type',
|
||||
'status' => 'Status',
|
||||
'brand_id' => 'Associated brand',
|
||||
'updated_at' => 'Updated at'
|
||||
'name' => 'Name',
|
||||
'contact_mail' => 'E-mail',
|
||||
'RCS' => 'RCS',
|
||||
'logo' => 'Logo',
|
||||
'crm_token' => 'CRM Token',
|
||||
'crm_password' => 'CRM Password',
|
||||
'type' => 'Type',
|
||||
'status' => 'Status',
|
||||
'brand_id' => 'Brand id',
|
||||
'updated_at' => 'Updated at',
|
||||
'process_code' => 'Process code',
|
||||
'amount' => 'Amount',
|
||||
'valid_on' => 'Valid on',
|
||||
'validity_period' => 'Validity period',
|
||||
'legal_notices' => 'Legal notices',
|
||||
'decoration' => 'Decoration',
|
||||
'gs1' => 'gs1',
|
||||
'website_picture' => 'Website picture',
|
||||
'website_picture_mobile' => 'Website picture mobile',
|
||||
'limit_qty' => 'Limit quantity',
|
||||
'limit_period' => 'Limit period',
|
||||
'can_be_used' => 'Can be used',
|
||||
'start_diffusion_date' => 'Start diffusion date',
|
||||
'end_diffusion_date' => 'End diffusion date',
|
||||
'end_validity_date' => 'End validity date'
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ return [
|
|||
'classes' => [
|
||||
'users' => 'Utilisateurs',
|
||||
'brands' => 'Marques',
|
||||
'campaigns' => 'Campagnes'
|
||||
'campaigns' => 'Campagnes',
|
||||
'coupons' => 'Coupons'
|
||||
]
|
||||
];
|
||||
|
|
|
|||
|
|
@ -119,15 +119,30 @@ return [
|
|||
'uuid' => 'Le champ :attribute doit être un UUID valide',
|
||||
'custom' => [],
|
||||
'attributes' => [
|
||||
'name' => 'Nom',
|
||||
'contact_mail' => 'E-mail',
|
||||
'rcs' => 'RCS',
|
||||
'logo' => 'Logo',
|
||||
'crm_token' => 'CRM Token',
|
||||
'crm_password' => 'Mot de passe CRM',
|
||||
'type' => 'Type',
|
||||
'status' => 'Status',
|
||||
'brand_id' => 'Marque associée',
|
||||
'updated_at' => 'Date de modification'
|
||||
'name' => 'Nom',
|
||||
'contact_mail' => 'E-mail',
|
||||
'rcs' => 'RCS',
|
||||
'logo' => 'Logo',
|
||||
'crm_token' => 'CRM Token',
|
||||
'crm_password' => 'Mot de passe CRM',
|
||||
'type' => 'Type',
|
||||
'status' => 'Status',
|
||||
'brand_id' => 'ID de la marque',
|
||||
'updated_at' => 'Date de modification',
|
||||
'process_code' => 'Code de processus',
|
||||
'amount' => 'Montant',
|
||||
'valid_on' => 'Valable sur',
|
||||
'validity_period' => 'Période de validité',
|
||||
'legal_notices' => 'Mentions légales',
|
||||
'decoration' => 'Décoration',
|
||||
'gs1' => 'gs1',
|
||||
'website_picture' => 'Photo pour site web',
|
||||
'website_picture_mobile' => 'Photo pour le site web mobile',
|
||||
'limit_qty' => 'Quantité limite',
|
||||
'limit_period' => 'Période limite',
|
||||
'can_be_used' => 'Peut être utilisé',
|
||||
'start_diffusion_date' => 'Date de début de diffusion',
|
||||
'end_diffusion_date' => 'Date de fin de diffusion',
|
||||
'end_validity_date' => 'Date de fin de validité'
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,22 +1,24 @@
|
|||
@auth('backend')
|
||||
<ul class="navbar-nav me-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @if (request()->routeIs('bo.dashboard')) active @endif" data-bs-toggle="tooltip" href="{{ route('bo.dashboard') }}"
|
||||
title="{{ __('Revenir à l\'accueil') }}">
|
||||
{{ __('Dashboard') }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @if (request()->routeIs('bo.brands.*')) active @endif" data-bs-toggle="tooltip" href="{{ route('bo.brands.index') }}"
|
||||
title="{{ __('Panneau des marques') }}">
|
||||
{{ __('Brands') }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @if (request()->routeIs('bo.campaigns.*')) active @endif" data-bs-toggle="tooltip"
|
||||
href="{{ route('bo.campaigns.index') }}" title="{{ __('Panneau des campagnes') }}">
|
||||
{{ __('Campaigns') }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@endauth
|
||||
<ul class="navbar-nav me-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @if (request()->routeIs('bo.dashboard')) active @endif" data-bs-toggle="tooltip" href="{{ route('bo.dashboard') }}" title="{{ __('Revenir à l\'accueil') }}">
|
||||
{{ __('Dashboard') }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @if (request()->routeIs('bo.brands.*')) active @endif" data-bs-toggle="tooltip" href="{{ route('bo.brands.index') }}" title="{{ __('Panneau des marques') }}">
|
||||
{{ __('Brands') }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @if (request()->routeIs('bo.campaigns.*')) active @endif" data-bs-toggle="tooltip" href="{{ route('bo.campaigns.index') }}" title="{{ __('Panneau des campagnes') }}">
|
||||
{{ __('Campaigns') }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @if (request()->routeIs('bo.coupons.*')) active @endif" data-bs-toggle="tooltip" href="{{ route('bo.coupons.index') }}" title="{{ __('Gestion des coupons') }}">
|
||||
{{ __('Coupons') }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@endauth
|
||||
41
resources/views/bo/pages/coupons/create.blade.php
Normal file
41
resources/views/bo/pages/coupons/create.blade.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
@extends('bo.layout')
|
||||
|
||||
@section('title', sprintf('%s - %s', Str::singular(__('models.classes.coupons')), Str::ucfirst(__('crud.actions.create'))))
|
||||
@section('description', __('Creation d\'un nouveau coupon.'))
|
||||
|
||||
@section('breadcrumb',
|
||||
request()->route()->getName())
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h1 class="col h2">
|
||||
<a class="btn btn-primary text-decoration-none m-0" data-bs="tooltip" data-bs-placement="top" data-bs-toggle="tooltip"
|
||||
href="{{ route('bo.coupons.index') }}"
|
||||
title="{{ __('Return to the :model list', ['model' => __('models.classes.coupons')]) }}">
|
||||
<i class="fa-solid fa-arrow-left"></i>
|
||||
</a>
|
||||
<span class="fw-bold">{{ Str::singular(__('models.classes.coupons')) }}</span> <small
|
||||
class="text-muted">{{ __('create') }}</small>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body bg-light">
|
||||
<form id="formSubmit" action="{{ route('bo.coupons.store') }}" method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
@include('bo.pages.coupons.form-inputs')
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<button class="btn btn-primary" data-bs-toggle="tooltip" type="submit"
|
||||
title="{{ __('Save :model', ['model' => Str::singular(__('models.classes.coupons'))]) }}">
|
||||
{{ __('crud.actions.save') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
43
resources/views/bo/pages/coupons/edit.blade.php
Normal file
43
resources/views/bo/pages/coupons/edit.blade.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
@extends('bo.layout', ['brParam' => $couponModel])
|
||||
|
||||
@section('title', sprintf('%s - %s %s', Str::singular(__('models.classes.coupons')), Str::ucfirst(__('crud.actions.edit')),
|
||||
$couponModel->name))
|
||||
@section('description', $couponModel->valid_on)
|
||||
|
||||
@section('breadcrumb',
|
||||
request()->route()->getName())
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h1 class="col h2">
|
||||
<a class="btn btn-primary text-decoration-none m-0" data-bs="tooltip" data-bs-placement="top" data-bs-toggle="tooltip"
|
||||
href="{{ route('bo.coupons.index') }}"
|
||||
title="{{ __('Return to the :model list', ['model' => __('models.classes.coupons')]) }}">
|
||||
<i class="fa-solid fa-arrow-left"></i>
|
||||
</a>
|
||||
<span class="fw-bold">{{ Str::singular(__('models.classes.coupons')) }}</span> <small
|
||||
class="text-muted">{{ __('crud.actions.edit') }}</small>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body bg-light">
|
||||
<form id="formSubmit" action="{{ route('bo.coupons.update', $couponModel->id) }}" method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
@include('bo.pages.coupons.form-inputs', ['model' => $couponModel])
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<button class="btn btn-primary" data-bs-toggle="tooltip" type="submit"
|
||||
title="{{ __('Save :model', ['model' => Str::singular(__('models.classes.coupons'))]) }}">
|
||||
{{ __('crud.actions.save') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
395
resources/views/bo/pages/coupons/form-inputs.blade.php
Normal file
395
resources/views/bo/pages/coupons/form-inputs.blade.php
Normal file
|
|
@ -0,0 +1,395 @@
|
|||
<div class="row">
|
||||
{{-- NAME --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('validation.attributes.name') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.varchar', [
|
||||
'id' => 'couponName',
|
||||
'label' => __('Nom du :model', ['model' => Str::singular(__('models.classes.coupons'))]),
|
||||
'hasWordCounter' => true,
|
||||
'name' => 'name',
|
||||
'required' => true,
|
||||
'model' => $couponModel ?? null,
|
||||
'helper' => __('validation.between.string', [
|
||||
'attribute' => __('Nom du :model', ['model' => Str::singular(__('models.classes.coupons'))]),
|
||||
'min' => 3,
|
||||
'max' => 255,
|
||||
]),
|
||||
'placeholder' => __('Nom du coupon'),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- BRAND_ID --}}
|
||||
<div class="col-12 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('validation.attributes.brand_id') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.bigint-foreign-id', [
|
||||
'id' => 'couponBrandId',
|
||||
'label' => __(':model associée', ['model' => Str::singular(trans('models.classes.brands'))]),
|
||||
'name' => 'brand_id',
|
||||
'size' => 5,
|
||||
'model' => $couponModel ?? null,
|
||||
'associatedModels' => $brandModels,
|
||||
'foreignLabel' => 'name',
|
||||
'helper' => __('Chose one :model among this list.', [
|
||||
'model' => Str::singular(trans('models.classes.brands')),
|
||||
]),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- PROCESS CODE --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('validation.attributes.process_code') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.varchar', [
|
||||
'id' => 'couponProcessCode',
|
||||
'label' => __('Code processus du :model', ['model' => Str::singular(__('models.classes.coupons'))]),
|
||||
'hasWordCounter' => true,
|
||||
'name' => 'process_code',
|
||||
'required' => true,
|
||||
'model' => $couponModel ?? null,
|
||||
'helper' => __('validation.between.string', [
|
||||
'attribute' => __('Code processus du :model', ['model' => Str::singular(__('models.classes.coupons'))]),
|
||||
'min' => 3,
|
||||
'max' => 255,
|
||||
]),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- AMOUNT --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('validation.attributes.amount') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.int-number', [
|
||||
'id' => 'couponAmount',
|
||||
'label' => __('Montant du :model', ['model' => Str::singular(__('models.classes.coupons'))]),
|
||||
'name' => 'amount',
|
||||
'step' => 0.1,
|
||||
'required' => true,
|
||||
'model' => $couponModel ?? null,
|
||||
'helper' => __('validation.between.numeric', [
|
||||
'attribute' => __('Montant du :model', ['model' => Str::singular(__('models.classes.coupons'))]),
|
||||
'min' => 0.1,
|
||||
'max' => 3,
|
||||
]),
|
||||
'placeholder' => __('Montant du coupon'),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- VALID ON --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('validation.attributes.valid_on') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.text-html', [
|
||||
'id' => 'couponValidOn',
|
||||
'label' => __(':model valable sur', ['model' => Str::singular(__('models.classes.coupons'))]),
|
||||
'name' => 'valid_on',
|
||||
'required' => true,
|
||||
'model' => $couponModel ?? null,
|
||||
'helper' => __('validation.gt.string', [
|
||||
'attribute' => __(':model valable sur', ['model' => Str::singular(__('models.classes.coupons'))]),
|
||||
'value' => 15,
|
||||
]),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- VALIDITY PERIOD --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('validation.attributes.validity_period') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.smallint-number', [
|
||||
'id' => 'couponValidityPeriod',
|
||||
'label' => __('Période de validité du :model', ['model' => Str::singular(__('models.classes.coupons'))]),
|
||||
'name' => 'validity_period',
|
||||
'required' => true,
|
||||
'model' => $couponModel ?? null,
|
||||
'helper' => __('validation.between.numeric', [
|
||||
'attribute' => __('Période de validité du :model', [
|
||||
'model' => Str::singular(__('models.classes.coupons')),
|
||||
]),
|
||||
'min' => 1,
|
||||
'max' => 30,
|
||||
]),
|
||||
'placeholder' => __('Période de validité du coupon'),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- LEGAL NOTICES --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('validation.attributes.legal_notices') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.text-html', [
|
||||
'id' => 'couponLegalNotices',
|
||||
'label' => __('Mentions légales du :model', ['model' => Str::singular(__('models.classes.coupons'))]),
|
||||
'name' => 'legal_notices',
|
||||
'required' => true,
|
||||
'model' => $couponModel ?? null,
|
||||
'helper' => __('validation.gt.string', [
|
||||
'attribute' => __('Mentions légales du :model', ['model' => Str::singular(__('models.classes.coupons'))]),
|
||||
'value' => 15,
|
||||
]),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- DECORATION --}}
|
||||
<div class="col-12 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('validation.attributes.decoration') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.varchar-picture', [
|
||||
'id' => 'couponDecoration',
|
||||
'name' => 'decoration',
|
||||
'width' => 280,
|
||||
'height' => 160,
|
||||
'required' => true,
|
||||
'model' => $couponModel ?? null,
|
||||
'helper' => __('crud.minicrud.dimensions_must_be', [
|
||||
'widthpx' => '280px',
|
||||
'heightpx' => '160px',
|
||||
]),
|
||||
'preview' => true,
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- GS1 --}}
|
||||
<div class="col-12 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('validation.attributes.gs1') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.varchar-picture', [
|
||||
'id' => 'couponGs1',
|
||||
'name' => 'gs1',
|
||||
'width' => 628,
|
||||
'height' => 360,
|
||||
'required' => true,
|
||||
'model' => $couponModel ?? null,
|
||||
'helper' => __('crud.minicrud.dimensions_must_be', [
|
||||
'widthpx' => '628px',
|
||||
'heightpx' => '360px',
|
||||
]),
|
||||
'required' => false,
|
||||
'preview' => true,
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- WEBSITE PICTURE --}}
|
||||
<div class="col-12 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('validation.attributes.website_picture') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.varchar-picture', [
|
||||
'id' => 'couponWebsitePicture',
|
||||
'name' => 'website_picture',
|
||||
'width' => 580,
|
||||
'height' => 190,
|
||||
'model' => $couponModel ?? null,
|
||||
'helper' => __('crud.minicrud.dimensions_must_be', [
|
||||
'widthpx' => '580px',
|
||||
'heightpx' => '190px',
|
||||
]),
|
||||
'required' => false,
|
||||
'preview' => true,
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- WEBSITE PICTURE MOBILE --}}
|
||||
<div class="col-12 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('validation.attributes.website_picture_mobile') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.varchar-picture', [
|
||||
'id' => 'couponWebsitePictureMobile',
|
||||
'name' => 'website_picture_mobile',
|
||||
'width' => 570,
|
||||
'height' => 560,
|
||||
'model' => $couponModel ?? null,
|
||||
'helper' => __('crud.minicrud.dimensions_must_be', [
|
||||
'widthpx' => '570px',
|
||||
'heightpx' => '560px',
|
||||
]),
|
||||
'required' => false,
|
||||
'preview' => true,
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- LIMITY QTY --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('validation.attributes.limit_qty') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.smallint-number', [
|
||||
'id' => 'couponLimitQty',
|
||||
'label' => __('Limite de quantité d\'impression du :model par clients', [
|
||||
'model' => Str::singular(__('models.classes.coupons')),
|
||||
]),
|
||||
'name' => 'limit_qty',
|
||||
'required' => true,
|
||||
'model' => $couponModel ?? null,
|
||||
'helper' => __('validation.between.numeric', [
|
||||
'attribute' => __('Limite de quantité d\'impression du :model par clients', [
|
||||
'model' => Str::singular(__('models.classes.coupons')),
|
||||
]),
|
||||
'min' => 1,
|
||||
'max' => 30,
|
||||
]),
|
||||
'placeholder' => __('Limite de quantité d\'impression du coupon par clients'),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- LIMITY PERIOD --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('validation.attributes.limit_period') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.smallint-number', [
|
||||
'id' => 'couponLimitPeriod',
|
||||
'label' => __('Limite d\'impression du :model dans une période (en jours)', [
|
||||
'model' => Str::singular(__('models.classes.coupons')),
|
||||
]),
|
||||
'name' => 'limit_period',
|
||||
'required' => true,
|
||||
'model' => $couponModel ?? null,
|
||||
'helper' => __('validation.between.numeric', [
|
||||
'attribute' => __('Limite d\'impression du :model dans une période (en jours)', [
|
||||
'model' => Str::singular(__('models.classes.coupons')),
|
||||
]),
|
||||
'min' => 1,
|
||||
'max' => 30,
|
||||
]),
|
||||
'placeholder' => __('Limite d\'impression du coupon dans une période (en jours)'),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- START DIFFUSION DATE --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('validation.attributes.start_diffusion_date') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.timestamp-date', [
|
||||
'id' => 'couponStartDiffusionDate',
|
||||
'label' => __('Date de début de diffusion du :model', [
|
||||
'model' => Str::singular(__('models.classes.coupons')),
|
||||
]),
|
||||
'name' => 'start_diffusion_date',
|
||||
'required' => false,
|
||||
'model' => $couponModel ?? null,
|
||||
'helper' => __('validation.date', [
|
||||
'attribute' => __('Date de début de diffusion du :model', [
|
||||
'model' => Str::singular(__('models.classes.coupons')),
|
||||
]),
|
||||
]),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
{{-- END DIFFUSION DATE --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('validation.attributes.end_diffusion_date') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.timestamp-date', [
|
||||
'id' => 'couponEndDiffusionDate',
|
||||
'label' => __('Date de fin de diffusion du :model', ['model' => Str::singular(__('models.classes.coupons'))]),
|
||||
'name' => 'end_diffusion_date',
|
||||
'required' => false,
|
||||
'model' => $couponModel ?? null,
|
||||
'helper' => __('validation.date', [
|
||||
'attribute' => __('Date de fin de diffusion du :model', [
|
||||
'model' => Str::singular(__('models.classes.coupons')),
|
||||
]),
|
||||
]),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- END VALIDITY DATE --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('validation.attributes.end_validity_date') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.timestamp-date', [
|
||||
'id' => 'couponEndDiffusionDate',
|
||||
'label' => __('Date de fin de validité du :model', ['model' => Str::singular(__('models.classes.coupons'))]),
|
||||
'name' => 'end_validity_date',
|
||||
'required' => false,
|
||||
'disabled' => true,
|
||||
'model' => $couponModel ?? null,
|
||||
'helper' => __('validation.date', [
|
||||
'attribute' => __('Date de fin de validité du :model', [
|
||||
'model' => Str::singular(__('models.classes.coupons')),
|
||||
]),
|
||||
]),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- STATUS --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('validation.attributes.status') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.tinyint-boolean', [
|
||||
'id' => 'couponStatus',
|
||||
'name' => 'status',
|
||||
'label' => __('crud.minicrud.visibility_label'),
|
||||
'helper' => __('crud.minicrud.visibility_helper'),
|
||||
'model' => $couponModel ?? null,
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
87
resources/views/bo/pages/coupons/index-list.blade.php
Normal file
87
resources/views/bo/pages/coupons/index-list.blade.php
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
<div class="table-responsive">
|
||||
<table class="fix-action m-0 table">
|
||||
<thead>
|
||||
@php
|
||||
$cols = [
|
||||
'name' => __('validation.attributes.name'),
|
||||
'brand_id' => __('validation.attributes.brand_id'),
|
||||
'status' => __('validation.attributes.status'),
|
||||
'process_code' => __('validation.attributes.process_code'),
|
||||
'amount' => __('validation.attributes.amount'),
|
||||
'valid_on' => __('validation.attributes.valid_on'),
|
||||
'validity_period' => __('validation.attributes.validity_period'),
|
||||
'legal_notices' => __('validation.attributes.legal_notices'),
|
||||
'decoration' => __('validation.attributes.decoration'),
|
||||
'gs1' => __('validation.attributes.gs1'),
|
||||
'website_picture' => __('validation.attributes.website_picture'),
|
||||
'website_picture_mobile' => __('validation.attributes.website_picture_mobile'),
|
||||
'limit_qty' => __('validation.attributes.limit_qty'),
|
||||
'limit_period' => __('validation.attributes.limit_period'),
|
||||
'can_be_used' => __('validation.attributes.can_be_used'),
|
||||
'start_diffusion_date' => __('validation.attributes.start_diffusion_date'),
|
||||
'end_diffusion_date' => __('validation.attributes.end_diffusion_date'),
|
||||
'end_validity_date' => __('validation.attributes.end_validity_date'),
|
||||
'updated_at' => __('validation.attributes.updated_at'),
|
||||
];
|
||||
@endphp
|
||||
@include('bo.modules.table-col-sorter', ['cols' => $cols, 'mobileHide' => ['status']])
|
||||
</thead>
|
||||
<tbody>
|
||||
@if ($couponModels->count())
|
||||
@foreach ($couponModels as $couponModel)
|
||||
<tr>
|
||||
<td class="align-middle">{{ $couponModel->name }}</td>
|
||||
<td class="text-center align-middle">{{ $couponModel->brand_id }}</td>
|
||||
@include('bo.modules.change-status', [
|
||||
'routeName' => 'coupons',
|
||||
'model' => $couponModel,
|
||||
])
|
||||
<td class="text-center align-middle">{{ $couponModel->process_code }}</td>
|
||||
<td class="text-center align-middle">{{ $couponModel->amount }}€</td>
|
||||
<td class="align-middle">{{ $couponModel->valid_on }}</td>
|
||||
<td class="text-center align-middle">{{ $couponModel->validity_period }} {{ __('jours') }}</td>
|
||||
<td class="align-middle">{{ $couponModel->legal_notices }}</td>
|
||||
<td class="align-middle">{{ $couponModel->decoration }}</td>
|
||||
<td class="align-middle">{{ $couponModel->gs1 }}</td>
|
||||
<td class="align-middle">{{ $couponModel->website_picture }}</td>
|
||||
<td class="align-middle">{{ $couponModel->website_picture_mobile }}</td>
|
||||
<td class="text-center align-middle">{{ $couponModel->limit_qty }}</td>
|
||||
<td class="text-center align-middle">{{ $couponModel->limit_period }} {{ __('jours') }}</td>
|
||||
<td class="text-center align-middle">{{ $couponModel->can_be_used }}</td>
|
||||
<td class="text-center align-middle">{{ $couponModel->start_diffusion_date }}</td>
|
||||
<td class="text-center align-middle">{{ $couponModel->end_diffusion_date }}</td>
|
||||
<td class="text-center align-middle">{{ $couponModel->end_validity_date }}</td>
|
||||
<td class="text-center align-middle">
|
||||
<span
|
||||
class="badge bg-warning text-dark text-wrap">{{ $couponModel->updated_at->formatLocalized('%d/%m/%Y à %H:%M') }}</span>
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
<form class="btn-group confirmDeleteJS" action="{{ route('bo.coupons.destroy', $couponModel->id) }}"
|
||||
method="POST" novalidate>
|
||||
<a class="btn btn-sm btn-primary" data-bs-toggle="tooltip"
|
||||
href="{{ route('bo.coupons.edit', $couponModel->id) }}"
|
||||
title="{{ __('crud.helpers.update_model', ['model' => Str::singular(__('models.classes.coupons'))]) }}">
|
||||
<i class="fa-solid fa-pencil"></i>
|
||||
</a>
|
||||
@method('DELETE')
|
||||
@csrf
|
||||
<div class="btn-group" role="group">
|
||||
<button class="btn btn-sm btn-danger" data-bs-toggle="tooltip"
|
||||
title="{{ __('crud.helpers.delete_model', ['model' => Str::singular(__('models.classes.coupons'))]) }}">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@else
|
||||
<tr>
|
||||
<td class="text-center" colspan="9">
|
||||
<span class="h3">{{ __('crud.helpers.no_results', ['model' => __('models.classes.coupons')]) }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
48
resources/views/bo/pages/coupons/index.blade.php
Normal file
48
resources/views/bo/pages/coupons/index.blade.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
@extends('bo.layout')
|
||||
|
||||
@section('title', __('crud.helpers.list_all', ['model' => __('models.classes.coupons')]))
|
||||
@section('description', __('crud.helpers.list_all', ['model' => __('models.classes.coupons')]))
|
||||
@section('breadcrumb', request()->route()->getName())
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h1 class="h2 d-inline"><span class="fw-bold">{{ __('models.classes.coupons') }}</span> <small class="text-muted">{{ Str::ucfirst(__('crud.helpers.list')) }}</small> </h1>
|
||||
</div>
|
||||
<div class="col-md-3 d-flex align-items-center">
|
||||
<div class="input-group justify-content-end">
|
||||
<a href="{{ route('bo.coupons.create') }}" class="btn btn-primary" title="{{ __('crud.helpers.create_model', ['model' => Str::singular(__('models.classes.coupons'))]) }}" data-bs-toggle="tooltip">
|
||||
<i class="fa-solid fa-plus"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@include('bo.modules.search-bar')
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12 col-md-6 p-0">
|
||||
{{ $couponModels->withQueryString()->onEachSide(1)->links() }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
@include('bo.pages.coupons.index-list')
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12 col-md-6 p-0">
|
||||
{{ $couponModels->withQueryString()->onEachSide(1)->links() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
19
resources/views/bo/partials/inputs/timestamp-date.blade.php
Normal file
19
resources/views/bo/partials/inputs/timestamp-date.blade.php
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<label for="{{ $id }}">
|
||||
<b>{{ $label }}</b>
|
||||
</label>
|
||||
{{-- blade-formatter-disable --}}
|
||||
<input
|
||||
aria-describedby="{{ "{$id}Help" }}"
|
||||
id="{{ $id }}"
|
||||
class="form-control"
|
||||
name="{{ $name }}"
|
||||
type="date"
|
||||
data-form-type="date"
|
||||
value="{{ old($name, ((isset($model) and $model->{$name}) ? ($model->{$name}->format('Y-m-d') ?? '') : '')) }}"
|
||||
@if(!empty($disabled)) disabled @endif>
|
||||
{{-- blade-formatter-enable --}}
|
||||
@include('modules.input-error', [
|
||||
'inputName' => $name,
|
||||
'helperId' => "{$id}Help",
|
||||
'helper' => $helper,
|
||||
])
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use App\Http\Controllers\Bo\BrandController;
|
||||
use App\Http\Controllers\Bo\CampaignController;
|
||||
use App\Http\Controllers\Bo\CouponController;
|
||||
use App\Http\Controllers\Bo\DashboardController;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
|
@ -25,9 +26,16 @@ Route::prefix('bo')->name('bo.')->group(
|
|||
|
||||
Route::middleware('auth:backend')->group(function () {
|
||||
Route::get('/', [DashboardController::class, 'index'])->name('dashboard');
|
||||
|
||||
// * BRANDS
|
||||
Route::resource('brands', BrandController::class)->except('show');
|
||||
|
||||
//* CAMPAIGNS
|
||||
// * COUPONS
|
||||
Route::resource('coupons', CouponController::class)->except('show');
|
||||
Route::post('/coupons/{coupon}/change-published', [CouponController::class, 'changePublished'])
|
||||
->name('coupons.change-published');
|
||||
|
||||
// * CAMPAIGNS
|
||||
Route::resource('campaigns', CampaignController::class)->except('show');
|
||||
Route::post('/campaigns/{campaign}/change-published', [CampaignController::class, 'changePublished'])
|
||||
->name('campaigns.change-published');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue