Skip to content

Commit a7a9555

Browse files
authored
feature: Allow bypassing application fee (#1002)
1 parent 0bcaed7 commit a7a9555

8 files changed

Lines changed: 61 additions & 3 deletions

File tree

backend/app/DomainObjects/Generated/AccountConfigurationDomainObjectAbstract.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ abstract class AccountConfigurationDomainObjectAbstract extends \HiEvents\Domain
1717
final public const CREATED_AT = 'created_at';
1818
final public const UPDATED_AT = 'updated_at';
1919
final public const DELETED_AT = 'deleted_at';
20+
final public const BYPASS_APPLICATION_FEES = 'bypass_application_fees';
2021

2122
protected int $id;
2223
protected string $name;
@@ -25,6 +26,7 @@ abstract class AccountConfigurationDomainObjectAbstract extends \HiEvents\Domain
2526
protected ?string $created_at = null;
2627
protected ?string $updated_at = null;
2728
protected ?string $deleted_at = null;
29+
protected bool $bypass_application_fees = false;
2830

2931
public function toArray(): array
3032
{
@@ -36,6 +38,7 @@ public function toArray(): array
3638
'created_at' => $this->created_at ?? null,
3739
'updated_at' => $this->updated_at ?? null,
3840
'deleted_at' => $this->deleted_at ?? null,
41+
'bypass_application_fees' => $this->bypass_application_fees ?? null,
3942
];
4043
}
4144

@@ -115,4 +118,15 @@ public function getDeletedAt(): ?string
115118
{
116119
return $this->deleted_at;
117120
}
121+
122+
public function setBypassApplicationFees(bool $bypass_application_fees): self
123+
{
124+
$this->bypass_application_fees = $bypass_application_fees;
125+
return $this;
126+
}
127+
128+
public function getBypassApplicationFees(): bool
129+
{
130+
return $this->bypass_application_fees;
131+
}
118132
}

backend/app/Http/Actions/Admin/Configurations/CreateConfigurationAction.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,14 @@ public function __invoke(Request $request): JsonResponse
2828
'application_fees' => 'required|array',
2929
'application_fees.fixed' => 'required|numeric|min:0',
3030
'application_fees.percentage' => 'required|numeric|min:0|max:100',
31+
'bypass_application_fees' => 'sometimes|boolean',
3132
]);
3233

3334
$configuration = $this->repository->create([
3435
'name' => $validated['name'],
3536
'is_system_default' => false,
3637
'application_fees' => $validated['application_fees'],
38+
'bypass_application_fees' => $validated['bypass_application_fees'] ?? false,
3739
]);
3840

3941
return $this->jsonResponse(

backend/app/Http/Actions/Admin/Configurations/UpdateConfigurationAction.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,15 @@ public function __invoke(Request $request, int $configurationId): JsonResponse
2727
'application_fees' => 'required|array',
2828
'application_fees.fixed' => 'required|numeric|min:0',
2929
'application_fees.percentage' => 'required|numeric|min:0|max:100',
30+
'bypass_application_fees' => 'sometimes|boolean',
3031
]);
3132

3233
$configuration = $this->repository->updateFromArray(
3334
id: $configurationId,
3435
attributes: [
3536
'name' => $validated['name'],
3637
'application_fees' => $validated['application_fees'],
38+
'bypass_application_fees' => $validated['bypass_application_fees'] ?? false,
3739
]
3840
);
3941

backend/app/Resources/Account/AccountConfigurationResource.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public function toArray($request): array
2020
'percentage' => $this->getPercentageApplicationFee(),
2121
'fixed' => $this->getFixedApplicationFee(),
2222
],
23+
'bypass_application_fees' => $this->getBypassApplicationFees(),
2324
];
2425
}
2526
}

backend/app/Services/Domain/Payment/Stripe/StripePaymentIntentCreationService.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,11 @@ public function createPaymentIntentWithClient(
6666
try {
6767
$this->databaseManager->beginTransaction();
6868

69+
$accountConfiguration = $paymentIntentDTO->account->getConfiguration();
70+
$bypassApplicationFees = $accountConfiguration?->getBypassApplicationFees() ?? false;
71+
6972
$applicationFee = $this->orderApplicationFeeCalculationService->calculateApplicationFee(
70-
accountConfiguration: $paymentIntentDTO->account->getConfiguration(),
73+
accountConfiguration: $accountConfiguration,
7174
order: $paymentIntentDTO->order,
7275
vatSettings: $paymentIntentDTO->vatSettings,
7376
);
@@ -80,7 +83,7 @@ public function createPaymentIntentWithClient(
8083
'automatic_payment_methods' => [
8184
'enabled' => true,
8285
],
83-
...($applicationFee ? ['application_fee_amount' => $applicationFee->grossApplicationFee->toMinorUnit()] : []),
86+
...($applicationFee && !$bypassApplicationFees ? ['application_fee_amount' => $applicationFee->grossApplicationFee->toMinorUnit()] : []),
8487
], $this->getStripeAccountData($paymentIntentDTO));
8588

8689
$this->logger->debug('Stripe payment intent created', [
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration {
8+
public function up(): void
9+
{
10+
Schema::table('account_configuration', function (Blueprint $table) {
11+
$table->boolean('bypass_application_fees')->default(false)->after('application_fees');
12+
});
13+
}
14+
15+
public function down(): void
16+
{
17+
Schema::table('account_configuration', function (Blueprint $table) {
18+
$table->dropColumn('bypass_application_fees');
19+
});
20+
}
21+
};

frontend/src/api/admin.client.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export interface AccountConfiguration {
5252
fixed: number;
5353
percentage: number;
5454
};
55+
bypass_application_fees: boolean;
5556
}
5657

5758
export interface CreateConfigurationData {
@@ -60,6 +61,7 @@ export interface CreateConfigurationData {
6061
fixed: number;
6162
percentage: number;
6263
};
64+
bypass_application_fees?: boolean;
6365
}
6466

6567
export interface UpdateConfigurationData {
@@ -68,6 +70,7 @@ export interface UpdateConfigurationData {
6870
fixed: number;
6971
percentage: number;
7072
};
73+
bypass_application_fees?: boolean;
7174
}
7275

7376
export interface AssignConfigurationData {

frontend/src/components/routes/admin/Configurations/index.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Container, Title, Stack, Card, Text, Group, Button, Badge, ActionIcon, Alert, NumberInput, TextInput, Skeleton} from "@mantine/core";
1+
import {Container, Title, Stack, Card, Text, Group, Button, Badge, ActionIcon, Alert, NumberInput, TextInput, Skeleton, Switch} from "@mantine/core";
22
import {t} from "@lingui/macro";
33
import {useGetAllConfigurations} from "../../../../queries/useGetAllConfigurations";
44
import {useCreateConfiguration} from "../../../../mutations/useCreateConfiguration";
@@ -16,6 +16,7 @@ interface ConfigurationFormValues {
1616
name: string;
1717
fixed_fee: number;
1818
percentage_fee: number;
19+
bypass_application_fees: boolean;
1920
}
2021

2122
const Configurations = () => {
@@ -80,6 +81,9 @@ const Configurations = () => {
8081
{config.is_system_default && (
8182
<Badge color="blue" size="sm">{t`System Default`}</Badge>
8283
)}
84+
{config.bypass_application_fees && (
85+
<Badge color="orange" size="sm">{t`Fees Bypassed`}</Badge>
86+
)}
8387
</Group>
8488
<Group gap="xl">
8589
<div>
@@ -150,6 +154,7 @@ const ConfigurationModal = ({configuration, onClose}: ConfigurationModalProps) =
150154
name: configuration?.name || '',
151155
fixed_fee: configuration?.application_fees?.fixed || 0,
152156
percentage_fee: configuration?.application_fees?.percentage || 0,
157+
bypass_application_fees: configuration?.bypass_application_fees || false,
153158
},
154159
validate: {
155160
name: (value) => {
@@ -172,6 +177,7 @@ const ConfigurationModal = ({configuration, onClose}: ConfigurationModalProps) =
172177
fixed: values.fixed_fee,
173178
percentage: values.percentage_fee,
174179
},
180+
bypass_application_fees: values.bypass_application_fees,
175181
};
176182

177183
const mutation = isEditing ? updateMutation : createMutation;
@@ -232,6 +238,12 @@ const ConfigurationModal = ({configuration, onClose}: ConfigurationModalProps) =
232238
{...form.getInputProps('percentage_fee')}
233239
/>
234240

241+
<Switch
242+
label={t`Bypass Application Fees`}
243+
description={t`When enabled, no application fees will be charged on Stripe Connect transactions. Use this for countries where application fees are not supported.`}
244+
{...form.getInputProps('bypass_application_fees', { type: 'checkbox' })}
245+
/>
246+
235247
<Button
236248
fullWidth
237249
loading={createMutation.isPending || updateMutation.isPending}

0 commit comments

Comments
 (0)