diff --git a/app/(dashboard)/settings/banking/page.tsx b/app/(dashboard)/settings/banking/page.tsx index e9b8b71c..21243a49 100644 --- a/app/(dashboard)/settings/banking/page.tsx +++ b/app/(dashboard)/settings/banking/page.tsx @@ -17,6 +17,8 @@ export default function BankingSettingsPage() { const router = useRouter() const { toast } = useToast() const [bankConnectionError, setBankConnectionError] = useState(null) + const [failedBankName, setFailedBankName] = useState(null) + const [isAccessDenied, setIsAccessDenied] = useState(false) const syncInitiatedRef = useRef(false) const abortControllerRef = useRef(null) const unmountedRef = useRef(false) @@ -93,13 +95,18 @@ export default function BankingSettingsPage() { } if (bankError) { - const errorMsg = decodeURIComponent(bankError) + let errorMsg: string + try { errorMsg = decodeURIComponent(bankError) } catch { errorMsg = bankError } + const bankName = searchParams.get('bank_name') + const errorCode = searchParams.get('bank_error_code') toast({ title: 'Anslutning misslyckades', description: errorMsg, variant: 'destructive', }) setBankConnectionError(errorMsg) + if (bankName) setFailedBankName(bankName) + if (errorCode === 'access_denied') setIsAccessDenied(true) router.replace('/settings/banking') } }, [searchParams, router, toast]) @@ -111,12 +118,21 @@ export default function BankingSettingsPage() {

{bankConnectionError}

+ {isAccessDenied && failedBankName && ( +

+ {failedBankName} nekade åtkomst. Om du använder ett privatkonto kan du prova att ansluta med kontotypen "Privatkonto" i bankväljaren nedan. +

+ )}

Du kan också importera transaktioner via bankfil istället.

+ + + + {psuType === 'personal' && ( +

+ Välj Privatkonto om du använder ditt personliga bankkonto för din verksamhet (vanligt för enskild firma). +

+ )} handleConnectBank(bank, psuType)} + onPsuTypeDetected={setPsuType} isConnecting={isConnecting} connectingBankName={connectingBankName} /> diff --git a/extensions/general/enable-banking/index.ts b/extensions/general/enable-banking/index.ts index aea7eba4..32f1f9bd 100644 --- a/extensions/general/enable-banking/index.ts +++ b/extensions/general/enable-banking/index.ts @@ -40,14 +40,27 @@ export const enableBankingExtension: Extension = { handler: async (_request: Request, ctx?: ExtensionContext) => { const log = ctx?.log ?? console try { - const aspsps = await getASPSPs('SE') + // Detect PSU type from company entity_type + let psuType: 'personal' | 'business' = 'business' + if (ctx?.companyId && ctx?.supabase) { + const { data: company } = await ctx.supabase + .from('companies') + .select('entity_type') + .eq('id', ctx.companyId) + .single() + if (company?.entity_type === 'enskild_firma') { + psuType = 'personal' + } + } + + const aspsps = await getASPSPs('SE', psuType) const banks = aspsps.map((aspsp: ASPSP) => ({ name: aspsp.name, country: aspsp.country, logo: aspsp.logo, bic: aspsp.bic, })) - return NextResponse.json({ banks, sandbox: isSandboxMode() }) + return NextResponse.json({ banks, psu_type: psuType, sandbox: isSandboxMode() }) } catch (error) { log.error('Error fetching banks:', error) return NextResponse.json({ @@ -74,7 +87,7 @@ export const enableBankingExtension: Extension = { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } - const { aspsp_name, aspsp_country } = await request.json() + const { aspsp_name, aspsp_country, psu_type: explicitPsuType } = await request.json() if (!aspsp_name || !aspsp_country) { return NextResponse.json( @@ -84,9 +97,21 @@ export const enableBankingExtension: Extension = { } try { - // Always use 'business' PSU type — gnubok is accounting software, - // users connect business accounts regardless of entity type (AB or EF) - const psuType = 'business' + // Detect PSU type: explicit override > company entity_type > default 'business' + let psuType: 'personal' | 'business' = 'business' + if (explicitPsuType === 'personal' || explicitPsuType === 'business') { + psuType = explicitPsuType + } else { + const companyId = ctx?.companyId ?? user.id + const { data: company } = await supabase + .from('companies') + .select('entity_type') + .eq('id', companyId) + .single() + if (company?.entity_type === 'enskild_firma') { + psuType = 'personal' + } + } log.info('[enable-banking] Starting bank connection', { user_id: user.id, diff --git a/extensions/general/enable-banking/lib/api-client.ts b/extensions/general/enable-banking/lib/api-client.ts index 02616d26..d6e2c0be 100644 --- a/extensions/general/enable-banking/lib/api-client.ts +++ b/extensions/general/enable-banking/lib/api-client.ts @@ -221,13 +221,13 @@ async function authenticatedFetchWithRetry( /** * Get list of supported banks (ASPSPs) for a country */ -export async function getASPSPs(country: string = 'SE'): Promise { - const psuType = process.env.ENABLE_BANKING_PSU_TYPE || 'business' +export async function getASPSPs(country: string = 'SE', psuType?: 'personal' | 'business'): Promise { + const resolvedPsuType = psuType || process.env.ENABLE_BANKING_PSU_TYPE || 'business' const isSandbox = ENABLE_BANKING_API_URL.includes('tilisy') const params = new URLSearchParams({ country, sandbox: String(isSandbox), - psu_type: psuType, + psu_type: resolvedPsuType, }) const response = await authenticatedFetchWithRetry(`/aspsps?${params.toString()}`) @@ -238,7 +238,7 @@ export async function getASPSPs(country: string = 'SE'): Promise { statusText: response.statusText, body, country, - psuType, + psuType: resolvedPsuType, sandbox: isSandbox, apiUrl: ENABLE_BANKING_API_URL, })