Finish the coupon base.
This commit is contained in:
parent
490e11572d
commit
640468acbe
13 changed files with 626 additions and 81 deletions
42
app/Console/Commands/DeleteExpiredCoupons.php
Normal file
42
app/Console/Commands/DeleteExpiredCoupons.php
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 () {
|
||||
|
|
25
app/Events/CouponUsedEvent.php
Normal file
25
app/Events/CouponUsedEvent.php
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
47
app/Listeners/CouponUsed.php
Normal file
47
app/Listeners/CouponUsed.php
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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',
|
||||
|
|
|
@ -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.'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
291
themes/default/views/admin/coupons/edit.blade.php
Normal file
291
themes/default/views/admin/coupons/edit.blade.php
Normal 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
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue