From dfb953638c0b339df1f4e275aba386f7a89aac6f Mon Sep 17 00:00:00 2001 From: Mattsson <111893710+mattssonn@users.noreply.github.com> Date: Mon, 20 Apr 2026 21:18:21 +0200 Subject: [PATCH] Feat/skv integration full (#285) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add script to import Skatteverket monthly tax tables as fallback TypeScript module - Implemented a new script `import-tax-tables.ts` to parse fixed-width TXT tax tables from Skatteverket (SKV 434). - The script generates a TypeScript module for emergency fallback when the Skatteverket open-data API is unavailable. - Supports command-line argument for specifying the year and handles parsing of B-rows only. - Outputs a structured TypeScript file containing tax data for specified years. * feat: gate salary module behind dev-only flag Temporarily disable the Lön module in production while the feature is being completed. Sidebar entries ("Löner", "Anställda") still render but are not clickable and show a "Kommer snart" badge. Middleware redirects /salary* to / and returns 404 on /api/salary/* so the feature can't be reached by direct URL. All gates check NODE_ENV === 'development' so local dev keeps full access for continued development. Co-Authored-By: Claude Opus 4.7 (1M context) * feat: refactor bank file import wizard to streamline column mapping and enhance CSV handling * fix: bump migration timestamp to avoid collision with logos_bucket Co-Authored-By: Claude Opus 4.7 (1M context) * feat: enhance AGI generation and salary entry calculations with improved status checks and error handling * fix: scope new-invoice customer/settings fetch to active company The customer dropdown relied solely on RLS, which returns rows from every company the user is a member of. POST /api/invoices strictly filters the customer by the active company_id, so selecting a customer from a non-active company returned 404 ("Resursen kunde inte hittas"). Filter both the customer list and the company_settings read by company.id. Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Claude Opus 4.7 (1M context) --- app/(dashboard)/invoices/new/page.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/(dashboard)/invoices/new/page.tsx b/app/(dashboard)/invoices/new/page.tsx index d070760c..94d80760 100644 --- a/app/(dashboard)/invoices/new/page.tsx +++ b/app/(dashboard)/invoices/new/page.tsx @@ -27,6 +27,7 @@ import { getErrorMessage } from '@/lib/errors/get-error-message' import { useUnsavedChanges } from '@/lib/hooks/use-unsaved-changes' import CustomerForm from '@/components/customers/CustomerForm' import { BankDetailsSetupDialog } from '@/components/invoices/BankDetailsSetupDialog' +import { useCompany } from '@/contexts/CompanyContext' import type { Customer, Currency, CreateInvoiceInput, CreateCustomerInput, InvoiceDocumentType } from '@/types' const itemSchema = z.object({ @@ -59,6 +60,7 @@ export default function NewInvoicePage() { const router = useRouter() const { toast } = useToast() const { canWrite } = useCanWrite() + const { company } = useCompany() const supabase = createClient() const [customers, setCustomers] = useState([]) @@ -126,14 +128,17 @@ export default function NewInvoicePage() { }, [customers, setValue]) useEffect(() => { + if (!company?.id) return fetchCustomers() fetchDefaultNotes() - }, []) + }, [company?.id]) async function fetchDefaultNotes() { + if (!company?.id) return const { data } = await supabase .from('company_settings') .select('invoice_default_notes, clearing_number, account_number, bankgiro') + .eq('company_id', company.id) .single() if (data?.invoice_default_notes) { setDefaultNotes(data.invoice_default_notes) @@ -171,9 +176,11 @@ export default function NewInvoicePage() { }, [watchCustomerId, customers, setValue]) async function fetchCustomers() { + if (!company?.id) return const { data, error } = await supabase .from('customers') .select('*') + .eq('company_id', company.id) .order('name', { ascending: true }) if (error) {