'decimal:2', 'used_giftcard_amount' => 'decimal:2', 'remaining_giftcard_amount' => 'decimal:2', 'customer_id' => 'integer', 'expirationdate' => 'datetime', 'channel' => 'string', ]; protected static function boot() { parent::boot(); static::created(function ($giftCard) { GiftCardUsageLog::create([ 'giftcard_number' => $giftCard->giftcard_number, 'customer_id' => $giftCard->customer_id, 'balance_before' => $giftCard->giftcard_amount, 'balance_after' => $giftCard->giftcard_amount, 'action_type' => GiftCardUsageLog::ACTION_ADD, 'status' => 'completed', 'notes' => $giftCard->channel ?: '', ]); }); } public static function setGiftCardCode($giftcard) { if (!$giftcard) { return false; } $cart = cart()->getCart(); $cart->giftcard_number = $giftcard->giftcard_number; $cart->save(); return true; } public static function removeGiftCardCode() { $cart = cart()->getCart(); $giftcardAmount = $cart->giftcard_amount ?? 0; // 清除购物车中的礼品卡标记 $cart->giftcard_number = null; $cart->giftcard_amount = null; // 恢复购物车总额 $cart->grand_total += $giftcardAmount; $cart->base_grand_total += $giftcardAmount; $cart->save(); return true; } /** * Add a new gift card for a customer. * * @param int $customerId The ID of the customer to receive the gift card. * @param float $giftcardAmount The initial amount/balance of the gift card. * @param int $num Maximum number of gift cards allowed for this channel (0 means unlimited). * @param int $expirationdate Number of days until the gift card expires (default: 30 days). * @param string $channel The source channel or campaign identifier (default: 'activity_26_04_21'). * @param string $notes Additional notes or description for the gift card creation. * @return void * @throws \Exception If customerId is empty, giftcardAmount is empty, or gift card limit exceeded. */ public static function addGiftCard($customerId, $giftcardAmount, $num = 0, $expirationdate = 30, $channel = 'activity_26_04_21', $notes = '拉新活动添加') { if (empty($customerId)) { throw new \Exception('customerId is empty'); } if (empty($giftcardAmount)) { throw new \Exception('giftcardAmount is empty'); } $data = GiftCards::where('customer_id', $customerId) ->where('channel', $channel) ->count(); if ($num != 0) { $giftNum =count($data); if($giftNum <= $num){ throw new \Exception('gift num is not enough'); } } $expirationDate = self::calculateExpirationDate($expirationdate); static::create([ 'giftcard_number' => self::generateGiftCardNumber(), 'giftcard_amount' => $giftcardAmount, 'used_giftcard_amount' => 0, 'remaining_giftcard_amount' => $giftcardAmount, 'customer_id' => $customerId, 'expirationdate' => $expirationDate, 'giftcard_status' => 1, 'channel' => $channel, 'notes' => $notes ]); } /** * Calculate expiration date from various input types. * * @param mixed $expirationdate Days (int), date string, or Carbon instance * @return \Carbon\Carbon Calculated expiration date * @throws \Exception If the input type is invalid */ protected static function calculateExpirationDate($expirationdate): Carbon { if ($expirationdate instanceof Carbon) { return $expirationdate; } if (is_string($expirationdate)) { try { return Carbon::parse($expirationdate); } catch (\Exception $e) { throw new \Exception("Invalid date format: {$expirationdate}. Use Y-m-d format."); } } if (is_int($expirationdate) || is_float($expirationdate)) { if ($expirationdate <= 0) { throw new \Exception('Expiration days must be greater than 0'); } return now()->addDays((int) $expirationdate); } throw new \Exception('Invalid expiration date type. Must be integer (days), string (Y-m-d), or Carbon instance.'); } public static function generateGiftCardNumber() { do { // Generate a random string of characters $randomString = Str::upper(Str::random(16)); // Format the string into groups of four separated by dashes $code = implode('-', str_split($randomString, 4)); // Check if the code already exists in the database $exists = GiftCards::where('giftcard_number', $code)->exists(); } while ($exists); return $code; } public function giftcards() { return [ 1 => [ 'id' => 1, 'name' => 'Gift Card 1', 'amount' => 20.00, 'points' => 20, 'num' => 0, 'expirationdate' => 30, 'channel' => 'activity_26_04_21', 'notes' => '' ], 2 => [ 'id' => 2, 'name' => 'Gift Card 2', 'amount' => 30.00, 'points' => 30, 'num' => 0, 'expirationdate' => 30, 'channel' => 'activity_26_04_21', 'notes' => '' ], 3 => [ 'id' => 3, 'name' => 'Gift Card 3', 'amount' => 40.00, 'points' => 40, 'num' => 0, 'expirationdate' => 30, 'channel' => 'activity_26_04_21', 'notes' => '' ], 4 => [ 'id' => 4, 'name' => 'Gift Card 4', 'amount' => 50.00, 'points' => 50, 'num' => 0, 'expirationdate' => 30, 'channel' => 'activity_26_04_21', 'notes' => '' ], ]; } /** * Add a gift card for a customer using points * * @param int $id Gift card ID from giftcards() array * @param int $customerId Customer ID * @return array|true */ public function add($id, $customerId) { if (empty($customerId)) { throw new \Exception('customer id is empty'); } if (empty($id)) { throw new \Exception('gift card id is empty'); } $gifts = $this->giftcards(); $giftInfo = $gifts[$id] ?? null; if (!$giftInfo) { throw new \Exception("gift card not found (ID: {$id})"); } $points = $giftInfo['points'] ?? 0; if ($points <= 0) { throw new \Exception("gift card points configuration error (points: {$points})"); } try { DB::beginTransaction(); self::addGiftCard( $customerId, $giftInfo['amount'], $giftInfo['num'], $giftInfo['expirationdate'], $giftInfo['channel'], $giftInfo['notes'] ); $rewardPointRepository = app(RewardPointRepository::class); $rewardPointRepository->deductPoints( $customerId, $points, TransactionType::GIFT_CARD_REDEEM, 'Gift Card Redeem' ); DB::commit(); return true; } catch (\Exception $e) { DB::rollBack(); throw $e; } } }