CartRewardPoints.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. <?php
  2. namespace Longyi\RewardPoints\Services;
  3. use Longyi\RewardPoints\Repositories\RewardPointRepository;
  4. use Longyi\RewardPoints\Models\RewardPointCustomer;
  5. use Webkul\Checkout\Facades\Cart;
  6. use Webkul\Customer\Facades\Customer;
  7. class CartRewardPoints
  8. {
  9. /**
  10. * Session key for points used in cart
  11. */
  12. const POINTS_USED_KEY = 'reward_points_used';
  13. /**
  14. * @var RewardPointRepository
  15. */
  16. protected $rewardPointRepository;
  17. /**
  18. * CartRewardPoints constructor.
  19. */
  20. public function __construct()
  21. {
  22. $this->rewardPointRepository = app(RewardPointRepository::class);
  23. }
  24. /**
  25. * Get available points for current customer
  26. */
  27. public function getAvailablePoints()
  28. {
  29. if (!Customer::check()) {
  30. return 0;
  31. }
  32. return $this->rewardPointRepository->getCustomerPoints(Customer::getCustomerId());
  33. }
  34. /**
  35. * Get points used in current cart
  36. */
  37. public function getPointsUsed()
  38. {
  39. if (!session()->has(self::POINTS_USED_KEY)) {
  40. return 0;
  41. }
  42. return session()->get(self::POINTS_USED_KEY);
  43. }
  44. /**
  45. * Get discount amount from points
  46. */
  47. public function getDiscountAmount($points = null)
  48. {
  49. $pointsUsed = $points ?: $this->getPointsUsed();
  50. if ($pointsUsed <= 0) {
  51. return 0;
  52. }
  53. $pointValue = config('rewardpoints.general.point_value', 0.01);
  54. return $pointsUsed * $pointValue;
  55. }
  56. /**
  57. * Apply points to cart
  58. */
  59. public function applyPoints($points)
  60. {
  61. $cart = Cart::getCart();
  62. if (!$cart) {
  63. return false;
  64. }
  65. $availablePoints = $this->getAvailablePoints();
  66. if ($points <= 0) {
  67. $this->removePoints();
  68. return false;
  69. }
  70. if ($points > $availablePoints) {
  71. return false;
  72. }
  73. // Calculate maximum points that can be used based on cart total
  74. $maxPointsByAmount = $this->getMaxPointsByCartTotal();
  75. if ($points > $maxPointsByAmount) {
  76. return false;
  77. }
  78. // Save points to session
  79. session()->put(self::POINTS_USED_KEY, $points);
  80. // Recalculate cart
  81. Cart::collectTotals();
  82. return true;
  83. }
  84. /**
  85. * Remove points from cart
  86. */
  87. public function removePoints()
  88. {
  89. session()->forget(self::POINTS_USED_KEY);
  90. Cart::collectTotals();
  91. return true;
  92. }
  93. /**
  94. * Calculate discount based on points
  95. */
  96. public function calculateDiscount()
  97. {
  98. $pointsUsed = $this->getPointsUsed();
  99. if ($pointsUsed <= 0) {
  100. return 0;
  101. }
  102. $discountAmount = $this->getDiscountAmount($pointsUsed);
  103. return $discountAmount;
  104. }
  105. /**
  106. * Get maximum points that can be used based on cart total
  107. */
  108. protected function getMaxPointsByCartTotal()
  109. {
  110. $cart = Cart::getCart();
  111. if (!$cart) {
  112. return 0;
  113. }
  114. $cartTotal = $cart->grand_total;
  115. // Get maximum discount percentage (default: 100%)
  116. $maxDiscountPercentage = core()->getConfigData('rewardpoints.general.max_discount_percentage', 100);
  117. // Calculate maximum discount amount
  118. $maxDiscountAmount = ($cartTotal * $maxDiscountPercentage) / 100;
  119. // Convert discount amount to points
  120. $pointValue = core()->getConfigData('rewardpoints.general.point_value', 0.01);
  121. $maxPoints = $pointValue > 0 ? floor($maxDiscountAmount / $pointValue) : 0;
  122. return $maxPoints;
  123. }
  124. /**
  125. * Get discount details for cart
  126. */
  127. public function getDiscountDetails()
  128. {
  129. $pointsUsed = $this->getPointsUsed();
  130. if ($pointsUsed <= 0) {
  131. return null;
  132. }
  133. $discountAmount = $this->getDiscountAmount();
  134. return [
  135. 'points_used' => $pointsUsed,
  136. 'discount_amount' => $discountAmount,
  137. 'formatted_discount' => core()->formatPrice($discountAmount),
  138. 'available_points' => $this->getAvailablePoints(),
  139. 'points_remaining' => $this->getAvailablePoints() - $pointsUsed
  140. ];
  141. }
  142. /**
  143. * Process order points
  144. */
  145. public function processOrderPoints($order)
  146. {
  147. $pointsUsed = $this->getPointsUsed();
  148. if ($pointsUsed <= 0) {
  149. return false;
  150. }
  151. $customerId = $order->customer_id;
  152. if (!$customerId) {
  153. return false;
  154. }
  155. // Deduct points from customer
  156. $discountAmount = $this->getDiscountAmount($pointsUsed);
  157. $result = $this->rewardPointRepository->deductPoints(
  158. $customerId,
  159. $pointsUsed,
  160. 0,
  161. "Points redeemed for order #{$order->increment_id} (Discount: " . core()->formatPrice($discountAmount) . ")",
  162. $order->id
  163. );
  164. // Clear session
  165. $this->removePoints();
  166. return $result;
  167. }
  168. /**
  169. * Get points value in currency
  170. */
  171. public function getPointsValue($points)
  172. {
  173. $pointValue = core()->getConfigData('rewardpoints.general.point_value', 0.01);
  174. return $points * $pointValue;
  175. }
  176. /**
  177. * Get currency value in points
  178. */
  179. public function getPointsFromValue($value)
  180. {
  181. $pointValue = core()->getConfigData('rewardpoints.general.point_value', 0.01);
  182. return $pointValue > 0 ? floor($value / $pointValue) : 0;
  183. }
  184. /**
  185. * Validate if points can be applied to cart
  186. */
  187. public function validatePoints($points)
  188. {
  189. $cart = Cart::getCart();
  190. if (!$cart) {
  191. return 'Cart not found';
  192. }
  193. $availablePoints = $this->getAvailablePoints();
  194. if ($points <= 0) {
  195. return 'Points must be greater than 0';
  196. }
  197. if ($points > $availablePoints) {
  198. return "You only have {$availablePoints} points available";
  199. }
  200. $maxPoints = $this->getMaxPointsByCartTotal();
  201. if ($points > $maxPoints) {
  202. return "Maximum {$maxPoints} points can be used for this order";
  203. }
  204. return true;
  205. }
  206. }