$emails * @param iterable $customerIds * @return Collection keyed by subscription id */ public function handle(iterable $emails, iterable $customerIds = []): Collection { $previousMaxNetworkRetries = Stripe::getMaxNetworkRetries(); Stripe::setMaxNetworkRetries(2); try { return $this->find(app(StripeClient::class), $emails, collect($customerIds)->filter()->values()); } finally { Stripe::setMaxNetworkRetries($previousMaxNetworkRetries); } } /** * @param iterable $emails * @param Collection $customerIds * @return Collection */ private function find(StripeClient $stripe, iterable $emails, Collection $customerIds): Collection { // The email filter of Stripe is case-sensitive. $emails = collect($emails)->filter()->flatMap(fn (string $email): array => [$email, strtolower($email)])->unique(); foreach ($emails as $email) { foreach ($stripe->customers->all(['email' => $email, 'limit' => 100])->autoPagingIterator() as $customer) { $customerIds->push($customer->id); } usleep(self::REQUEST_DELAY_MICROSECONDS); } $subscriptions = collect(); foreach ($customerIds->unique() as $customerId) { // Without a status filter, Stripe lists every subscription that is not canceled. foreach ($stripe->subscriptions->all(['customer' => $customerId, 'limit' => 100])->autoPagingIterator() as $subscription) { if ($subscription->status !== StripeSubscription::STATUS_INCOMPLETE_EXPIRED) { $subscriptions->put($subscription->id, $subscription); } } usleep(self::REQUEST_DELAY_MICROSECONDS); } return $subscriptions; } /** * The team that records the subscription, else the team in its metadata. */ public static function teamId(StripeSubscription $subscription): ?int { $teamId = Subscription::query()->where('stripe_subscription_id', $subscription->id)->value('team_id') ?? data_get($subscription, 'metadata.team_id'); return is_numeric($teamId) ? (int) $teamId : null; } }