feat: dynamic tax thresholds from backend (#5342)
* feat: dynamic tax thresholds from backend * fix: lint & i18n
This commit is contained in:
@@ -1,11 +1,18 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { FileTextIcon } from '@modrinth/assets'
|
import { FileTextIcon } from '@modrinth/assets'
|
||||||
import { ButtonStyled, defineMessages, PagewideBanner, useVIntl } from '@modrinth/ui'
|
import { ButtonStyled, defineMessages, PagewideBanner, useVIntl } from '@modrinth/ui'
|
||||||
|
import { formatMoney } from '@modrinth/utils'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
import { getTaxThreshold } from '@/providers/creator-withdraw.ts'
|
||||||
import CreatorTaxFormModal from '~/components/ui/dashboard/CreatorTaxFormModal.vue'
|
import CreatorTaxFormModal from '~/components/ui/dashboard/CreatorTaxFormModal.vue'
|
||||||
|
import { useGeneratedState } from '~/composables/generated'
|
||||||
|
|
||||||
const { formatMessage } = useVIntl()
|
const { formatMessage } = useVIntl()
|
||||||
|
|
||||||
|
const generatedState = useGeneratedState()
|
||||||
|
const taxThreshold = computed(() => getTaxThreshold(generatedState.value?.taxComplianceThresholds))
|
||||||
|
|
||||||
const modal = useTemplateRef('modal')
|
const modal = useTemplateRef('modal')
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
@@ -16,7 +23,7 @@ const messages = defineMessages({
|
|||||||
description: {
|
description: {
|
||||||
id: 'layout.banner.tax.description',
|
id: 'layout.banner.tax.description',
|
||||||
defaultMessage:
|
defaultMessage:
|
||||||
"You've already withdrawn over $600 from Modrinth this year. To comply with tax regulations, you need to complete a tax form. Your withdrawals are paused until this form is submitted.",
|
"You've already withdrawn over {threshold} from Modrinth this year. To comply with tax regulations, you need to complete a tax form. Your withdrawals are paused until this form is submitted.",
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
id: 'layout.banner.tax.action',
|
id: 'layout.banner.tax.action',
|
||||||
@@ -38,7 +45,9 @@ function openTaxForm(e: MouseEvent) {
|
|||||||
<span>{{ formatMessage(messages.title) }}</span>
|
<span>{{ formatMessage(messages.title) }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #description>
|
<template #description>
|
||||||
<span>{{ formatMessage(messages.description) }}</span>
|
<span>{{
|
||||||
|
formatMessage(messages.description, { threshold: formatMoney(taxThreshold) })
|
||||||
|
}}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<ButtonStyled color="orange">
|
<ButtonStyled color="orange">
|
||||||
|
|||||||
@@ -128,12 +128,14 @@ import { computed, nextTick, onMounted, ref, useTemplateRef, watch } from 'vue'
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
createWithdrawContext,
|
createWithdrawContext,
|
||||||
|
getTaxThreshold,
|
||||||
|
getTaxThresholdActual,
|
||||||
type PaymentProvider,
|
type PaymentProvider,
|
||||||
type PayoutMethod,
|
type PayoutMethod,
|
||||||
provideWithdrawContext,
|
provideWithdrawContext,
|
||||||
TAX_THRESHOLD_ACTUAL,
|
|
||||||
type WithdrawStage,
|
type WithdrawStage,
|
||||||
} from '@/providers/creator-withdraw.ts'
|
} from '@/providers/creator-withdraw.ts'
|
||||||
|
import { useGeneratedState } from '~/composables/generated'
|
||||||
|
|
||||||
import CreatorTaxFormModal from './CreatorTaxFormModal.vue'
|
import CreatorTaxFormModal from './CreatorTaxFormModal.vue'
|
||||||
import CompletionStage from './withdraw-stages/CompletionStage.vue'
|
import CompletionStage from './withdraw-stages/CompletionStage.vue'
|
||||||
@@ -191,9 +193,13 @@ defineExpose({
|
|||||||
const { formatMessage } = useVIntl()
|
const { formatMessage } = useVIntl()
|
||||||
const { addNotification } = injectNotificationManager()
|
const { addNotification } = injectNotificationManager()
|
||||||
|
|
||||||
|
const generatedState = useGeneratedState()
|
||||||
|
const taxComplianceThresholds = computed(() => generatedState.value.taxComplianceThresholds)
|
||||||
|
|
||||||
const withdrawContext = createWithdrawContext(
|
const withdrawContext = createWithdrawContext(
|
||||||
props.balance,
|
props.balance,
|
||||||
props.preloadedPaymentData || undefined,
|
props.preloadedPaymentData || undefined,
|
||||||
|
taxComplianceThresholds.value,
|
||||||
)
|
)
|
||||||
provideWithdrawContext(withdrawContext)
|
provideWithdrawContext(withdrawContext)
|
||||||
|
|
||||||
@@ -249,13 +255,13 @@ const needsTaxForm = computed(() => {
|
|||||||
const ytd = props.balance.withdrawn_ytd ?? 0
|
const ytd = props.balance.withdrawn_ytd ?? 0
|
||||||
const available = props.balance.available ?? 0
|
const available = props.balance.available ?? 0
|
||||||
const status = props.balance.form_completion_status
|
const status = props.balance.form_completion_status
|
||||||
return status !== 'complete' && ytd + available >= 600
|
return status !== 'complete' && ytd + available >= getTaxThreshold(taxComplianceThresholds.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
const remainingLimit = computed(() => {
|
const remainingLimit = computed(() => {
|
||||||
if (!props.balance) return 0
|
if (!props.balance) return 0
|
||||||
const ytd = props.balance.withdrawn_ytd ?? 0
|
const ytd = props.balance.withdrawn_ytd ?? 0
|
||||||
const raw = TAX_THRESHOLD_ACTUAL - ytd
|
const raw = getTaxThresholdActual(taxComplianceThresholds.value) - ytd
|
||||||
if (raw <= 0) return 0
|
if (raw <= 0) return 0
|
||||||
const cents = Math.floor(raw * 100)
|
const cents = Math.floor(raw * 100)
|
||||||
return cents / 100
|
return cents / 100
|
||||||
|
|||||||
@@ -94,8 +94,14 @@ import { formatMoney } from '@modrinth/utils'
|
|||||||
import { useGeolocation } from '@vueuse/core'
|
import { useGeolocation } from '@vueuse/core'
|
||||||
|
|
||||||
import { useCountries, useFormattedCountries, useUserCountry } from '@/composables/country.ts'
|
import { useCountries, useFormattedCountries, useUserCountry } from '@/composables/country.ts'
|
||||||
import { type PayoutMethod, useWithdrawContext } from '@/providers/creator-withdraw.ts'
|
import {
|
||||||
|
getTaxThreshold,
|
||||||
|
type PayoutMethod,
|
||||||
|
useWithdrawContext,
|
||||||
|
} from '@/providers/creator-withdraw.ts'
|
||||||
|
import { useGeneratedState } from '~/composables/generated'
|
||||||
|
|
||||||
|
const generatedState = useGeneratedState()
|
||||||
const debug = useDebugLogger('MethodSelectionStage')
|
const debug = useDebugLogger('MethodSelectionStage')
|
||||||
const {
|
const {
|
||||||
withdrawData,
|
withdrawData,
|
||||||
@@ -165,7 +171,9 @@ const shouldShowTaxLimitWarning = computed(() => {
|
|||||||
if (!balanceValue) return false
|
if (!balanceValue) return false
|
||||||
|
|
||||||
const formIncomplete = balanceValue.form_completion_status !== 'complete'
|
const formIncomplete = balanceValue.form_completion_status !== 'complete'
|
||||||
const wouldHitLimit = (balanceValue.withdrawn_ytd ?? 0) + (balanceValue.available ?? 0) >= 600
|
const wouldHitLimit =
|
||||||
|
(balanceValue.withdrawn_ytd ?? 0) + (balanceValue.available ?? 0) >=
|
||||||
|
getTaxThreshold(generatedState.value.taxComplianceThresholds)
|
||||||
|
|
||||||
return formIncomplete && wouldHitLimit
|
return formIncomplete && wouldHitLimit
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,14 +5,14 @@
|
|||||||
<span class="font-semibold text-contrast">{{ formatMessage(messages.withdrawLimit) }}</span>
|
<span class="font-semibold text-contrast">{{ formatMessage(messages.withdrawLimit) }}</span>
|
||||||
<div>
|
<div>
|
||||||
<span class="text-orange">{{ formatMoney(usedLimit) }}</span> /
|
<span class="text-orange">{{ formatMoney(usedLimit) }}</span> /
|
||||||
<span class="text-contrast">{{ formatMoney(600) }}</span>
|
<span class="text-contrast">{{ formatMoney(taxThreshold) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex h-2.5 w-full overflow-hidden rounded-full bg-surface-2">
|
<div class="flex h-2.5 w-full overflow-hidden rounded-full bg-surface-2">
|
||||||
<div
|
<div
|
||||||
v-if="usedLimit > 0"
|
v-if="usedLimit > 0"
|
||||||
class="gradient-border bg-orange"
|
class="gradient-border bg-orange"
|
||||||
:style="{ width: `${(usedLimit / 600) * 100}%` }"
|
:style="{ width: `${(usedLimit / taxThreshold) * 100}%` }"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
<span>
|
<span>
|
||||||
<IntlFormatted
|
<IntlFormatted
|
||||||
:message-id="messages.withdrawLimitUsed"
|
:message-id="messages.withdrawLimitUsed"
|
||||||
:values="{ withdrawLimit: formatMoney(600) }"
|
:values="{ withdrawLimit: formatMoney(taxThreshold) }"
|
||||||
>
|
>
|
||||||
<template #b="{ children }">
|
<template #b="{ children }">
|
||||||
<b>
|
<b>
|
||||||
@@ -85,7 +85,8 @@ import {
|
|||||||
import { formatMoney } from '@modrinth/utils'
|
import { formatMoney } from '@modrinth/utils'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
import { TAX_THRESHOLD_ACTUAL } from '@/providers/creator-withdraw.ts'
|
import { getTaxThreshold, getTaxThresholdActual } from '@/providers/creator-withdraw.ts'
|
||||||
|
import { useGeneratedState } from '~/composables/generated'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
balance: any
|
balance: any
|
||||||
@@ -94,9 +95,15 @@ const props = defineProps<{
|
|||||||
|
|
||||||
const { formatMessage } = useVIntl()
|
const { formatMessage } = useVIntl()
|
||||||
|
|
||||||
|
const generatedState = useGeneratedState()
|
||||||
|
const taxThreshold = computed(() => getTaxThreshold(generatedState.value.taxComplianceThresholds))
|
||||||
|
const taxThresholdActual = computed(() =>
|
||||||
|
getTaxThresholdActual(generatedState.value.taxComplianceThresholds),
|
||||||
|
)
|
||||||
|
|
||||||
const usedLimit = computed(() => props.balance?.withdrawn_ytd ?? 0)
|
const usedLimit = computed(() => props.balance?.withdrawn_ytd ?? 0)
|
||||||
const remainingLimit = computed(() => {
|
const remainingLimit = computed(() => {
|
||||||
const raw = TAX_THRESHOLD_ACTUAL - usedLimit.value
|
const raw = taxThresholdActual.value - usedLimit.value
|
||||||
if (raw <= 0) return 0
|
if (raw <= 0) return 0
|
||||||
const cents = Math.floor(raw * 100)
|
const cents = Math.floor(raw * 100)
|
||||||
return cents / 100
|
return cents / 100
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export interface GeneratedState extends Labrinth.State.GeneratedState {
|
|||||||
approvedStatuses: string[]
|
approvedStatuses: string[]
|
||||||
rejectedStatuses: string[]
|
rejectedStatuses: string[]
|
||||||
staffRoles: string[]
|
staffRoles: string[]
|
||||||
|
taxComplianceThresholds?: Record<string, number>
|
||||||
|
|
||||||
// Metadata
|
// Metadata
|
||||||
lastGenerated?: string
|
lastGenerated?: string
|
||||||
@@ -121,6 +122,10 @@ export const useGeneratedState = () =>
|
|||||||
homePageSearch: generatedState.homePageSearch as Labrinth.Search.v2.SearchResults | undefined,
|
homePageSearch: generatedState.homePageSearch as Labrinth.Search.v2.SearchResults | undefined,
|
||||||
homePageNotifs: generatedState.homePageNotifs as Labrinth.Search.v2.SearchResults | undefined,
|
homePageNotifs: generatedState.homePageNotifs as Labrinth.Search.v2.SearchResults | undefined,
|
||||||
products: generatedState.products as Labrinth.Billing.Internal.Product[] | undefined,
|
products: generatedState.products as Labrinth.Billing.Internal.Product[] | undefined,
|
||||||
|
taxComplianceThresholds: (generatedState.taxComplianceThresholds ?? {}) as Record<
|
||||||
|
string,
|
||||||
|
number
|
||||||
|
>,
|
||||||
|
|
||||||
lastGenerated: generatedState.lastGenerated,
|
lastGenerated: generatedState.lastGenerated,
|
||||||
apiUrl: generatedState.apiUrl,
|
apiUrl: generatedState.apiUrl,
|
||||||
|
|||||||
@@ -721,6 +721,7 @@ import {
|
|||||||
} from '@modrinth/ui'
|
} from '@modrinth/ui'
|
||||||
import { isAdmin, isStaff, UserBadge } from '@modrinth/utils'
|
import { isAdmin, isStaff, UserBadge } from '@modrinth/utils'
|
||||||
|
|
||||||
|
import { getTaxThreshold } from '@/providers/creator-withdraw.ts'
|
||||||
import TextLogo from '~/components/brand/TextLogo.vue'
|
import TextLogo from '~/components/brand/TextLogo.vue'
|
||||||
import BatchCreditModal from '~/components/ui/admin/BatchCreditModal.vue'
|
import BatchCreditModal from '~/components/ui/admin/BatchCreditModal.vue'
|
||||||
import GeneratedStateErrorsBanner from '~/components/ui/banner/GeneratedStateErrorsBanner.vue'
|
import GeneratedStateErrorsBanner from '~/components/ui/banner/GeneratedStateErrorsBanner.vue'
|
||||||
@@ -739,6 +740,8 @@ import TeleportOverflowMenu from '~/components/ui/servers/TeleportOverflowMenu.v
|
|||||||
import { errors as generatedStateErrors } from '~/generated/state.json'
|
import { errors as generatedStateErrors } from '~/generated/state.json'
|
||||||
import { getProjectTypeMessage } from '~/utils/i18n-project-type.ts'
|
import { getProjectTypeMessage } from '~/utils/i18n-project-type.ts'
|
||||||
|
|
||||||
|
const generatedState = useGeneratedState()
|
||||||
|
|
||||||
const country = useUserCountry()
|
const country = useUserCountry()
|
||||||
|
|
||||||
const { formatMessage } = useVIntl()
|
const { formatMessage } = useVIntl()
|
||||||
@@ -763,7 +766,8 @@ const showTaxComplianceBanner = computed(() => {
|
|||||||
if (flags.value.testTaxForm && auth.value.user) return true
|
if (flags.value.testTaxForm && auth.value.user) return true
|
||||||
const bal = payoutBalance.value
|
const bal = payoutBalance.value
|
||||||
if (!bal) return false
|
if (!bal) return false
|
||||||
const thresholdMet = (bal.withdrawn_ytd ?? 0) >= 600
|
const threshold = getTaxThreshold(generatedState.value?.taxComplianceThresholds)
|
||||||
|
const thresholdMet = (bal.withdrawn_ytd ?? 0) >= threshold
|
||||||
const status = bal.form_completion_status ?? 'unknown'
|
const status = bal.form_completion_status ?? 'unknown'
|
||||||
const isComplete = status === 'complete'
|
const isComplete = status === 'complete'
|
||||||
const isTinMismatch = status === 'tin-mismatch'
|
const isTinMismatch = status === 'tin-mismatch'
|
||||||
|
|||||||
@@ -1485,7 +1485,7 @@
|
|||||||
"message": "Complete tax form"
|
"message": "Complete tax form"
|
||||||
},
|
},
|
||||||
"layout.banner.tax.description": {
|
"layout.banner.tax.description": {
|
||||||
"message": "You've already withdrawn over $600 from Modrinth this year. To comply with tax regulations, you need to complete a tax form. Your withdrawals are paused until this form is submitted."
|
"message": "You've already withdrawn over {threshold} from Modrinth this year. To comply with tax regulations, you need to complete a tax form. Your withdrawals are paused until this form is submitted."
|
||||||
},
|
},
|
||||||
"layout.banner.tax.title": {
|
"layout.banner.tax.title": {
|
||||||
"message": "Tax form required"
|
"message": "Tax form required"
|
||||||
|
|||||||
@@ -12,10 +12,20 @@ import { type Component, computed, type ComputedRef, type Ref, ref } from 'vue'
|
|||||||
|
|
||||||
import { getRailConfig } from '@/utils/muralpay-rails'
|
import { getRailConfig } from '@/utils/muralpay-rails'
|
||||||
|
|
||||||
// Tax form is required when withdrawn_ytd >= $600
|
export function getTaxThreshold(thresholds: Record<string, number> | undefined): number {
|
||||||
// Therefore, the maximum withdrawal without a tax form is $599.99
|
if (!thresholds || Object.keys(thresholds).length === 0) return 600
|
||||||
export const TAX_THRESHOLD_REQUIREMENT = 600
|
const currentYear = new Date().getFullYear()
|
||||||
export const TAX_THRESHOLD_ACTUAL = 599.99
|
const years = Object.keys(thresholds)
|
||||||
|
.map(Number)
|
||||||
|
.sort((a, b) => a - b)
|
||||||
|
if (currentYear <= years[0]) return thresholds[String(years[0])]
|
||||||
|
if (currentYear >= years[years.length - 1]) return thresholds[String(years[years.length - 1])]
|
||||||
|
return thresholds[String(currentYear)] ?? thresholds[String(years[years.length - 1])]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTaxThresholdActual(thresholds: Record<string, number> | undefined): number {
|
||||||
|
return getTaxThreshold(thresholds) - 0.01
|
||||||
|
}
|
||||||
|
|
||||||
export type WithdrawStage =
|
export type WithdrawStage =
|
||||||
| 'tax-form'
|
| 'tax-form'
|
||||||
@@ -379,6 +389,7 @@ const STATE_EXPIRY_MS = 15 * 60 * 1000 // 15 minutes
|
|||||||
export function createWithdrawContext(
|
export function createWithdrawContext(
|
||||||
balance: any,
|
balance: any,
|
||||||
preloadedPaymentData?: { country: string; methods: PayoutMethod[] },
|
preloadedPaymentData?: { country: string; methods: PayoutMethod[] },
|
||||||
|
taxComplianceThresholds?: Record<string, number>,
|
||||||
): WithdrawContextValue {
|
): WithdrawContextValue {
|
||||||
const debug = useDebugLogger('CreatorWithdraw')
|
const debug = useDebugLogger('CreatorWithdraw')
|
||||||
const currentStage = ref<WithdrawStage | undefined>()
|
const currentStage = ref<WithdrawStage | undefined>()
|
||||||
@@ -422,14 +433,18 @@ export function createWithdrawContext(
|
|||||||
const available = balance?.available ?? 0
|
const available = balance?.available ?? 0
|
||||||
|
|
||||||
const needsTaxForm =
|
const needsTaxForm =
|
||||||
balance?.form_completion_status !== 'complete' && usedLimit + available >= 600
|
balance?.form_completion_status !== 'complete' &&
|
||||||
|
usedLimit + available >= getTaxThreshold(taxComplianceThresholds)
|
||||||
|
|
||||||
|
const threshold = getTaxThreshold(taxComplianceThresholds)
|
||||||
debug('Tax form check:', {
|
debug('Tax form check:', {
|
||||||
usedLimit,
|
usedLimit,
|
||||||
available,
|
available,
|
||||||
total: usedLimit + available,
|
total: usedLimit + available,
|
||||||
status: balance?.form_completion_status,
|
status: balance?.form_completion_status,
|
||||||
needsTaxForm,
|
needsTaxForm,
|
||||||
|
taxThreshold: threshold,
|
||||||
|
taxComplianceFilled: `${((usedLimit / threshold) * 100).toFixed(1)}%`,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (needsTaxForm) {
|
if (needsTaxForm) {
|
||||||
@@ -462,7 +477,7 @@ export function createWithdrawContext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const usedLimit = balance?.withdrawn_ytd ?? 0
|
const usedLimit = balance?.withdrawn_ytd ?? 0
|
||||||
const remainingLimit = Math.max(0, TAX_THRESHOLD_ACTUAL - usedLimit)
|
const remainingLimit = Math.max(0, getTaxThresholdActual(taxComplianceThresholds) - usedLimit)
|
||||||
return Math.max(0, Math.min(remainingLimit, availableBalance))
|
return Math.max(0, Math.min(remainingLimit, availableBalance))
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -627,9 +642,9 @@ export function createWithdrawContext(
|
|||||||
case 'tax-form': {
|
case 'tax-form': {
|
||||||
if (!balanceRef.value) return true
|
if (!balanceRef.value) return true
|
||||||
const ytd = balanceRef.value.withdrawn_ytd ?? 0
|
const ytd = balanceRef.value.withdrawn_ytd ?? 0
|
||||||
const remainingLimit = Math.max(0, TAX_THRESHOLD_ACTUAL - ytd)
|
const remainingLimit = Math.max(0, getTaxThresholdActual(taxComplianceThresholds) - ytd)
|
||||||
const form_completion_status = balanceRef.value.form_completion_status
|
const form_completion_status = balanceRef.value.form_completion_status
|
||||||
if (ytd < 600) return true
|
if (ytd < getTaxThreshold(taxComplianceThresholds)) return true
|
||||||
if (withdrawData.value.tax.skipped && remainingLimit > 0) return true
|
if (withdrawData.value.tax.skipped && remainingLimit > 0) return true
|
||||||
return form_completion_status === 'complete'
|
return form_completion_status === 'complete'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export class LabrinthStateModule extends AbstractModule {
|
|||||||
muralBankDetails,
|
muralBankDetails,
|
||||||
iso3166Data,
|
iso3166Data,
|
||||||
payoutMethods,
|
payoutMethods,
|
||||||
|
globals,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
// Tag endpoints
|
// Tag endpoints
|
||||||
this.client
|
this.client
|
||||||
@@ -126,6 +127,15 @@ export class LabrinthStateModule extends AbstractModule {
|
|||||||
method: 'GET',
|
method: 'GET',
|
||||||
})
|
})
|
||||||
.catch((err) => handleError(err, [], '/v3/payout/methods')),
|
.catch((err) => handleError(err, [], '/v3/payout/methods')),
|
||||||
|
|
||||||
|
// Global configuration
|
||||||
|
this.client
|
||||||
|
.request<{ tax_compliance_thresholds: Record<string, number> }>('/globals', {
|
||||||
|
api: 'labrinth',
|
||||||
|
version: 'internal',
|
||||||
|
method: 'GET',
|
||||||
|
})
|
||||||
|
.catch((err) => handleError(err, null, '/_internal/globals')),
|
||||||
])
|
])
|
||||||
|
|
||||||
const tremendousIdMap = Object.fromEntries(
|
const tremendousIdMap = Object.fromEntries(
|
||||||
@@ -148,6 +158,7 @@ export class LabrinthStateModule extends AbstractModule {
|
|||||||
tremendousIdMap,
|
tremendousIdMap,
|
||||||
countries: iso3166Data.countries,
|
countries: iso3166Data.countries,
|
||||||
subdivisions: iso3166Data.subdivisions,
|
subdivisions: iso3166Data.subdivisions,
|
||||||
|
taxComplianceThresholds: globals?.tax_compliance_thresholds,
|
||||||
errors,
|
errors,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -782,6 +782,8 @@ export namespace Labrinth {
|
|||||||
countries: ISO3166.Country[]
|
countries: ISO3166.Country[]
|
||||||
subdivisions: Record<string, ISO3166.Subdivision[]>
|
subdivisions: Record<string, ISO3166.Subdivision[]>
|
||||||
|
|
||||||
|
taxComplianceThresholds?: Record<string, number>
|
||||||
|
|
||||||
errors: unknown[]
|
errors: unknown[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user