Finish the coupon base.

This commit is contained in:
Ferks-FK 2023-05-18 19:51:10 +00:00 committed by IceToast
parent 490e11572d
commit 640468acbe
13 changed files with 626 additions and 81 deletions

View file

@ -0,0 +1,42 @@
<?php
namespace App\Console\Commands;
use App\Settings\CouponSettings;
use App\Models\Coupon;
use Carbon\Carbon;
use Illuminate\Console\Command;
class DeleteExpiredCoupons extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'coupons:delete';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Delete expired coupons from DB.';
/**
* Execute the console command.
*
* @return int
*/
public function handle(CouponSettings $couponSettings)
{
if ($couponSettings->delete_coupon_on_expires) {
$expired_coupons = Coupon::where('expires_at', '<=', Carbon::now(config('app.timezone')))->get();
foreach ($expired_coupons as $expired_coupon) {
$expired_coupon->delete();
}
}
}
}

View file

@ -16,6 +16,7 @@ class Kernel extends ConsoleKernel
protected $commands = [
Commands\ChargeCreditsCommand::class,
Commands\ChargeServers::class,
Commands\DeleteExpiredCoupons::class,
];
/**
@ -29,6 +30,7 @@ class Kernel extends ConsoleKernel
$schedule->command('servers:charge')->everyMinute();
$schedule->command('cp:versioncheck:get')->daily();
$schedule->command('payments:open:clear')->daily();
$schedule->command('coupons:delete')->daily();
//log cronjob activity
$schedule->call(function () {

View file

@ -0,0 +1,25 @@
<?php
namespace App\Events;
use App\Models\Coupon;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class CouponUsedEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public Coupon $coupon;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(Coupon $coupon)
{
$this->coupon = $coupon;
}
}

View file

@ -2,6 +2,7 @@
namespace App\Extensions\PaymentGateways\PayPal;
use App\Events\CouponUsedEvent;
use App\Helpers\AbstractExtension;
use App\Events\PaymentEvent;
use App\Events\UserUpdateCreditsEvent;
@ -56,6 +57,7 @@ class PayPalExtension extends AbstractExtension
// Partner Discount.
$price = $price - ($price * $discount / 100);
$price = number_format($price, 2);
// create a new payment
$payment = Payment::create([
@ -82,12 +84,12 @@ class PayPalExtension extends AbstractExtension
"reference_id" => uniqid(),
"description" => $shopProduct->display . ($discount ? (" (" . __('Discount') . " " . $discount . '%)') : ""),
"amount" => [
"value" => $shopProduct->getTotalPrice(),
"value" => $price,
'currency_code' => strtoupper($shopProduct->currency_code),
'breakdown' => [
'item_total' => [
'currency_code' => strtoupper($shopProduct->currency_code),
'value' => number_format($price, 2),
'value' => $price
],
'tax_total' => [
'currency_code' => strtoupper($shopProduct->currency_code),
@ -158,6 +160,8 @@ class PayPalExtension extends AbstractExtension
if ($coupon_code) {
$coupon = new Coupon;
$coupon->incrementUses($coupon_code);
event(new CouponUsedEvent($coupon));
}
event(new UserUpdateCreditsEvent($user));

View file

@ -4,6 +4,7 @@ namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Coupon;
use App\Settings\LocaleSettings;
use App\Traits\Coupon as CouponTrait;
use Illuminate\Http\Request;
use Carbon\Carbon;
@ -20,11 +21,13 @@ class CouponController extends Controller
*
* @return \Illuminate\Http\Response
*/
public function index()
public function index(LocaleSettings $localeSettings)
{
$this->checkPermission(self::READ_PERMISSION);
return view('admin.coupons.index');
return view('admin.coupons.index', [
'locale_datatables' => $localeSettings->datatables
]);
}
/**
@ -47,21 +50,12 @@ class CouponController extends Controller
*/
public function store(Request $request)
{
$coupon_code = $request->input('coupon_code');
$coupon_type = $request->input('coupon_type');
$coupon_value = $request->input('coupon_value');
$coupon_max_uses = $request->input('coupon_uses');
$coupon_datepicker = $request->input('datepicker');
$coupon_code = $request->input('code');
$random_codes_amount = $request->input('range_codes');
$rules = [
"coupon_type" => "required|string|in:percentage,amount",
"coupon_uses" => "required|integer|digits_between:1,100",
"coupon_value" => "required|numeric|between:0,100",
"datepicker" => "required|date|after:" . Carbon::now()->format(Coupon::formatDate())
];
$rules = $this->requestRules($request);
// If for some reason you pass both fields at once.
if ($coupon_code && $random_codes_amount) {
// If for some reason you pass both fields at once.
if ($coupon_code && $random_codes_amount) {
return redirect()->back()->with('error', __('Only one of the two code inputs must be provided.'))->withInput($request->all());
}
@ -69,12 +63,6 @@ class CouponController extends Controller
return redirect()->back()->with('error', __('At least one of the two code inputs must be provided.'))->withInput($request->all());
}
if ($coupon_code) {
$rules['coupon_code'] = 'required|string|min:4';
} elseif ($random_codes_amount) {
$rules['range_codes'] = 'required|integer|digits_between:1,100';
}
$request->validate($rules);
if (array_key_exists('range_codes', $rules)) {
@ -85,23 +73,17 @@ class CouponController extends Controller
foreach ($coupons as $coupon) {
$data[] = [
'code' => $coupon,
'type' => $coupon_type,
'value' => $coupon_value,
'max_uses' => $coupon_max_uses,
'expires_at' => $coupon_datepicker,
'type' => $request->input('type'),
'value' => $request->input('value'),
'max_uses' => $request->input('max_uses'),
'expires_at' => $request->input('expires_at'),
'created_at' => Carbon::now(), // Does not fill in by itself when using the 'insert' method.
'updated_at' => Carbon::now()
];
}
Coupon::insert($data);
} else {
Coupon::create([
'code' => $coupon_code,
'type' => $coupon_type,
'value' => $coupon_value,
'max_uses' => $coupon_max_uses,
'expires_at' => $coupon_datepicker,
]);
Coupon::create($request->except('_token'));
}
return redirect()->route('admin.coupons.index')->with('success', __("The coupon's was registered successfully."));
@ -126,7 +108,12 @@ class CouponController extends Controller
*/
public function edit(Coupon $coupon)
{
//
$this->checkPermission(self::WRITE_PERMISSION);
return view('admin.coupons.edit', [
'coupon' => $coupon,
'expired_at' => $coupon->expires_at ? Carbon::createFromTimestamp($coupon->expires_at) : null
]);
}
/**
@ -138,7 +125,23 @@ class CouponController extends Controller
*/
public function update(Request $request, Coupon $coupon)
{
//
$coupon_code = $request->input('code');
$random_codes_amount = $request->input('range_codes');
$rules = $this->requestRules($request);
// If for some reason you pass both fields at once.
if ($coupon_code && $random_codes_amount) {
return redirect()->back()->with('error', __('Only one of the two code inputs must be provided.'))->withInput($request->all());
}
if (!$coupon_code && !$random_codes_amount) {
return redirect()->back()->with('error', __('At least one of the two code inputs must be provided.'))->withInput($request->all());
}
$request->validate($rules);
$coupon->update($request->except('_token'));
return redirect()->route('admin.coupons.index')->with('success', __('coupon has been updated!'));
}
/**
@ -149,11 +152,87 @@ class CouponController extends Controller
*/
public function destroy(Coupon $coupon)
{
//
$this->checkPermission(self::WRITE_PERMISSION);
$coupon->delete();
return redirect()->back()->with('success', __('coupon has been removed!'));
}
private function requestRules(Request $request)
{
$coupon_code = $request->input('code');
$random_codes_amount = $request->input('range_codes');
$rules = [
"type" => "required|string|in:percentage,amount",
"max_uses" => "required|integer|digits_between:1,100",
"value" => "required|numeric|between:0,100",
"expires_at" => "nullable|date|after:" . Carbon::now()->format(Coupon::formatDate())
];
if ($coupon_code) {
$rules['code'] = "required|string|min:4";
} elseif ($random_codes_amount) {
$rules['range_codes'] = 'required|integer|digits_between:1,100';
}
return $rules;
}
public function redeem(Request $request)
{
return $this->validateCoupon($request->user(), $request->input('couponCode'), $request->input('productId'));
}
public function dataTable()
{
$query = Coupon::query();
return datatables($query)
->addColumn('actions', function(Coupon $coupon) {
return '
<a data-content="'.__('Edit').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.coupons.edit', $coupon->id).'" class="btn btn-sm btn-info mr-1"><i class="fas fa-pen"></i></a>
<form class="d-inline" onsubmit="return submitResult();" method="post" action="'.route('admin.coupons.destroy', $coupon->id).'">
'.csrf_field().'
'.method_field('DELETE').'
<button data-content="'.__('Delete').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm btn-danger mr-1"><i class="fas fa-trash"></i></button>
</form>
';
})
->addColumn('status', function(Coupon $coupon) {
$color = 'success';
$status = $coupon->getStatus();
if ($status != __('VALID')) {
$color = 'danger';
}
return '<span class="badge badge-'.$color.'">'.str_replace('_', ' ', $status).'</span>';
})
->editColumn('uses', function (Coupon $coupon) {
return "{$coupon->uses} / {$coupon->max_uses}";
})
->editColumn('value', function (Coupon $coupon) {
if ($coupon->type === 'percentage') {
return $coupon->value . "%";
}
return number_format($coupon->value, 2, '.', '');
})
->editColumn('expires_at', function (Coupon $coupon) {
if (!$coupon->expires_at) {
return __('Never');
}
return Carbon::createFromTimestamp($coupon->expires_at);
})
->editColumn('created_at', function(Coupon $coupon) {
return Carbon::createFromTimeString($coupon->created_at);
})
->editColumn('code', function (Coupon $coupon) {
return "<code>{$coupon->code}</code>";
})
->rawColumns(['actions', 'code', 'status'])
->make();
}
}

View file

@ -0,0 +1,47 @@
<?php
namespace App\Listeners;
use App\Events\CouponUsedEvent;
use App\Settings\CouponSettings;
use Carbon\Carbon;
class CouponUsed
{
private $delete_coupon_on_expires;
private $delete_coupon_on_uses_reached;
/**
* Create the event listener.
*
* @return void
*/
public function __construct(CouponSettings $couponSettings)
{
$this->delete_coupon_on_expires = $couponSettings->delete_coupon_on_expires;
$this->delete_coupon_on_uses_reached = $couponSettings->delete_coupon_on_uses_reached;
}
/**
* Handle the event.
*
* @param \App\Events\CouponUsedEvent $event
* @return void
*/
public function handle(CouponUsedEvent $event)
{
if ($this->delete_coupon_on_expires) {
if (!is_null($event->coupon->expired_at)) {
if ($event->coupon->expires_at <= Carbon::now()->timestamp) {
$event->coupon->delete();
}
}
}
if ($this->delete_coupon_on_uses_reached) {
if ($event->coupon->uses >= $event->coupon->max_uses) {
$event->coupon->delete();
}
}
}
}

View file

@ -4,6 +4,8 @@ namespace App\Providers;
use App\Events\PaymentEvent;
use App\Events\UserUpdateCreditsEvent;
use App\Events\CouponUsedEvent;
use App\Listeners\CouponUsed;
use App\Listeners\CreateInvoice;
use App\Listeners\UnsuspendServers;
use App\Listeners\UserPayment;
@ -31,6 +33,9 @@ class EventServiceProvider extends ServiceProvider
CreateInvoice::class,
UserPayment::class,
],
CouponUsedEvent::class => [
CouponUsed::class
],
SocialiteWasCalled::class => [
// ... other providers
'SocialiteProviders\\Discord\\DiscordExtendSocialite@handle',

View file

@ -7,6 +7,8 @@ use Spatie\LaravelSettings\Settings;
class CouponSettings extends Settings
{
public ?int $max_uses_per_user;
public ?bool $delete_coupon_on_expires;
public ?bool $delete_coupon_on_uses_reached;
public static function group(): string
{
@ -20,7 +22,9 @@ class CouponSettings extends Settings
public static function getValidations()
{
return [
'max_uses_per_user' => 'required|integer'
'max_uses_per_user' => 'required|integer',
'delete_coupon_on_expires' => 'required|boolean',
'delete_coupon_on_uses_reached' => 'required|boolean',
];
}
@ -36,7 +40,17 @@ class CouponSettings extends Settings
'max_uses_per_user' => [
'label' => 'Max Uses Per User',
'type' => 'number',
'description' => 'Maximum number of uses that a user can make of the same coupon.',
'description' => 'Maximum number of uses that a user can make of the same coupon.'
],
'delete_coupon_on_expires' => [
'label' => 'Delete Coupon On Expires',
'type' => 'boolean',
'description' => 'Automatically deletes the coupon if it expires.'
],
'delete_coupon_on_uses_reached' => [
'label' => 'Delete Coupon When Max Uses Reached',
'type' => 'boolean',
'description' => 'Delete a coupon as soon as its maximum usage is reached.'
]
];
}

View file

@ -7,10 +7,14 @@ return new class extends SettingsMigration
public function up(): void
{
$this->migrator->add('coupon.max_uses_per_user', 1);
$this->migrator->add('coupon.delete_coupon_on_expires', false);
$this->migrator->add('coupon.delete_coupon_on_uses_reached', false);
}
public function down(): void
{
$this->migrator->delete('coupon.max_uses_per_user');
$this->migrator->delete('coupon.delete_coupon_on_expires');
$this->migrator->delete('coupon.delete_coupon_on_uses_reached');
}
};

View file

@ -201,6 +201,7 @@ Route::middleware(['auth', 'checkSuspended'])->group(function () {
Route::resource('partners', PartnerController::class);
//coupons
Route::get('coupons/datatable', [CouponController::class, 'dataTable'])->name('coupons.datatable');
Route::post('coupons/redeem', [CouponController::class, 'redeem'])->name('coupon.redeem');
Route::resource('coupons', CouponController::class);

View file

@ -84,7 +84,7 @@
@enderror
</div>
<div id="coupon_code_element" class="form-group">
<label for="coupon_code">
<label for="code">
{{ __('Coupon Code') }}
<i
data-toggle="popover"
@ -95,13 +95,13 @@
</label>
<input
type="text"
id="coupon_code"
name="coupon_code"
id="code"
name="code"
placeholder="SUMMER"
class="form-control @error('coupon_code') is-invalid @enderror"
value="{{ old('coupon_code') }}"
class="form-control @error('code') is-invalid @enderror"
value="{{ old('code') }}"
>
@error('coupon_code')
@error('code')
<div class="text-danger">
{{ $message }}
</div>
@ -109,7 +109,7 @@
</div>
<div class="form-group">
<div class="custom-control mb-3 p-0">
<label for="coupon_type">
<label for="type">
{{ __('Coupon Type') }}
<i
data-toggle="popover"
@ -119,17 +119,17 @@
</i>
</label>
<select
name="coupon_type"
id="coupon_type"
class="custom-select @error('coupon_type') is_invalid @enderror"
name="type"
id="type"
class="custom-select @error('type') is_invalid @enderror"
style="width: 100%; cursor: pointer;"
autocomplete="off"
required
>
<option value="percentage" @if(old('coupon_type') == 'percentage') selected @endif>{{ __('Percentage') }}</option>
<option value="amount" @if(old('coupon_type') == 'amount') selected @endif>{{ __('Amount') }}</option>
<option value="percentage" @if(old('type') == 'percentage') selected @endif>{{ __('Percentage') }}</option>
<option value="amount" @if(old('type') == 'amount') selected @endif>{{ __('Amount') }}</option>
</select>
@error('coupon_type')
@error('type')
<div class="text-danger">
{{ $message }}
</div>
@ -138,7 +138,7 @@
</div>
<div class="form-group">
<div class="input-group d-flex flex-column">
<label for="coupon_value">
<label for="value">
{{ __('Coupon Value') }}
<i
data-toggle="popover"
@ -149,18 +149,18 @@
</label>
<div class="d-flex">
<input
name="coupon_value"
id="coupon_value"
name="value"
id="value"
type="number"
step="any"
min="1"
max="100"
class="form-control @error('coupon_value') is-invalid @enderror"
value="{{ old('coupon_value') }}"
class="form-control @error('value') is-invalid @enderror"
value="{{ old('value') }}"
>
<span id="input_percentage" class="input-group-text">%</span>
</div>
@error('coupon_value')
@error('value')
<div class="text-danger">
{{ $message }}
</div>
@ -168,7 +168,7 @@
</div>
</div>
<div class="form-group">
<label for="coupon_uses">
<label for="max_uses">
{{ __('Max uses') }}
<i
data-toggle="popover"
@ -178,43 +178,43 @@
</i>
</label>
<input
name="coupon_uses"
id="coupon_uses"
name="max_uses"
id="max_uses"
type="number"
step="any"
min="1"
max="100"
class="form-control @error('coupon_uses') is-invalid @enderror"
value="{{ old('coupon_uses') }}"
class="form-control @error('max_uses') is-invalid @enderror"
value="{{ old('max_uses') }}"
>
@error('coupon_uses')
@error('max_uses')
<div class="text-danger">
{{ $message }}
</div>
@enderror
</div>
<div class="d-flex flex-column input-group form-group date" id="datepicker" data-target-input="nearest">
<label for="datepicker">
<div class="d-flex flex-column input-group form-group date" id="expires_at" data-target-input="nearest">
<label for="expires_at">
{{ __('Expires at') }}
<i
data-toggle="popover"
data-trigger="hover"
data-content="{{__('The date when the coupon will expire.')}}"
data-content="{{__('The date when the coupon will expire (If no date is provided, the coupon never expires).')}}"
class="fas fa-info-circle">
</i>
</label>
<div class="d-flex">
<input
value="{{old('datepicker')}}"
name="datepicker"
value="{{ old('expires_at') }}"
name="expires_at"
placeholder="yyyy-mm-dd hh:mm:ss"
type="text"
class="form-control @error('datepicker') is-invalid @enderror datetimepicker-input"
data-target="#datepicker"
class="form-control @error('expires_at') is-invalid @enderror datetimepicker-input"
data-target="#expires_at"
/>
<div
class="input-group-append"
data-target="#datepicker"
data-target="#expires_at"
data-toggle="datetimepicker"
>
<div class="input-group-text">
@ -222,7 +222,7 @@
</div>
</div>
</div>
@error('datepicker')
@error('expires_at')
<div class="text-danger">
{{ $message }}
</div>
@ -244,7 +244,7 @@
<script>
$(document).ready(function() {
$('#datepicker').datetimepicker({
$('#expires_at').datetimepicker({
format: 'Y-MM-DD HH:mm:ss',
icons: {
time: 'far fa-clock',
@ -263,8 +263,8 @@
$('#coupon_code_element').prop('disabled', true).hide()
$('#range_codes_element').prop('disabled', false).show()
if ($('#coupon_code').val()) {
$('#coupon_code').prop('value', null)
if ($('#code').val()) {
$('#code').prop('value', null)
}
} else {
@ -277,7 +277,7 @@
}
})
$('#coupon_type').change(function() {
$('#type').change(function() {
if ($(this).val() == 'percentage') {
$('#input_percentage').prop('disabled', false).show()
} else {

View file

@ -0,0 +1,291 @@
@extends('layouts.main')
@section('content')
<!-- CONTENT HEADER -->
<section class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1>{{__('Coupon')}}</h1>
</div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item"><a href="{{route('home')}}">{{__('Dashboard')}}</a></li>
<li class="breadcrumb-item"><a href="{{route('admin.coupons.index')}}">{{__('Coupon')}}</a>
</li>
<li class="breadcrumb-item"><a class="text-muted"
href="{{route('admin.coupons.edit' , $coupon->id)}}">{{__('Edit')}}</a>
</li>
</ol>
</div>
</div>
</div>
</section>
<!-- END CONTENT HEADER -->
<!-- MAIN CONTENT -->
<section class="content">
<div class="container-fluid">
<div class="row">
<div class="col-lg-6">
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-money-check-alt mr-2"></i>{{__('Coupon details')}}
</h5>
</div>
<div class="card-body">
<form action="{{ route('admin.coupons.update', $coupon->id) }}" method="POST">
@csrf
@method('PATCH')
<div class="d-flex flex-row-reverse">
<div class="custom-control custom-switch">
<input
type="checkbox"
id="random_codes"
name="random_codes"
class="custom-control-input"
>
<label for="random_codes" class="custom-control-label">
{{ __('Random Codes') }}
<i
data-toggle="popover"
data-trigger="hover"
data-content="{{__('Replace the creation of a single code with several at once with a custom field.')}}"
class="fas fa-info-circle">
</i>
</label>
</div>
</div>
<div id="range_codes_element" style="display: none;" class="form-group">
<label for="range_codes">
{{ __('Range Codes') }}
<i
data-toggle="popover"
data-trigger="hover"
data-content="{{__('Generate a number of random codes.')}}"
class="fas fa-info-circle">
</i>
</label>
<input
type="number"
id="range_codes"
name="range_codes"
step="any"
min="1"
max="100"
class="form-control @error('range_codes') is-invalid @enderror"
>
@error('range_codes')
<div class="text-danger">
{{ $message }}
</div>
@enderror
</div>
<div id="coupon_code_element" class="form-group">
<label for="code">
{{ __('Coupon Code') }}
<i
data-toggle="popover"
data-trigger="hover"
data-content="{{__('The coupon code to be registered.')}}"
class="fas fa-info-circle">
</i>
</label>
<input
type="text"
id="code"
name="code"
placeholder="SUMMER"
class="form-control @error('code') is-invalid @enderror"
value="{{ $coupon->code }}"
>
@error('code')
<div class="text-danger">
{{ $message }}
</div>
@enderror
</div>
<div class="form-group">
<div class="custom-control mb-3 p-0">
<label for="type">
{{ __('Coupon Type') }}
<i
data-toggle="popover"
data-trigger="hover"
data-content="{{__('The way the coupon should discount.')}}"
class="fas fa-info-circle">
</i>
</label>
<select
name="type"
id="type"
class="custom-select @error('type') is_invalid @enderror"
style="width: 100%; cursor: pointer;"
autocomplete="off"
required
>
<option value="percentage" @if($coupon->type == 'percentage') selected @endif>{{ __('Percentage') }}</option>
<option value="amount" @if($coupon->type == 'amount') selected @endif>{{ __('Amount') }}</option>
</select>
@error('type')
<div class="text-danger">
{{ $message }}
</div>
@enderror
</div>
</div>
<div class="form-group">
<div class="input-group d-flex flex-column">
<label for="value">
{{ __('Coupon Value') }}
<i
data-toggle="popover"
data-trigger="hover"
data-content="{{__('The value that the coupon will represent.')}}"
class="fas fa-info-circle">
</i>
</label>
<div class="d-flex">
<input
name="value"
id="value"
type="number"
step="any"
min="1"
max="100"
class="form-control @error('value') is-invalid @enderror"
value="{{ $coupon->value }}"
>
<span id="input_percentage" class="input-group-text">%</span>
</div>
@error('value')
<div class="text-danger">
{{ $message }}
</div>
@enderror
</div>
</div>
<div class="form-group">
<label for="max_uses">
{{ __('Max uses') }}
<i
data-toggle="popover"
data-trigger="hover"
data-content="{{__('The maximum number of times the coupon can be used.')}}"
class="fas fa-info-circle">
</i>
</label>
<input
name="max_uses"
id="max_uses"
type="number"
step="any"
min="1"
max="100"
class="form-control @error('max_uses') is-invalid @enderror"
value="{{ $coupon->max_uses }}"
>
@error('max_uses')
<div class="text-danger">
{{ $message }}
</div>
@enderror
</div>
<div class="d-flex flex-column input-group form-group date" id="expires_at" data-target-input="nearest">
<label for="expires_at">
{{ __('Expires at') }}
<i
data-toggle="popover"
data-trigger="hover"
data-content="{{__('The date when the coupon will expire (If no date is provided, the coupon never expires).')}}"
class="fas fa-info-circle">
</i>
</label>
<div class="d-flex">
<input
value="{{ $expired_at ?? '' }}"
name="expires_at"
placeholder="yyyy-mm-dd hh:mm:ss"
type="text"
class="form-control @error('expires_at') is-invalid @enderror datetimepicker-input"
data-target="#expires_at"
/>
<div
class="input-group-append"
data-target="#expires_at"
data-toggle="datetimepicker"
>
<div class="input-group-text">
<i class="fa fa-calendar"></i>
</div>
</div>
</div>
@error('expires_at')
<div class="text-danger">
{{ $message }}
</div>
@enderror
</div>
<div class="form-group text-right mb-0">
<button type="submit" class="btn btn-primary">
{{__('Submit')}}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- END CONTENT -->
<script>
$(document).ready(function() {
$('#expires_at').datetimepicker({
format: 'Y-MM-DD HH:mm:ss',
icons: {
time: 'far fa-clock',
date: 'far fa-calendar',
up: 'fas fa-arrow-up',
down: 'fas fa-arrow-down',
previous: 'fas fa-chevron-left',
next: 'fas fa-chevron-right',
today: 'fas fa-calendar-check',
clear: 'far fa-trash-alt',
close: 'far fa-times-circle'
}
});
$('#random_codes').change(function() {
if ($(this).is(':checked')) {
$('#coupon_code_element').prop('disabled', true).hide()
$('#range_codes_element').prop('disabled', false).show()
if ($('#code').val()) {
$('#code').prop('value', null)
}
} else {
$('#coupon_code_element').prop('disabled', false).show()
$('#range_codes_element').prop('disabled', true).hide()
if ($('#range_codes').val()) {
$('#range_codes').prop('value', null)
}
}
})
$('#type').change(function() {
if ($(this).val() == 'percentage') {
$('#input_percentage').prop('disabled', false).show()
} else {
$('#input_percentage').prop('disabled', true).hide()
}
})
})
</script>
@endsection

View file

@ -42,10 +42,12 @@
<table id="datatable" class="table table-striped">
<thead>
<tr>
<th>{{__('Partner discount')}}</th>
<th>{{__('Registered user discount')}}</th>
<th>{{__('Referral system commission')}}</th>
<th>{{__('Created')}}</th>
<th>{{__('Status')}}</th>
<th>{{__('Code')}}</th>
<th>{{__('Value')}}</th>
<th>{{__('Used / Max Uses')}}</th>
<th>{{__('Expires')}}</th>
<th>{{__('Created At')}}</th>
<th>{{__('Actions')}}</th>
</tr>
</thead>
@ -62,4 +64,33 @@
</section>
<!-- END CONTENT -->
<script>
function submitResult() {
return confirm("{{__('Are you sure you wish to delete?')}}") !== false;
}
$(document).ready(function() {
$('#datatable').DataTable({
language: {
url: '//cdn.datatables.net/plug-ins/1.11.3/i18n/{{ $locale_datatables }}.json'
},
processing: true,
serverSide: true,
stateSave: true,
ajax: "{{route('admin.coupons.datatable')}}",
columns: [
{data: 'status'},
{data: 'code'},
{data: 'value'},
{data: 'uses'},
{data: 'expires_at'},
{data: 'created_at'},
{data: 'actions', sortable: false},
],
fnDrawCallback: function( oSettings ) {
$('[data-toggle="popover"]').popover();
}
});
})
</script>
@endsection