Skip to content

Commit 8ef889b

Browse files
authored
Merge pull request #945 from HiEventsDev/develop
2 parents 275a52c + e33a196 commit 8ef889b

File tree

167 files changed

+14340
-2914
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

167 files changed

+14340
-2914
lines changed
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
<?php
2+
3+
namespace HiEvents\Console\Commands;
4+
5+
use HiEvents\DomainObjects\Generated\StripePaymentDomainObjectAbstract;
6+
use HiEvents\DomainObjects\OrderDomainObject;
7+
use HiEvents\DomainObjects\StripePaymentDomainObject;
8+
use HiEvents\Repository\Eloquent\StripePaymentsRepository;
9+
use HiEvents\Repository\Eloquent\Value\Relationship;
10+
use HiEvents\Repository\Interfaces\OrderPaymentPlatformFeeRepositoryInterface;
11+
use HiEvents\Services\Domain\Payment\Stripe\StripePaymentPlatformFeeExtractionService;
12+
use HiEvents\Services\Infrastructure\Stripe\StripeClientFactory;
13+
use Illuminate\Console\Command;
14+
use Throwable;
15+
16+
class BackfillPlatformFeesCommand extends Command
17+
{
18+
protected $signature = 'stripe:backfill-platform-fees
19+
{--payout-id= : Only backfill for specific payout ID}
20+
{--limit=100 : Maximum number of payments to process}
21+
{--dry-run : Show what would be done without actually doing it}';
22+
23+
protected $description = 'Backfill missing order_payment_platform_fees records from Stripe API';
24+
25+
public function __construct(
26+
private readonly StripePaymentsRepository $stripePaymentsRepository,
27+
private readonly OrderPaymentPlatformFeeRepositoryInterface $orderPaymentPlatformFeeRepository,
28+
private readonly StripePaymentPlatformFeeExtractionService $platformFeeExtractionService,
29+
private readonly StripeClientFactory $stripeClientFactory,
30+
)
31+
{
32+
parent::__construct();
33+
}
34+
35+
public function handle(): int
36+
{
37+
$this->info('Starting platform fees backfill...');
38+
39+
$payoutId = $this->option('payout-id');
40+
$limit = (int)$this->option('limit');
41+
$dryRun = $this->option('dry-run');
42+
43+
if ($dryRun) {
44+
$this->warn('DRY RUN MODE - No changes will be made');
45+
}
46+
47+
// Find stripe_payments that have payout_id
48+
$where = [];
49+
50+
if ($payoutId) {
51+
$where[StripePaymentDomainObjectAbstract::PAYOUT_ID] = $payoutId;
52+
$this->info("Filtering by payout ID: {$payoutId}");
53+
}
54+
55+
// Get all payments (or filtered by payout_id)
56+
$allPayments = $this->stripePaymentsRepository
57+
->loadRelation(new Relationship(OrderDomainObject::class, name: 'order'))
58+
->findWhere($payoutId ? $where : []);
59+
60+
// Filter to only those without platform fees and with charge_id
61+
$stripePayments = $allPayments->filter(function ($payment) {
62+
/** @var StripePaymentDomainObject $payment */
63+
64+
// Must have charge_id and payout_id
65+
if (!$payment->getChargeId() || !$payment->getPayoutId()) {
66+
return false;
67+
}
68+
69+
$order = $payment->getOrder();
70+
if (!$order) {
71+
return false;
72+
}
73+
74+
// Check if platform fee already exists for this order using count
75+
$existsCount = $this->orderPaymentPlatformFeeRepository->countWhere([
76+
'order_id' => $order->getId(),
77+
]);
78+
79+
return $existsCount === 0;
80+
})->take($limit);
81+
82+
if ($stripePayments->isEmpty()) {
83+
$this->info('No stripe payments found that need platform fee backfill.');
84+
return self::SUCCESS;
85+
}
86+
87+
$this->info("Found {$stripePayments->count()} payments to process");
88+
89+
$progressBar = $this->output->createProgressBar($stripePayments->count());
90+
$progressBar->start();
91+
92+
$successCount = 0;
93+
$errorCount = 0;
94+
$skippedCount = 0;
95+
96+
foreach ($stripePayments as $stripePayment) {
97+
/** @var StripePaymentDomainObject $stripePayment */
98+
$order = $stripePayment->getOrder();
99+
100+
if (!$order) {
101+
$this->newLine();
102+
$this->warn("Order not found for stripe_payment ID: {$stripePayment->getId()}");
103+
$skippedCount++;
104+
$progressBar->advance();
105+
continue;
106+
}
107+
108+
try {
109+
if (!$dryRun) {
110+
// Fetch charge from Stripe with expanded balance_transaction
111+
$stripeClient = $this->stripeClientFactory->createForPlatform(
112+
$stripePayment->getStripePlatformEnum()
113+
);
114+
115+
$params = ['expand' => ['balance_transaction']];
116+
$opts = [];
117+
118+
if ($stripePayment->getConnectedAccountId()) {
119+
$opts['stripe_account'] = $stripePayment->getConnectedAccountId();
120+
}
121+
122+
$charge = $stripeClient->charges->retrieve(
123+
$stripePayment->getChargeId(),
124+
$params,
125+
$opts
126+
);
127+
128+
$this->platformFeeExtractionService->extractAndStorePlatformFee(
129+
order: $order,
130+
charge: $charge,
131+
stripePayment: $stripePayment
132+
);
133+
134+
} else {
135+
$this->newLine();
136+
$this->line("Would process: Order #{$order->getId()}, Charge: {$stripePayment->getChargeId()}");
137+
}
138+
$successCount++;
139+
} catch (Throwable $exception) {
140+
$this->newLine();
141+
$this->error("Failed to process order #{$order->getId()}: {$exception->getMessage()}");
142+
$errorCount++;
143+
}
144+
145+
$progressBar->advance();
146+
}
147+
148+
$progressBar->finish();
149+
$this->newLine(2);
150+
151+
$this->info('Backfill complete!');
152+
$this->table(
153+
['Status', 'Count'],
154+
[
155+
['Success', $successCount],
156+
['Errors', $errorCount],
157+
['Skipped', $skippedCount],
158+
['Total', $stripePayments->count()],
159+
]
160+
);
161+
162+
return $errorCount > 0 ? self::FAILURE : self::SUCCESS;
163+
}
164+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace HiEvents\DataTransferObjects;
4+
5+
class UpdateAccountConfigurationDTO extends BaseDataObject
6+
{
7+
public function __construct(
8+
public readonly int $accountId,
9+
public readonly array $applicationFees,
10+
)
11+
{
12+
}
13+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace HiEvents\DataTransferObjects;
4+
5+
class UpdateAdminAccountVatSettingDTO extends BaseDataObject
6+
{
7+
public function __construct(
8+
public readonly int $accountId,
9+
public readonly bool $vatRegistered,
10+
public readonly ?string $vatNumber = null,
11+
public readonly ?bool $vatValidated = null,
12+
public readonly ?string $businessName = null,
13+
public readonly ?string $businessAddress = null,
14+
public readonly ?string $vatCountryCode = null,
15+
)
16+
{
17+
}
18+
}

backend/app/DomainObjects/AccountDomainObject.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ class AccountDomainObject extends Generated\AccountDomainObjectAbstract
1313
/** @var Collection<int, AccountStripePlatformDomainObject>|null */
1414
private ?Collection $stripePlatforms = null;
1515

16+
private ?AccountVatSettingDomainObject $accountVatSetting = null;
17+
1618
public function getApplicationFee(): AccountApplicationFeeDTO
1719
{
1820
/** @var AccountConfigurationDomainObject $applicationFee */
@@ -44,6 +46,16 @@ public function setAccountStripePlatforms(Collection $stripePlatforms): void
4446
$this->stripePlatforms = $stripePlatforms;
4547
}
4648

49+
public function getAccountVatSetting(): ?AccountVatSettingDomainObject
50+
{
51+
return $this->accountVatSetting;
52+
}
53+
54+
public function setAccountVatSetting(AccountVatSettingDomainObject $accountVatSetting): void
55+
{
56+
$this->accountVatSetting = $accountVatSetting;
57+
}
58+
4759
/**
4860
* Get the primary active Stripe platform for this account
4961
* Returns the platform with setup completed, preferring the most recent
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace HiEvents\DomainObjects;
4+
5+
class AccountVatSettingDomainObject extends Generated\AccountVatSettingDomainObjectAbstract
6+
{
7+
}

0 commit comments

Comments
 (0)