whisper-money/app/Console/Commands/GenerateStripePromotionCode...

104 lines
3.1 KiB
PHP

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
use Laravel\Cashier\Cashier;
use RuntimeException;
use Stripe\Exception\ApiErrorException;
use Stripe\PromotionCode;
class GenerateStripePromotionCodesCommand extends Command
{
private const DEFAULT_COUPON_ID = '0E5fAsXG';
protected $signature = 'stripe:generate-promotion-codes
{count : Number of promotion codes to generate}
{--coupon='.self::DEFAULT_COUPON_ID.' : Stripe coupon ID to attach to each code}';
protected $description = 'Generate single-use Stripe promotion codes';
public function handle(): int
{
$count = filter_var($this->argument('count'), FILTER_VALIDATE_INT);
if ($count === false || $count < 1) {
$this->error('Count must be a positive integer.');
return self::FAILURE;
}
$couponId = (string) $this->option('coupon');
$generatedCodes = [];
$rows = [];
$this->info("Generating {$count} single-use promotion codes for coupon {$couponId}...");
for ($index = 1; $index <= $count; $index++) {
try {
$promotionCode = $this->createPromotionCode($couponId, $generatedCodes);
} catch (ApiErrorException $exception) {
$this->error("Failed generating promotion code {$index}: {$exception->getMessage()}");
return self::FAILURE;
}
$generatedCodes[] = $promotionCode->code;
$rows[] = [$index, $promotionCode->id, $promotionCode->code];
}
$this->newLine();
$this->table(['#', 'Stripe ID', 'Code'], $rows);
$this->newLine();
$this->info('Generated '.$count.' promotion code'.($count === 1 ? '' : 's').'.');
return self::SUCCESS;
}
/**
* @param list<string> $generatedCodes
*/
private function createPromotionCode(string $couponId, array $generatedCodes): PromotionCode
{
for ($attempt = 1; $attempt <= 5; $attempt++) {
$code = $this->makeCode($generatedCodes);
try {
return Cashier::stripe()->promotionCodes->create([
'coupon' => $couponId,
'code' => $code,
'max_redemptions' => 1,
]);
} catch (ApiErrorException $exception) {
if ($attempt < 5 && $this->isDuplicateCodeError($exception)) {
continue;
}
throw $exception;
}
}
throw new RuntimeException('Unable to generate a unique promotion code after 5 attempts.');
}
/**
* @param list<string> $generatedCodes
*/
private function makeCode(array $generatedCodes): string
{
do {
$code = 'WM-'.Str::upper(Str::random(10));
} while (in_array($code, $generatedCodes, true));
return $code;
}
private function isDuplicateCodeError(ApiErrorException $exception): bool
{
$message = Str::lower($exception->getMessage());
return str_contains($message, 'code') && str_contains($message, 'exist');
}
}