From 72f3decd3f97b9e1236b7cd42ead513b8eb624ba Mon Sep 17 00:00:00 2001 From: Ferks-FK Date: Wed, 17 May 2023 16:17:51 +0000 Subject: [PATCH] Feat: Let's implement the coupons now --- .editorconfig | 25 +- .gitignore | 1 + .../PayPal/PayPalExtension.php | 25 +- .../Controllers/Admin/CouponController.php | 159 ++++++++++ .../Controllers/Admin/PaymentController.php | 30 ++ app/Http/Controllers/ProfileController.php | 3 +- app/Models/Coupon.php | 162 ++++++++++ app/Models/User.php | 10 +- app/Settings/CouponSettings.php | 43 +++ app/Traits/Coupon.php | 86 ++++++ bootstrap/cache/.gitignore | 0 config/permissions_web.php | 3 + config/settings.php | 2 + ...2023_05_11_153719_create_coupons_table.php | 37 +++ ...05_14_152604_create_user_coupons_table.php | 32 ++ ...23_05_12_170041_create_coupon_settings.php | 16 + package-lock.json | 2 +- routes/web.php | 5 + storage/app/.gitignore | 0 storage/app/public/.gitignore | 0 storage/debugbar/.gitignore | 0 storage/framework/.gitignore | 0 storage/framework/cache/.gitignore | 0 storage/framework/sessions/.gitignore | 0 storage/framework/testing/.gitignore | 0 storage/framework/views/.gitignore | 0 storage/logs/.gitignore | 0 .../views/admin/coupons/create.blade.php | 289 ++++++++++++++++++ .../views/admin/coupons/index.blade.php | 65 ++++ themes/default/views/layouts/main.blade.php | 14 +- themes/default/views/store/checkout.blade.php | 128 +++++++- 31 files changed, 1122 insertions(+), 15 deletions(-) create mode 100644 app/Http/Controllers/Admin/CouponController.php create mode 100644 app/Models/Coupon.php create mode 100644 app/Settings/CouponSettings.php create mode 100644 app/Traits/Coupon.php mode change 100644 => 100755 bootstrap/cache/.gitignore create mode 100644 database/migrations/2023_05_11_153719_create_coupons_table.php create mode 100644 database/migrations/2023_05_14_152604_create_user_coupons_table.php create mode 100644 database/settings/2023_05_12_170041_create_coupon_settings.php mode change 100644 => 100755 storage/app/.gitignore mode change 100644 => 100755 storage/app/public/.gitignore mode change 100644 => 100755 storage/debugbar/.gitignore mode change 100644 => 100755 storage/framework/.gitignore mode change 100644 => 100755 storage/framework/cache/.gitignore mode change 100644 => 100755 storage/framework/sessions/.gitignore mode change 100644 => 100755 storage/framework/testing/.gitignore mode change 100644 => 100755 storage/framework/views/.gitignore mode change 100644 => 100755 storage/logs/.gitignore create mode 100644 themes/default/views/admin/coupons/create.blade.php create mode 100644 themes/default/views/admin/coupons/index.blade.php diff --git a/.editorconfig b/.editorconfig index 6537ca46..78326873 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,9 +3,9 @@ root = true [*] charset = utf-8 end_of_line = lf -insert_final_newline = true +indent_size = 2 indent_style = space -indent_size = 4 +insert_final_newline = true trim_trailing_whitespace = true [*.md] @@ -13,3 +13,24 @@ trim_trailing_whitespace = false [*.{yml,yaml}] indent_size = 2 + +[docker-compose.yml] +indent_size = 2 + +[*.php] +indent_size = 4 + +[*.blade.php] +indent_size = 2 + +[*.js] +indent_size = 4 + +[*.jsx] +indent_size = 2 + +[*.tsx] +indent_size = 2 + +[*.json] +indent_size = 4 diff --git a/.gitignore b/.gitignore index 58212a1d..ad9d095b 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ storage/debugbar .env.backup .idea .phpunit.result.cache +.editorconfig docker-compose.override.yml Homestead.json Homestead.yaml diff --git a/app/Extensions/PaymentGateways/PayPal/PayPalExtension.php b/app/Extensions/PaymentGateways/PayPal/PayPalExtension.php index 6b1c335e..73d632df 100644 --- a/app/Extensions/PaymentGateways/PayPal/PayPalExtension.php +++ b/app/Extensions/PaymentGateways/PayPal/PayPalExtension.php @@ -10,6 +10,7 @@ use App\Models\PartnerDiscount; use App\Models\Payment; use App\Models\ShopProduct; use App\Models\User; +use App\Models\Coupon; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Redirect; @@ -41,6 +42,17 @@ class PayPalExtension extends AbstractExtension $user = Auth::user(); $shopProduct = ShopProduct::findOrFail($request->shopProduct); $discount = PartnerDiscount::getDiscount(); + $discountPrice = $request->get('discountPrice'); + + dd($discountPrice); + + // Partner Discount. + $price = $shopProduct->price - ($shopProduct->price * $discount / 100); + + // Coupon Discount. + // if ($discountPrice) { + // $price = $price - ($price * floatval($coupon_percentage) / 100); + // } // create a new payment $payment = Payment::create([ @@ -50,7 +62,7 @@ class PayPalExtension extends AbstractExtension 'type' => $shopProduct->type, 'status' => 'open', 'amount' => $shopProduct->quantity, - 'price' => $shopProduct->price - ($shopProduct->price * $discount / 100), + 'price' => $price, 'tax_value' => $shopProduct->getTaxValue(), 'tax_percent' => $shopProduct->getTaxPercent(), 'total_price' => $shopProduct->getTotalPrice(), @@ -73,7 +85,7 @@ class PayPalExtension extends AbstractExtension 'item_total' => [ 'currency_code' => strtoupper($shopProduct->currency_code), - 'value' => $shopProduct->getPriceAfterDiscount(), + 'value' => number_format($price, 2), ], 'tax_total' => [ @@ -86,7 +98,7 @@ class PayPalExtension extends AbstractExtension ], "application_context" => [ "cancel_url" => route('payment.Cancel'), - "return_url" => route('payment.PayPalSuccess', ['payment' => $payment->id]), + "return_url" => route('payment.PayPalSuccess', ['payment' => $payment->id, 'couponCode' => $coupon_code]), 'brand_name' => config('app.name', 'CtrlPanel.GG'), 'shipping_preference' => 'NO_SHIPPING' ] @@ -126,6 +138,7 @@ class PayPalExtension extends AbstractExtension $payment = Payment::findOrFail($laravelRequest->payment); $shopProduct = ShopProduct::findOrFail($payment->shop_item_product_id); + $coupon_code = $laravelRequest->input('couponCode'); $request = new OrdersCaptureRequest($laravelRequest->input('token')); $request->prefer('return=representation'); @@ -140,6 +153,12 @@ class PayPalExtension extends AbstractExtension 'payment_id' => $response->result->id, ]); + // increase the use of the coupon when the payment is confirmed. + if ($coupon_code) { + $coupon = new Coupon; + $coupon->incrementUses($coupon_code); + } + event(new UserUpdateCreditsEvent($user)); event(new PaymentEvent($user, $payment, $shopProduct)); diff --git a/app/Http/Controllers/Admin/CouponController.php b/app/Http/Controllers/Admin/CouponController.php new file mode 100644 index 00000000..44c3d618 --- /dev/null +++ b/app/Http/Controllers/Admin/CouponController.php @@ -0,0 +1,159 @@ +checkPermission(self::READ_PERMISSION); + + return view('admin.coupons.index'); + } + + /** + * Show the form for creating a new resource. + * + * @return \Illuminate\Http\Response + */ + public function create() + { + $this->checkPermission(self::WRITE_PERMISSION); + + return view('admin.coupons.create'); + } + + /** + * Store a newly created resource in storage. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + 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'); + $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()) + ]; + + // 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()); + } + + 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)) { + $data = []; + $coupons = Coupon::generateRandomCoupon($random_codes_amount); + + // Scroll through all the randomly generated coupons. + foreach ($coupons as $coupon) { + $data[] = [ + 'code' => $coupon, + 'type' => $coupon_type, + 'value' => $coupon_value, + 'max_uses' => $coupon_max_uses, + 'expires_at' => $coupon_datepicker, + '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, + ]); + } + + return redirect()->route('admin.coupons.index')->with('success', __("The coupon's was registered successfully.")); + } + + /** + * Display the specified resource. + * + * @param \App\Models\Coupon $coupon + * @return \Illuminate\Http\Response + */ + public function show(Coupon $coupon) + { + // + } + + /** + * Show the form for editing the specified resource. + * + * @param \App\Models\Coupon $coupon + * @return \Illuminate\Http\Response + */ + public function edit(Coupon $coupon) + { + // + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param \App\Models\Coupon $coupon + * @return \Illuminate\Http\Response + */ + public function update(Request $request, Coupon $coupon) + { + // + } + + /** + * Remove the specified resource from storage. + * + * @param \App\Models\Coupon $coupon + * @return \Illuminate\Http\Response + */ + public function destroy(Coupon $coupon) + { + // + } + + public function redeem(Request $request) + { + return $this->validateCoupon($request); + } +} diff --git a/app/Http/Controllers/Admin/PaymentController.php b/app/Http/Controllers/Admin/PaymentController.php index 543cdcf6..7c85d44e 100644 --- a/app/Http/Controllers/Admin/PaymentController.php +++ b/app/Http/Controllers/Admin/PaymentController.php @@ -9,6 +9,8 @@ use App\Models\PartnerDiscount; use App\Models\Payment; use App\Models\User; use App\Models\ShopProduct; +use App\Models\Coupon; +use App\Traits\Coupon as CouponTrait; use Exception; use Illuminate\Contracts\Foundation\Application; use Illuminate\Contracts\View\Factory; @@ -20,11 +22,16 @@ use Illuminate\Support\Facades\Auth; use App\Helpers\ExtensionHelper; use App\Settings\GeneralSettings; use App\Settings\LocaleSettings; +use Carbon\Carbon; +use Illuminate\Support\Str; class PaymentController extends Controller { const BUY_PERMISSION = 'user.shop.buy'; const VIEW_PERMISSION = "admin.payments.read"; + + use CouponTrait; + /** * @return Application|Factory|View */ @@ -123,6 +130,8 @@ class PaymentController extends Controller { $product = ShopProduct::find($request->product_id); $paymentGateway = $request->payment_method; + $coupon_data = null; + $coupon_code = $request->coupon_code; // on free products, we don't need to use a payment gateway $realPrice = $product->price - ($product->price * PartnerDiscount::getDiscount() / 100); @@ -130,6 +139,22 @@ class PaymentController extends Controller return $this->handleFreeProduct($product); } + if ($coupon_code) { + $isValidCoupon = $this->validateCoupon($request); + + if ($isValidCoupon->getStatusCode() == 200) { + $coupon_data = $isValidCoupon; + $discountPrice = $this->calcDiscount($product, $isValidCoupon->getData()); + } + } + + if ($coupon_data) { + return redirect()->route('payment.' . $paymentGateway . 'Pay', [ + 'shopProduct' => $product->id, + 'discountPrice' => $discountPrice + ]); + } + return redirect()->route('payment.' . $paymentGateway . 'Pay', ['shopProduct' => $product->id]); } @@ -141,6 +166,11 @@ class PaymentController extends Controller return redirect()->route('store.index')->with('info', 'Payment was Canceled'); } + protected function getCouponDiscount(float $productPrice, string $discount) + { + return $productPrice - ($productPrice * $discount / 100); + } + /** * @return JsonResponse|mixed * diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index 8a042501..52cb0bff 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -34,8 +34,7 @@ class ProfileController extends Controller 'force_discord_verification' => $user_settings->force_discord_verification, 'discord_client_id' => $discord_settings->client_id, 'discord_client_secret' => $discord_settings->client_secret, - 'referral_enabled' => $referral_settings->enabled, - 'referral_allowed' => $referral_settings->allowed + 'referral_enabled' => $referral_settings->enabled ]); } diff --git a/app/Models/Coupon.php b/app/Models/Coupon.php new file mode 100644 index 00000000..9b849751 --- /dev/null +++ b/app/Models/Coupon.php @@ -0,0 +1,162 @@ +uses >= $this->max_uses) { + return 'USES_LIMIT_REACHED'; + } + + if (! is_null($this->expires_at)) { + $expires_at = Carbon::createFromTimeString($this->expires_at)->timestamp; + + if ($expires_at <= Carbon::now()->timestamp) { + return __('EXPIRED'); + } + } + + return __('VALID'); + } + + /** + * Check if a user has already exceeded the uses of a coupon. + * + * @param Request $request The request being made. + * @param CouponSettings $coupon_settings The instance of the coupon settings. + * + * @return bool + */ + public function isLimitsUsesReached($request, $coupon_settings): bool + { + $coupon_uses = $request->user()->coupons()->where('id', $this->id)->count(); + + return $coupon_uses >= $coupon_settings->max_uses_per_user ? true : false; + } + + /** + * Generate a specified quantity of coupon codes. + * + * @param int $amount Amount of coupons to be generated. + * + * @return array + */ + public static function generateRandomCoupon(int $amount = 10): array + { + $coupons = []; + + for ($i = 0; $i < $amount; $i++) { + $random_coupon = strtoupper(bin2hex(random_bytes(3))); + + $coupons[] = $random_coupon; + } + + return $coupons; + } + + /** + * Standardize queries into one single function. + * + * @param string $code Coupon Code. + * @param array $attributes Attributes to be returned. + * + * @return mixed + */ + protected function getQueryData(string $code, array $attributes): mixed + { + $query = (Coupon::where('code', $code) + ->where('expires_at', '>', Carbon::now()) + ->whereColumn('uses', '<=', 'max_uses') + ->get($attributes)->toArray() + ); + + // When there are results, it comes nested arrays, idk why. This is the solution for now. + $results = count($query) > 0 ? $query[0] : $query; + + if (empty($results)) { + return []; + } + + return $results; + } + + /** + * Get the data from a coupon. + * + * @param string $code Coupon Code. + * @param array $attributes Attributes of a coupon. + * + * @return mixed + */ + public function getCoupon(string $code, array $attributes = ['percentage']): mixed + { + $coupon = $this->getQueryData($code, $attributes); + + if (is_null($coupon)) { + return null; + } + + return $coupon; + } + + /** + * Increments the use of a coupon. + * + * @param string $code Coupon Code. + * @param int $amount Amount to increment. + * + * @return null|bool + */ + public function incrementUses(string $code, int $amount = 1): null|bool + { + $coupon = $this->getQueryData($code, ['uses', 'max_uses']); + + if (empty($coupon) || $coupon['uses'] == $coupon['max_uses']) { + return null; + } + + $this->where('code', $code)->increment('uses', $amount); + + return true; + } + + /** + * @return BelongsToMany + */ + public function users() + { + return $this->belongsToMany(User::class, 'user_coupons'); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 2c632e3c..7c04a65b 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -4,8 +4,6 @@ namespace App\Models; use App\Notifications\Auth\QueuedVerifyEmail; use App\Notifications\WelcomeMessage; -use App\Settings\GeneralSettings; -use App\Settings\UserSettings; use App\Classes\PterodactylClient; use App\Settings\PterodactylSettings; use Illuminate\Contracts\Auth\MustVerifyEmail; @@ -170,6 +168,14 @@ class User extends Authenticatable implements MustVerifyEmail return $this->belongsToMany(Voucher::class); } + /** + * @return BelongsToMany + */ + public function coupons() + { + return $this->belongsToMany(Coupon::class, 'user_coupons'); + } + /** * @return HasOne */ diff --git a/app/Settings/CouponSettings.php b/app/Settings/CouponSettings.php new file mode 100644 index 00000000..45f9c25b --- /dev/null +++ b/app/Settings/CouponSettings.php @@ -0,0 +1,43 @@ + + */ + public static function getValidations() + { + return [ + 'max_uses_per_user' => 'required|integer' + ]; + } + + /** + * Summary of optionInputData array + * Only used for the settings page + * @return array>> + */ + public static function getOptionInputData() + { + return [ + "category_icon" => "fas fa-ticket-alt", + '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.', + ] + ]; + } +} diff --git a/app/Traits/Coupon.php b/app/Traits/Coupon.php new file mode 100644 index 00000000..319fd890 --- /dev/null +++ b/app/Traits/Coupon.php @@ -0,0 +1,86 @@ +input('coupon_code'))->first(); + $coupon_settings = new CouponSettings; + $response = response()->json([ + 'isValid' => false, + 'error' => __('This coupon does not exist.') + ], 404); + + if (!is_null($coupon)) { + if ($coupon->getStatus() == 'USES_LIMIT_REACHED') { + $response = response()->json([ + 'isValid' => false, + 'error' => __('This coupon has reached the maximum amount of uses.') + ], 422); + + return $response; + } + + if ($coupon->getStatus() == 'EXPIRED') { + $response = response()->json([ + 'isValid' => false, + 'error' => __('This coupon has expired.') + ], 422); + + return $response; + } + + if ($coupon->isLimitsUsesReached($request, $coupon_settings)) { + $response = response()->json([ + 'isValid' => false, + 'error' => __('You have reached the maximum uses of this coupon.') + ], 422); + + return $response; + } + + $response = response()->json([ + 'isValid' => true, + 'couponCode' => $coupon->code, + 'couponType' => $coupon->type, + 'couponValue' => $coupon->value + ]); + } + + return $response; + } + + public function calcDiscount(ShopProduct $product, stdClass $data) + { + + if ($data->isValid) { + $productPrice = $product->price; + + if (is_string($productPrice)) { + $productPrice = floatval($product->price); + } + + if ($data->couponType === 'percentage') { + return $productPrice - ($productPrice * $data->couponValue / 100); + } + + if ($data->couponType === 'amount') { + // There is no discount if the value of the coupon is greater than or equal to the value of the product. + if ($data->couponValue >= $productPrice) { + return $productPrice; + } + } + + return $productPrice - $data->couponValue; + } + } +} diff --git a/bootstrap/cache/.gitignore b/bootstrap/cache/.gitignore old mode 100644 new mode 100755 diff --git a/config/permissions_web.php b/config/permissions_web.php index 1c3828f7..f0918375 100644 --- a/config/permissions_web.php +++ b/config/permissions_web.php @@ -74,6 +74,9 @@ return [ 'admin.partners.read', 'admin.partners.write', + 'admin.coupons.read', + 'admin.coupons.write', + 'admin.logs.read', /* diff --git a/config/settings.php b/config/settings.php index 67838a5c..6b6ae4b7 100644 --- a/config/settings.php +++ b/config/settings.php @@ -12,6 +12,7 @@ use App\Settings\ServerSettings; use App\Settings\UserSettings; use App\Settings\WebsiteSettings; use App\Settings\TicketSettings; +use App\Settings\CouponSettings; return [ @@ -31,6 +32,7 @@ return [ UserSettings::class, WebsiteSettings::class, TicketSettings::class, + CouponSettings::class, ], /* diff --git a/database/migrations/2023_05_11_153719_create_coupons_table.php b/database/migrations/2023_05_11_153719_create_coupons_table.php new file mode 100644 index 00000000..48048f6a --- /dev/null +++ b/database/migrations/2023_05_11_153719_create_coupons_table.php @@ -0,0 +1,37 @@ +id(); + $table->string('code')->unique(); + $table->enum('type', ['percentage', 'amount']); + $table->integer('value'); + $table->integer('uses')->default(0); + $table->integer('max_uses'); + $table->timestamp('expires_at'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('coupons'); + } +}; diff --git a/database/migrations/2023_05_14_152604_create_user_coupons_table.php b/database/migrations/2023_05_14_152604_create_user_coupons_table.php new file mode 100644 index 00000000..10f584ae --- /dev/null +++ b/database/migrations/2023_05_14_152604_create_user_coupons_table.php @@ -0,0 +1,32 @@ +foreignId('user_id')->constrained(); + $table->foreignId('coupon_id')->constrained(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('user_coupons'); + } +}; diff --git a/database/settings/2023_05_12_170041_create_coupon_settings.php b/database/settings/2023_05_12_170041_create_coupon_settings.php new file mode 100644 index 00000000..77505cea --- /dev/null +++ b/database/settings/2023_05_12_170041_create_coupon_settings.php @@ -0,0 +1,16 @@ +migrator->add('coupon.max_uses_per_user', 1); + } + + public function down(): void + { + $this->migrator->delete('coupon.max_uses_per_user'); + } +}; diff --git a/package-lock.json b/package-lock.json index c687dafd..89d691a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "controllpanelgg", + "name": "controlpanel", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/routes/web.php b/routes/web.php index 5e09c048..bdfd06f5 100644 --- a/routes/web.php +++ b/routes/web.php @@ -22,6 +22,7 @@ use App\Http\Controllers\Admin\TicketsController as AdminTicketsController; use App\Http\Controllers\Admin\UsefulLinkController; use App\Http\Controllers\Admin\UserController; use App\Http\Controllers\Admin\VoucherController; +use App\Http\Controllers\Admin\CouponController; use App\Http\Controllers\Auth\SocialiteController; use App\Http\Controllers\HomeController; use App\Http\Controllers\NotificationController; @@ -199,6 +200,10 @@ Route::middleware(['auth', 'checkSuspended'])->group(function () { Route::get('partners/{voucher}/users', [PartnerController::class, 'users'])->name('partners.users'); Route::resource('partners', PartnerController::class); + //coupons + Route::post('coupons/redeem', [CouponController::class, 'redeem'])->name('coupon.redeem'); + Route::resource('coupons', CouponController::class); + //api-keys Route::get('api/datatable', [ApplicationApiController::class, 'datatable'])->name('api.datatable'); Route::resource('api', ApplicationApiController::class)->parameters([ diff --git a/storage/app/.gitignore b/storage/app/.gitignore old mode 100644 new mode 100755 diff --git a/storage/app/public/.gitignore b/storage/app/public/.gitignore old mode 100644 new mode 100755 diff --git a/storage/debugbar/.gitignore b/storage/debugbar/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/.gitignore b/storage/framework/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/cache/.gitignore b/storage/framework/cache/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/sessions/.gitignore b/storage/framework/sessions/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/testing/.gitignore b/storage/framework/testing/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/views/.gitignore b/storage/framework/views/.gitignore old mode 100644 new mode 100755 diff --git a/storage/logs/.gitignore b/storage/logs/.gitignore old mode 100644 new mode 100755 diff --git a/themes/default/views/admin/coupons/create.blade.php b/themes/default/views/admin/coupons/create.blade.php new file mode 100644 index 00000000..2b19d6a7 --- /dev/null +++ b/themes/default/views/admin/coupons/create.blade.php @@ -0,0 +1,289 @@ +@extends('layouts.main') + +@section('content') + +
+
+
+
+

{{__('Coupon')}}

+
+ +
+
+
+ + + +
+
+
+
+
+
+
+ + {{__('Coupon Details')}} +
+
+
+
+ @csrf + +
+
+ + +
+
+ +
+ + + @error('coupon_code') +
+ {{ $message }} +
+ @enderror +
+
+
+ + + @error('coupon_type') +
+ {{ $message }} +
+ @enderror +
+
+
+
+ +
+ + % +
+ @error('coupon_value') +
+ {{ $message }} +
+ @enderror +
+
+
+ + + @error('coupon_uses') +
+ {{ $message }} +
+ @enderror +
+
+ +
+ +
+
+ +
+
+
+ @error('datepicker') +
+ {{ $message }} +
+ @enderror +
+
+ +
+
+
+
+
+
+
+
+ + + +@endsection diff --git a/themes/default/views/admin/coupons/index.blade.php b/themes/default/views/admin/coupons/index.blade.php new file mode 100644 index 00000000..814b41ab --- /dev/null +++ b/themes/default/views/admin/coupons/index.blade.php @@ -0,0 +1,65 @@ +@extends('layouts.main') + +@section('content') + +
+
+
+
+

{{__('Coupons')}}

+
+ +
+
+
+ + + +
+
+
+
+
+
+ + {{__('Coupons')}} +
+ + + {{__('Create new')}} + +
+
+ +
+ + + + + + + + + + + + + +
{{__('Partner discount')}}{{__('Registered user discount')}}{{__('Referral system commission')}}{{__('Created')}}{{__('Actions')}}
+ +
+
+ + +
+ + +
+ +@endsection diff --git a/themes/default/views/layouts/main.blade.php b/themes/default/views/layouts/main.blade.php index 994f2bfc..9631ef64 100644 --- a/themes/default/views/layouts/main.blade.php +++ b/themes/default/views/layouts/main.blade.php @@ -424,7 +424,7 @@ @endcanany - @canany(["admin.voucher.read","admin.voucher.read"]) + @canany(["admin.voucher.read","admin.voucher.write"]) @endcanany - @canany(["admin.partners.read","admin.partners.read"]) + @canany(["admin.partners.read","admin.partners.write"]) @endcanany + @canany(["admin.coupons.read", "admin.coupons.write"]) + + @endcanany + @canany(["admin.useful_links.read","admin.legal.read"]) @endcanany diff --git a/themes/default/views/store/checkout.blade.php b/themes/default/views/store/checkout.blade.php index a6ca6886..690e6c04 100644 --- a/themes/default/views/store/checkout.blade.php +++ b/themes/default/views/store/checkout.blade.php @@ -24,7 +24,19 @@
-
+ @csrf @method('post')
@@ -67,6 +79,45 @@
+
+
+
+

+ Coupon Code +

+
+
+
+ + +
+ @error('coupon_code') +
+ {{ $message }} +
+ @enderror +
+
+
@endif
@@ -131,6 +182,12 @@ + {{ $product->formatToCurrency($taxvalue) }}
+
+ + {{ __('Coupon Discount') }} + + +
@if ($discountpercent && $discountvalue)
{{ __('Discount') }} @@ -155,9 +212,12 @@ - +
@@ -175,4 +237,64 @@
+ + @endsection