Feat/skv integration full (#285)
* 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) <noreply@anthropic.com>
* 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) <noreply@anthropic.com>
* 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) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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<Customer[]>([])
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user