From 24ce267962ef57d71354dbeaea8ac732789095c6 Mon Sep 17 00:00:00 2001 From: Ferks-FK Date: Fri, 19 May 2023 14:01:10 +0000 Subject: [PATCH] Implement coupons for the other gateways. --- .../Mollie/MollieExtension.php | 35 ++++++++-- .../PaymentGateways/Mollie/web_routes.php | 4 +- .../Stripe/StripeExtension.php | 36 ++++++++-- .../PaymentGateways/Stripe/web_routes.php | 4 +- app/Models/Coupon.php | 67 ++++--------------- app/Settings/CouponSettings.php | 2 +- 6 files changed, 78 insertions(+), 70 deletions(-) diff --git a/app/Extensions/PaymentGateways/Mollie/MollieExtension.php b/app/Extensions/PaymentGateways/Mollie/MollieExtension.php index 11cf3c6e..9145b067 100644 --- a/app/Extensions/PaymentGateways/Mollie/MollieExtension.php +++ b/app/Extensions/PaymentGateways/Mollie/MollieExtension.php @@ -9,10 +9,12 @@ use App\Models\PartnerDiscount; use App\Models\Payment; use App\Models\ShopProduct; use App\Models\User; +use App\Models\Coupon; +use App\Traits\Coupon as CouponTrait; +use App\Events\CouponUsedEvent; use Exception; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -use Illuminate\Http\Response; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\Log; @@ -23,6 +25,8 @@ use Illuminate\Support\Facades\Http; */ class MollieExtension extends AbstractExtension { + use CouponTrait; + public static function getConfig(): array { return [ @@ -33,7 +37,7 @@ class MollieExtension extends AbstractExtension ]; } - static function pay(Request $request): void + public function pay(Request $request): void { $url = 'https://api.mollie.com/v2/payments'; $settings = new MollieSettings(); @@ -41,6 +45,18 @@ class MollieExtension extends AbstractExtension $user = Auth::user(); $shopProduct = ShopProduct::findOrFail($request->shopProduct); $discount = PartnerDiscount::getDiscount(); + $couponCode = $request->input('couponCode'); + $isValidCoupon = $this->validateCoupon($request->user(), $couponCode, $request->shopProduct); + $price = $shopProduct->price; + + // Coupon Discount. + if ($isValidCoupon->getStatusCode() == 200) { + $price = $this->calcDiscount($price, $isValidCoupon->getData()); + } + + // Partner Discount. + $price = $price - ($price * $discount / 100); + $price = number_format($price, 2, thousands_separator: ''); // create a new payment $payment = Payment::create([ @@ -50,7 +66,7 @@ class MollieExtension 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(), @@ -65,10 +81,10 @@ class MollieExtension extends AbstractExtension ])->post($url, [ 'amount' => [ 'currency' => $shopProduct->currency_code, - 'value' => number_format($shopProduct->getTotalPrice(), 2, '.', ''), + 'value' => $price, ], 'description' => "Order #{$payment->id} - " . $shopProduct->name, - 'redirectUrl' => route('payment.MollieSuccess'), + 'redirectUrl' => route('payment.MollieSuccess', ['couponCode' => $couponCode]), 'cancelUrl' => route('payment.Cancel'), 'webhookUrl' => url('/extensions/payment/MollieWebhook'), 'metadata' => [ @@ -103,6 +119,15 @@ class MollieExtension extends AbstractExtension { $payment = Payment::findOrFail($request->input('payment')); $payment->status = 'pending'; + $coupon_code = $request->input('couponCode'); + + // increase the use of the coupon when the payment is confirmed. + if ($coupon_code) { + $coupon = new Coupon; + $coupon->incrementUses($coupon_code); + + event(new CouponUsedEvent($coupon)); + } Redirect::route('home')->with('success', 'Your payment is being processed')->send(); return; diff --git a/app/Extensions/PaymentGateways/Mollie/web_routes.php b/app/Extensions/PaymentGateways/Mollie/web_routes.php index f5640b9a..2314774a 100644 --- a/app/Extensions/PaymentGateways/Mollie/web_routes.php +++ b/app/Extensions/PaymentGateways/Mollie/web_routes.php @@ -4,8 +4,8 @@ use Illuminate\Support\Facades\Route; use App\Extensions\PaymentGateways\Mollie\MollieExtension; Route::middleware(['web', 'auth'])->group(function () { - Route::get('payment/MolliePay/{shopProduct}', function () { - MollieExtension::pay(request()); + Route::get('payment/MolliePay/{shopProduct}', function (MollieExtension $mollieExtension) { + $mollieExtension->pay(request()); })->name('payment.MolliePay'); Route::get( diff --git a/app/Extensions/PaymentGateways/Stripe/StripeExtension.php b/app/Extensions/PaymentGateways/Stripe/StripeExtension.php index 7102e223..f54157d4 100644 --- a/app/Extensions/PaymentGateways/Stripe/StripeExtension.php +++ b/app/Extensions/PaymentGateways/Stripe/StripeExtension.php @@ -4,12 +4,15 @@ namespace App\Extensions\PaymentGateways\Stripe; use App\Helpers\AbstractExtension; use App\Events\PaymentEvent; +use App\Events\CouponUsedEvent; use App\Events\UserUpdateCreditsEvent; use App\Extensions\PaymentGateways\Stripe\StripeSettings; use App\Models\PartnerDiscount; use App\Models\Payment; use App\Models\ShopProduct; use App\Models\User; +use App\Models\Coupon; +use App\Traits\Coupon as CouponTrait; use App\Notifications\ConfirmPaymentNotification; use Exception; use Illuminate\Http\Request; @@ -21,6 +24,8 @@ use Stripe\StripeClient; class StripeExtension extends AbstractExtension { + use CouponTrait; + public static function getConfig(): array { return [ @@ -35,10 +40,14 @@ class StripeExtension extends AbstractExtension * @param Request $request * @param ShopProduct $shopProduct */ - public static function StripePay(Request $request) + public function StripePay(Request $request) { $user = Auth::user(); $shopProduct = ShopProduct::findOrFail($request->shopProduct); + $discount = PartnerDiscount::getDiscount(); + $couponCode = $request->input('couponCode'); + $isValidCoupon = $this->validateCoupon($request->user(), $couponCode, $request->shopProduct); + $price = $shopProduct->price; // check if the price is valid for stripe if (!self::checkPriceAmount($shopProduct->getTotalPrice(), strtoupper($shopProduct->currency_code), 'stripe')) { @@ -46,7 +55,14 @@ class StripeExtension extends AbstractExtension return; } - $discount = PartnerDiscount::getDiscount(); + // Coupon Discount. + if ($isValidCoupon->getStatusCode() == 200) { + $price = $this->calcDiscount($price, $isValidCoupon->getData()); + } + + // Partner Discount. + $price = $price - ($price * $discount / 100); + $price = number_format($price, 2); // create payment @@ -57,7 +73,7 @@ class StripeExtension extends AbstractExtension 'type' => $shopProduct->type, 'status' => 'open', 'amount' => $shopProduct->quantity, - 'price' => $shopProduct->price - ($shopProduct->price * $discount / 100), + 'price' => $price, 'tax_value' => $shopProduct->getTaxValue(), 'total_price' => $shopProduct->getTotalPrice(), 'tax_percent' => $shopProduct->getTaxPercent(), @@ -75,7 +91,7 @@ class StripeExtension extends AbstractExtension 'name' => $shopProduct->display . ($discount ? (' (' . __('Discount') . ' ' . $discount . '%)') : ''), 'description' => $shopProduct->description, ], - 'unit_amount_decimal' => round($shopProduct->getPriceAfterDiscount() * 100, 2), + 'unit_amount_decimal' => $price, ], 'quantity' => 1, ], @@ -93,7 +109,7 @@ class StripeExtension extends AbstractExtension ], 'mode' => 'payment', - 'success_url' => route('payment.StripeSuccess', ['payment' => $payment->id]) . '&session_id={CHECKOUT_SESSION_ID}', + 'success_url' => route('payment.StripeSuccess', ['payment' => $payment->id, 'couponCode' => $couponCode]) . '&session_id={CHECKOUT_SESSION_ID}', 'cancel_url' => route('payment.Cancel'), 'payment_intent_data' => [ 'metadata' => [ @@ -114,7 +130,7 @@ class StripeExtension extends AbstractExtension $user = User::findOrFail($user->id); $payment = Payment::findOrFail($request->input('payment')); $shopProduct = ShopProduct::findOrFail($payment->shop_item_product_id); - + $couponCode = $request->input('couponCode'); Redirect::route('home')->with('success', 'Please wait for success')->send(); @@ -136,6 +152,14 @@ class StripeExtension extends AbstractExtension 'status' => 'paid', ]); + // increase the use of the coupon when the payment is confirmed. + if ($couponCode) { + $coupon = new Coupon; + $coupon->incrementUses($couponCode); + + event(new CouponUsedEvent($coupon)); + } + //payment notification $user->notify(new ConfirmPaymentNotification($payment)); diff --git a/app/Extensions/PaymentGateways/Stripe/web_routes.php b/app/Extensions/PaymentGateways/Stripe/web_routes.php index 0f4fed96..c5640aba 100644 --- a/app/Extensions/PaymentGateways/Stripe/web_routes.php +++ b/app/Extensions/PaymentGateways/Stripe/web_routes.php @@ -4,8 +4,8 @@ use Illuminate\Support\Facades\Route; use App\Extensions\PaymentGateways\Stripe\StripeExtension; Route::middleware(['web', 'auth'])->group(function () { - Route::get('payment/StripePay/{shopProduct}', function () { - StripeExtension::StripePay(request()); + Route::get('payment/StripePay/{shopProduct}', function (StripeExtension $stripeExtension) { + $stripeExtension->StripePay(request()); })->name('payment.StripePay'); Route::get( diff --git a/app/Models/Coupon.php b/app/Models/Coupon.php index 01133f4a..97a5b973 100644 --- a/app/Models/Coupon.php +++ b/app/Models/Coupon.php @@ -4,11 +4,21 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Spatie\Activitylog\LogOptions; +use Spatie\Activitylog\Traits\LogsActivity; use Carbon\Carbon; class Coupon extends Model { - use HasFactory; + use HasFactory, LogsActivity; + + public function getActivitylogOptions(): LogOptions + { + return LogOptions::defaults() + ->logOnlyDirty() + ->logOnly(['*']) + ->dontSubmitEmptyLogs(); + } /** * @var string[] @@ -97,67 +107,16 @@ class Coupon extends Model 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 + * @return bool */ - public function incrementUses(string $code, int $amount = 1): null|bool + public function incrementUses(string $code, int $amount = 1): 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; diff --git a/app/Settings/CouponSettings.php b/app/Settings/CouponSettings.php index 29ec3332..dde8f42a 100644 --- a/app/Settings/CouponSettings.php +++ b/app/Settings/CouponSettings.php @@ -43,7 +43,7 @@ class CouponSettings extends Settings 'description' => 'Maximum number of uses that a user can make of the same coupon.' ], 'delete_coupon_on_expires' => [ - 'label' => 'Delete Coupon On Expires', + 'label' => 'Auto Delete Expired Coupons', 'type' => 'boolean', 'description' => 'Automatically deletes the coupon if it expires.' ],