diff --git a/components/parties/RegistryAutofillNote.tsx b/components/parties/RegistryAutofillNote.tsx
new file mode 100644
index 00000000..64b47820
--- /dev/null
+++ b/components/parties/RegistryAutofillNote.tsx
@@ -0,0 +1,53 @@
+'use client'
+
+import { useTranslations } from 'next-intl'
+import { describeFilledFields } from '@/lib/parties/registry-form-fill'
+import { listSv } from '@/lib/parties/registry-summary'
+import { formatOrgNumber } from '@/lib/utils'
+import type { RegistryAutofillState } from './use-registry-autofill'
+
+/**
+ * The one line under the org number field that says what the register
+ * did: looking, "Webhallen Sverige AB · namn och adress från SCB", found
+ * but nothing to fill, or no such company. Nothing while idle, which is
+ * also what an environment without SCB shows.
+ */
+export function RegistryAutofillNote({ state }: { state: RegistryAutofillState }) {
+ const t = useTranslations('parties')
+ if (state.status === 'idle') return null
+ let text: string
+ switch (state.status) {
+ case 'looking':
+ text = t('autofill_looking')
+ break
+ case 'not_found':
+ text = t('autofill_not_found', { org: formatOrgNumber(state.orgNumber) })
+ break
+ case 'found':
+ text = t('autofill_found', { name: state.name })
+ break
+ case 'filled': {
+ const labels = describeFilledFields(state.fields).map((f) => {
+ switch (f) {
+ case 'name':
+ return t('autofill_field_name')
+ case 'address':
+ return t('facts_address_short')
+ case 'email':
+ return t('autofill_field_email')
+ case 'phone':
+ return t('autofill_field_phone')
+ case 'vat_number':
+ return t('autofill_field_vat')
+ }
+ })
+ text = t('autofill_filled', { name: state.name, fields: listSv(labels, t('facts_list_and')) })
+ break
+ }
+ }
+ return (
+
+ {text}
+
+ )
+}
diff --git a/components/parties/use-registry-autofill.ts b/components/parties/use-registry-autofill.ts
new file mode 100644
index 00000000..790dea42
--- /dev/null
+++ b/components/parties/use-registry-autofill.ts
@@ -0,0 +1,104 @@
+'use client'
+
+import { useEffect, useRef, useState } from 'react'
+import { registryLookupKey, type RegistryLookup, type RegistryLookupFound } from '@/lib/parties/registry-form-fill'
+
+export type RegistryAutofillState =
+ | { status: 'idle' }
+ | { status: 'looking' }
+ /** A company was found and these form fields were set from it. */
+ | { status: 'filled'; name: string; fields: string[] }
+ /** A company was found but every field it knows was already typed. */
+ | { status: 'found'; name: string }
+ | { status: 'not_found'; orgNumber: string }
+
+const DEBOUNCE_MS = 400
+
+/**
+ * Looks a typed org number up in the register once it is complete and
+ * valid, and hands a found company to `apply`. One lookup per distinct
+ * number per form (answers are kept, so retyping a number costs nothing),
+ * none for the number the form opened with (an edit dialog must not fetch
+ * on open), none for a personnummer, and none at all once the environment
+ * has said it has no SCB credentials (503). A failed lookup leaves the form
+ * as it is: no toast, no spinner, the person keeps typing.
+ */
+export function useRegistryAutofill({
+ orgNumber,
+ enabled,
+ initialOrgNumber,
+ apply,
+}: {
+ /** The org number field as typed. */
+ orgNumber: string | null | undefined
+ /** False while the row is not a Swedish company, or the person cannot write. */
+ enabled: boolean
+ /** The value the form opened with: only a change from it triggers a lookup. */
+ initialOrgNumber?: string | null
+ /** Sets form fields from a found company; returns the names of the fields it set. */
+ apply: (now: RegistryLookupFound, before: RegistryLookupFound | null) => string[]
+}): RegistryAutofillState {
+ const [state, setState] = useState({ status: 'idle' })
+ const applyRef = useRef(apply)
+ useEffect(() => {
+ applyRef.current = apply
+ }, [apply])
+ const answers = useRef(new Map())
+ const unavailable = useRef(false)
+ const lastApplied = useRef(null)
+ const opened = useRef(registryLookupKey(initialOrgNumber))
+ /** The key the current state describes; null while idle. */
+ const shown = useRef(null)
+
+ const key = enabled ? registryLookupKey(orgNumber) : null
+
+ useEffect(() => {
+ if (key === shown.current) return
+ const quiet = () => {
+ shown.current = null
+ setState((s) => (s.status === 'idle' ? s : { status: 'idle' }))
+ }
+ if (!key || key === opened.current || unavailable.current) {
+ quiet()
+ return
+ }
+ const settle = (result: RegistryLookup) => {
+ shown.current = key
+ if (!result.found) {
+ setState({ status: 'not_found', orgNumber: result.orgNumber })
+ return
+ }
+ const fields = applyRef.current(result, lastApplied.current)
+ lastApplied.current = result
+ setState(fields.length > 0 ? { status: 'filled', name: result.name, fields } : { status: 'found', name: result.name })
+ }
+ const known = answers.current.get(key)
+ if (known) {
+ settle(known)
+ return
+ }
+ const ctrl = new AbortController()
+ const timer = setTimeout(async () => {
+ setState({ status: 'looking' })
+ try {
+ const res = await fetch(`/api/parties/registry?org_number=${encodeURIComponent(key)}`, { signal: ctrl.signal })
+ if (res.status === 503) unavailable.current = true
+ const json = res.ok ? ((await res.json()) as { data?: RegistryLookup }) : null
+ if (!json?.data) {
+ quiet()
+ return
+ }
+ answers.current.set(key, json.data)
+ settle(json.data)
+ } catch {
+ if (!ctrl.signal.aborted) quiet()
+ }
+ }, DEBOUNCE_MS)
+ return () => {
+ clearTimeout(timer)
+ ctrl.abort()
+ }
+ }, [key])
+
+ return state
+}
diff --git a/components/suppliers/SupplierForm.tsx b/components/suppliers/SupplierForm.tsx
index dbf0e865..e130497e 100644
--- a/components/suppliers/SupplierForm.tsx
+++ b/components/suppliers/SupplierForm.tsx
@@ -15,6 +15,9 @@ import { Loader2, Lock, X } from 'lucide-react'
import AccountCombobox from '@/components/bookkeeping/AccountCombobox'
import { useCanWrite } from '@/lib/hooks/use-can-write'
import { getCountryOptions, normalizeCountryCode } from '@/lib/vat/country-codes'
+import { registryFormFill, type RegistryFormField } from '@/lib/parties/registry-form-fill'
+import { useRegistryAutofill } from '@/components/parties/use-registry-autofill'
+import { RegistryAutofillNote } from '@/components/parties/RegistryAutofillNote'
import type { CreateSupplierInput } from '@/types'
interface SupplierFormProps {
@@ -87,6 +90,8 @@ export default function SupplierForm({
handleSubmit,
control,
watch,
+ getValues,
+ setValue,
formState: { errors },
} = useForm({
resolver: zodResolver(schema),
@@ -96,6 +101,7 @@ export default function SupplierForm({
email: initialData?.email || '',
phone: initialData?.phone || '',
address_line1: initialData?.address_line1 || '',
+ address_line2: initialData?.address_line2 || '',
postal_code: initialData?.postal_code || '',
city: initialData?.city || '',
country: normalizeCountryCode(initialData?.country) ?? initialData?.country ?? 'SE',
@@ -115,6 +121,39 @@ export default function SupplierForm({
},
})
+ const supplierType = watch('supplier_type')
+ const orgNumber = watch('org_number')
+ // A complete org number of a Swedish company is looked up in SCB's
+ // register once, and the fields it knows are filled where nothing has
+ // been typed (issue #2218). Quiet when the environment has no SCB
+ // credentials. The VAT number is among the fields here: the form shows it.
+ const autofill = useRegistryAutofill({
+ orgNumber,
+ enabled: canWrite && supplierType === 'swedish_business',
+ initialOrgNumber: initialData?.org_number,
+ apply: (now, before) => {
+ const v = getValues()
+ const patch = registryFormFill(
+ {
+ name: v.name ?? '',
+ email: v.email ?? '',
+ phone: v.phone ?? '',
+ address_line1: v.address_line1 ?? '',
+ address_line2: v.address_line2 ?? '',
+ postal_code: v.postal_code ?? '',
+ city: v.city ?? '',
+ vat_number: v.vat_number ?? '',
+ },
+ now,
+ before,
+ )
+ for (const [field, value] of Object.entries(patch)) {
+ setValue(field as RegistryFormField, value ?? '', { shouldDirty: true, shouldValidate: true })
+ }
+ return Object.keys(patch)
+ },
+ })
+
const countryValue = watch('country')
// A stored value the picker does not list (an unmapped legacy name, or a
// code outside the curated list) still has to be visible, or the field
@@ -151,6 +190,27 @@ export default function SupplierForm({
/>
+ {/* Identification first: on a Swedish company's org number the register fills the rest */}
+
+
+
+
+
+
+
+
+
+
+
+
{/* Name */}
@@ -188,29 +248,6 @@ export default function SupplierForm({
- {/* Business info */}
-
-
{t('business_section')}
-
-
-
-
-
-
-
-
-
-
-
-
{/* Address */}
{t('address_section')}
@@ -222,6 +259,14 @@ export default function SupplierForm({
{...register('address_line1')}
/>
+
+
+
+
diff --git a/lib/api/schemas.ts b/lib/api/schemas.ts
index 42dc7b88..943fd824 100644
--- a/lib/api/schemas.ts
+++ b/lib/api/schemas.ts
@@ -4248,6 +4248,16 @@ export const PartySearchRegistryQuerySchema = z.object({
q: z.string().max(120).optional(),
})
+/**
+ * GET /api/parties/registry: the org number a customer or supplier form is
+ * being filled for. Shape, check digit and the legal-person rule are one
+ * function (registryLookupKey in lib/parties/registry-form-fill), so the
+ * form and the route cannot disagree about what may be looked up.
+ */
+export const PartyRegistryLookupQuerySchema = z.object({
+ org_number: z.string().trim().min(1).max(20),
+})
+
export const PartyUndoMergeSchema = z.object({
decisionId: uuid,
})
diff --git a/lib/parties/__tests__/registry-form-fill.test.ts b/lib/parties/__tests__/registry-form-fill.test.ts
new file mode 100644
index 00000000..dc6e7040
--- /dev/null
+++ b/lib/parties/__tests__/registry-form-fill.test.ts
@@ -0,0 +1,140 @@
+import { describe, it, expect } from 'vitest'
+import { describeFilledFields, registryFormFill, registryLookupKey, type RegistryFormFields, type RegistryLookupFound } from '../registry-form-fill'
+import type { RegistrySummary } from '../registry-summary'
+
+function summary(over: Partial = {}): RegistrySummary {
+ return {
+ legal_name: 'WEBHALLEN SVERIGE AB',
+ legal_form: 'Aktiebolag',
+ status: { label: 'Verksamt', active: true },
+ warning: null,
+ registrations: { f_tax: true, vat: true, employer: true },
+ industry: null,
+ seat: 'Stockholm',
+ registered_at: null,
+ active_since: null,
+ active_until: null,
+ employees_band: null,
+ turnover: null,
+ workplaces: null,
+ contact: { email: null, phone: null, address: { co: null, street: 'Storgatan 1', postal_code: '111 22', city: 'Stockholm' } },
+ vat_number: 'SE556252915501',
+ fetched_at: '2026-09-06T10:00:00Z',
+ ...over,
+ }
+}
+
+function found(over: Partial = {}, summaryOver: Partial = {}): RegistryLookupFound {
+ return { found: true, orgNumber: '5562529155', name: 'Webhallen Sverige AB', registry: summary(summaryOver), ...over }
+}
+
+const empty: RegistryFormFields = { name: '', email: '', phone: '', address_line1: '', address_line2: '', postal_code: '', city: '', vat_number: '' }
+
+describe('registryLookupKey', () => {
+ it('returns the canonical ten digits for a Swedish legal person, however written', () => {
+ expect(registryLookupKey('5562529155')).toBe('5562529155')
+ expect(registryLookupKey('556252-9155')).toBe('5562529155')
+ expect(registryLookupKey('16 556252-9155')).toBe('5562529155')
+ expect(registryLookupKey('165562529155')).toBe('5562529155')
+ })
+
+ it('is null while the number is incomplete or its check digit is wrong', () => {
+ expect(registryLookupKey('')).toBeNull()
+ expect(registryLookupKey(null)).toBeNull()
+ expect(registryLookupKey('556252-915')).toBeNull()
+ expect(registryLookupKey('5562529156')).toBeNull()
+ expect(registryLookupKey('abc')).toBeNull()
+ })
+
+ it('never yields a key for a personnummer, even with a valid check digit', () => {
+ // 800101-1231 is Luhn-valid: the refusal is about shape, not the check digit.
+ expect(registryLookupKey('8001011231')).toBeNull()
+ expect(registryLookupKey('800101-1231')).toBeNull()
+ expect(registryLookupKey('198001011231')).toBeNull()
+ })
+})
+
+describe('registryFormFill', () => {
+ it('fills name, VAT number and address on an empty form', () => {
+ expect(registryFormFill(empty, found(), null)).toEqual({
+ name: 'Webhallen Sverige AB',
+ vat_number: 'SE556252915501',
+ address_line1: 'Storgatan 1',
+ address_line2: '',
+ postal_code: '111 22',
+ city: 'Stockholm',
+ })
+ })
+
+ it('never replaces a value the person typed', () => {
+ const typed = { ...empty, name: 'Webhallen (butiken)', vat_number: 'SE999999999901' }
+ const patch = registryFormFill(typed, found(), null)
+ expect(patch.name).toBeUndefined()
+ expect(patch.vat_number).toBeUndefined()
+ expect(patch.address_line1).toBe('Storgatan 1')
+ })
+
+ it('leaves the whole address alone when any part of it was typed', () => {
+ const patch = registryFormFill({ ...empty, city: 'Uppsala' }, found(), null)
+ expect(patch).toEqual({ name: 'Webhallen Sverige AB', vat_number: 'SE556252915501' })
+ })
+
+ it('replaces its own earlier fill when the number is corrected', () => {
+ const first = found()
+ const afterFirst: RegistryFormFields = { ...empty, ...registryFormFill(empty, first, null) } as RegistryFormFields
+ const second = found(
+ { orgNumber: '5560125790', name: 'Beijer Byggmaterial AB' },
+ { legal_name: 'BEIJER BYGGMATERIAL AB', vat_number: 'SE556012579001', contact: { email: null, phone: null, address: { co: null, street: 'Norra vägen 5', postal_code: '169 70', city: 'Solna' } } },
+ )
+ expect(registryFormFill(afterFirst, second, first)).toEqual({
+ name: 'Beijer Byggmaterial AB',
+ vat_number: 'SE556012579001',
+ address_line1: 'Norra vägen 5',
+ address_line2: '',
+ postal_code: '169 70',
+ city: 'Solna',
+ })
+ })
+
+ it('keeps a name the person changed after the first fill', () => {
+ const first = found()
+ const edited: RegistryFormFields = { ...empty, ...registryFormFill(empty, first, null), name: 'Webhallen' } as RegistryFormFields
+ const second = found({ orgNumber: '5560125790', name: 'Beijer Byggmaterial AB' }, { legal_name: 'BEIJER BYGGMATERIAL AB' })
+ expect(registryFormFill(edited, second, first).name).toBeUndefined()
+ })
+
+ it('puts a c/o on line 1 and the street on line 2, as on the row', () => {
+ const patch = registryFormFill(empty, found({}, { contact: { email: null, phone: null, address: { co: 'c/o Byrån AB', street: 'Box 12', postal_code: '111 22', city: 'Stockholm' } } }), null)
+ expect(patch.address_line1).toBe('c/o Byrån AB')
+ expect(patch.address_line2).toBe('Box 12')
+ })
+
+ it('fills e-mail and phone when the register has them', () => {
+ const patch = registryFormFill(empty, found({}, { contact: { email: 'info@webhallen.com', phone: '08-123 45 67', address: null } }), null)
+ expect(patch).toEqual({ name: 'Webhallen Sverige AB', vat_number: 'SE556252915501', email: 'info@webhallen.com', phone: '08-123 45 67' })
+ })
+
+ it('touches nothing when the form already holds what the register says', () => {
+ const filled: RegistryFormFields = { ...empty, ...registryFormFill(empty, found(), null) } as RegistryFormFields
+ expect(registryFormFill(filled, found(), null)).toEqual({})
+ })
+
+ it('does not fill a field the form does not show', () => {
+ const patch = registryFormFill(empty, found(), null, ['name', 'address_line1', 'address_line2', 'postal_code', 'city'])
+ expect(patch.vat_number).toBeUndefined()
+ expect(patch.name).toBe('Webhallen Sverige AB')
+ expect(patch.city).toBe('Stockholm')
+ })
+
+ it('does nothing without a legal name or VAT number in the register', () => {
+ expect(registryFormFill(empty, found({ name: '' }, { legal_name: null, vat_number: null, contact: { email: null, phone: null, address: null } }), null)).toEqual({})
+ })
+})
+
+describe('describeFilledFields', () => {
+ it('collapses the address columns into one item in a fixed order', () => {
+ expect(describeFilledFields(['city', 'vat_number', 'postal_code', 'name', 'address_line1'])).toEqual(['name', 'address', 'vat_number'])
+ expect(describeFilledFields(['phone', 'email'])).toEqual(['email', 'phone'])
+ expect(describeFilledFields([])).toEqual([])
+ })
+})
diff --git a/lib/parties/registry-form-fill.ts b/lib/parties/registry-form-fill.ts
new file mode 100644
index 00000000..cb85b441
--- /dev/null
+++ b/lib/parties/registry-form-fill.ts
@@ -0,0 +1,118 @@
+/**
+ * Parties: filling a customer or supplier form from the register.
+ *
+ * The registry lookup was built for rows that already exist (the detail
+ * page's "Hämta uppgifter" records facts on the row's party), so on the
+ * create form people typed what SCB already knew. This is the form side:
+ * which numbers may be looked up at all, and which fields a found company
+ * fills. Pure: form values in, patch out. The hook in
+ * components/parties/use-registry-autofill.ts decides when to call.
+ */
+import { looksLikeSwedishPersonalNumber } from '@/lib/customers/personal-number-shape'
+import { normalizeOrgNumber } from '@/lib/invariants/org-number'
+import { isLegalPersonOrgNumber } from './scb/org-number'
+import { contactFill, fromRegistry, type RegistrySummary } from './registry-summary'
+
+export interface RegistryLookupFound {
+ found: true
+ /** Canonical ten digits. */
+ orgNumber: string
+ /** The register's legal name in display case ("Webhallen Sverige AB"). */
+ name: string
+ registry: RegistrySummary
+}
+
+export interface RegistryLookupMissing {
+ found: false
+ orgNumber: string
+}
+
+export type RegistryLookup = RegistryLookupFound | RegistryLookupMissing
+
+/**
+ * The canonical ten digits when the typed value is a complete org number
+ * of a Swedish legal person with a valid check digit; null for anything
+ * else. A personnummer (a private person's, or a sole trader's org number)
+ * is never a key: it must not reach the register, and the server refuses
+ * it too (SCB_NOT_A_LEGAL_PERSON). Both checks are kept although a legal
+ * person's number can never have personnummer shape: they guard different
+ * things and each is cheap.
+ */
+export function registryLookupKey(orgNumber: string | null | undefined): string | null {
+ const canonical = normalizeOrgNumber(orgNumber)
+ if (!canonical) return null
+ if (!isLegalPersonOrgNumber(canonical) || looksLikeSwedishPersonalNumber(canonical)) return null
+ return canonical
+}
+
+export interface RegistryFormFields {
+ name: string
+ email: string
+ phone: string
+ address_line1: string
+ address_line2: string
+ postal_code: string
+ city: string
+ vat_number: string
+}
+
+export type RegistryFormField = keyof RegistryFormFields
+
+export const REGISTRY_FORM_FIELDS: readonly RegistryFormField[] = ['name', 'email', 'phone', 'address_line1', 'address_line2', 'postal_code', 'city', 'vat_number']
+
+/**
+ * Which fields to set after a lookup. A field is filled when it is empty,
+ * or when it still holds what the previous lookup put there (a corrected
+ * number replaces its own fill); a value the person typed is never
+ * replaced. Contact fields follow the row rule from registry-summary
+ * (`contactFill`): the address is one unit, c/o on line 1 and street on
+ * line 2. `fields` is what the form shows; nothing lands in a field the
+ * person cannot see.
+ */
+export function registryFormFill(
+ current: RegistryFormFields,
+ now: RegistryLookupFound,
+ before: RegistryLookupFound | null,
+ fields: readonly RegistryFormField[] = REGISTRY_FORM_FIELDS,
+): Partial {
+ const out: Partial = {}
+ const untouched = (value: string, previous: string | null | undefined) => value.trim() === '' || fromRegistry(value, previous)
+
+ if (now.name && untouched(current.name, before?.name) && !fromRegistry(current.name, now.name)) out.name = now.name
+
+ const vat = now.registry.vat_number
+ if (vat && untouched(current.vat_number, before?.registry.vat_number) && !fromRegistry(current.vat_number, vat)) out.vat_number = vat
+
+ const contact = contactFill(
+ {
+ email: current.email,
+ phone: current.phone,
+ address_line1: current.address_line1,
+ address_line2: current.address_line2,
+ postal_code: current.postal_code,
+ city: current.city,
+ },
+ now.registry.contact,
+ before?.registry.contact ?? null,
+ )
+ for (const [key, value] of Object.entries(contact)) out[key as Exclude] = value ?? ''
+
+ const shown = new Set(fields)
+ for (const key of Object.keys(out) as RegistryFormField[]) if (!shown.has(key)) delete out[key]
+ return out
+}
+
+/**
+ * The filled fields as the note under the org number lists them: the four
+ * address columns collapse into one "adress", in a fixed order.
+ */
+export function describeFilledFields(filled: readonly string[]): Array<'name' | 'address' | 'email' | 'phone' | 'vat_number'> {
+ const set = new Set(filled)
+ const out: Array<'name' | 'address' | 'email' | 'phone' | 'vat_number'> = []
+ if (set.has('name')) out.push('name')
+ if (set.has('address_line1') || set.has('address_line2') || set.has('postal_code') || set.has('city')) out.push('address')
+ if (set.has('email')) out.push('email')
+ if (set.has('phone')) out.push('phone')
+ if (set.has('vat_number')) out.push('vat_number')
+ return out
+}
diff --git a/messages/en.json b/messages/en.json
index cd39abfa..8fbed5e7 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -1299,7 +1299,9 @@
"submit_save": "Save customer",
"submit_saving": "Saving...",
"viewer_disabled_tooltip": "You only have viewer access in this company",
- "personal_number_unreadable": "The stored personal number cannot be read. Enter it again to replace it."
+ "personal_number_unreadable": "The stored personal number cannot be read. Enter it again to replace it.",
+ "address_line2_label": "Address line 2",
+ "address_line2_placeholder": "c/o"
},
"form_supplier": {
"name_label": "Name *",
@@ -1345,7 +1347,9 @@
"notes_placeholder": "Internal notes about the supplier...",
"submit_save": "Save supplier",
"submit_saving": "Saving...",
- "viewer_disabled_tooltip": "You only have viewer access in this company"
+ "viewer_disabled_tooltip": "You only have viewer access in this company",
+ "address_line2_label": "Address line 2",
+ "address_line2_placeholder": "c/o"
},
"initial_setup": {
"completed_verdict": "Your bookkeeping is up and running.",
@@ -8823,8 +8827,16 @@
"open_dossier": "Open {name}",
"attn_create": "Create suggestions",
"auto_created_title": "{count} suggestions created from the books",
- "auto_created_description": "Counterparts your vouchers name that are not in the register. Add them, or hide the ones that do not belong here."
-},
+ "auto_created_description": "Counterparts your vouchers name that are not in the register. Add them, or hide the ones that do not belong here.",
+ "autofill_looking": "Searching the SCB business register…",
+ "autofill_filled": "{name} · {fields} from SCB. Edit freely.",
+ "autofill_found": "{name} according to the SCB register. Nothing changed, the fields were already filled in.",
+ "autofill_not_found": "No company with org. no. {org} in the SCB register.",
+ "autofill_field_name": "name",
+ "autofill_field_email": "email",
+ "autofill_field_phone": "phone",
+ "autofill_field_vat": "VAT number"
+ },
"tx_expense_payout_match": {
"title": "Book expense reimbursement",
"description": "The transfer is booked against the person's liability account, the claims are marked as paid and the transaction is linked to the voucher.",
diff --git a/messages/sv.json b/messages/sv.json
index 798ccf55..125d8af4 100644
--- a/messages/sv.json
+++ b/messages/sv.json
@@ -1299,7 +1299,9 @@
"submit_save": "Spara kund",
"submit_saving": "Sparar...",
"viewer_disabled_tooltip": "Du har endast läsbehörighet i detta företag",
- "personal_number_unreadable": "Det sparade personnumret kan inte läsas. Skriv in det igen för att ersätta det."
+ "personal_number_unreadable": "Det sparade personnumret kan inte läsas. Skriv in det igen för att ersätta det.",
+ "address_line2_label": "Adressrad 2",
+ "address_line2_placeholder": "c/o"
},
"form_supplier": {
"name_label": "Namn *",
@@ -1345,7 +1347,9 @@
"notes_placeholder": "Interna anteckningar om leverantören...",
"submit_save": "Spara leverantör",
"submit_saving": "Sparar...",
- "viewer_disabled_tooltip": "Du har endast läsbehörighet i detta företag"
+ "viewer_disabled_tooltip": "Du har endast läsbehörighet i detta företag",
+ "address_line2_label": "Adressrad 2",
+ "address_line2_placeholder": "c/o"
},
"initial_setup": {
"completed_verdict": "Bokföringen är igång.",
@@ -8823,8 +8827,16 @@
"open_dossier": "Öppna {name}",
"attn_create": "Skapa förslag",
"auto_created_title": "{count} förslag skapade från bokföringen",
- "auto_created_description": "Motparter som dina verifikat namnger men som inte finns i registret. Lägg upp dem, eller dölj de som inte hör hemma här."
-},
+ "auto_created_description": "Motparter som dina verifikat namnger men som inte finns i registret. Lägg upp dem, eller dölj de som inte hör hemma här.",
+ "autofill_looking": "Söker i SCB:s företagsregister…",
+ "autofill_filled": "{name} · {fields} från SCB. Ändra fritt.",
+ "autofill_found": "{name} enligt SCB:s register. Inget ändrat, fälten var redan ifyllda.",
+ "autofill_not_found": "Inget företag med org.nr {org} i SCB:s register.",
+ "autofill_field_name": "namn",
+ "autofill_field_email": "e-post",
+ "autofill_field_phone": "telefon",
+ "autofill_field_vat": "momsnummer"
+ },
"tx_expense_payout_match": {
"title": "Bokför återbetalning av utlägg",
"description": "Överföringen bokförs mot personens skuldkonto, utläggen markeras som utbetalda och transaktionen kopplas till verifikatet.",