fix: scope company_settings query to active company in invoice dialogs (#288)
SendInvoiceDialog and PaymentBookingDialog called .single() on company_settings without a company_id filter, relying on RLS to narrow the result. RLS uses user_company_ids() which returns every company the user can access, so multi-company users (including team members) got multiple rows back and PostgREST returned 406. Filter explicitly by the active company and use maybeSingle() so a missing row falls back to defaults. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
0076aa85f8
commit
aec14f0ca7
@@ -18,6 +18,7 @@ import AccountCombobox from '@/components/bookkeeping/AccountCombobox'
|
||||
import { proposePaymentLines } from '@/lib/bookkeeping/propose-payment-lines'
|
||||
import { formatCurrency } from '@/lib/utils'
|
||||
import { createClient } from '@/lib/supabase/client'
|
||||
import { useCompany } from '@/contexts/CompanyContext'
|
||||
import { Plus, Trash2, Loader2 } from 'lucide-react'
|
||||
import type { FormLine } from '@/components/bookkeeping/JournalEntryForm'
|
||||
import type { Invoice, InvoiceItem, Customer, BASAccount, EntityType } from '@/types'
|
||||
@@ -44,6 +45,7 @@ export default function PaymentBookingDialog({
|
||||
}: PaymentBookingDialogProps) {
|
||||
const { toast } = useToast()
|
||||
const supabase = createClient()
|
||||
const { company } = useCompany()
|
||||
|
||||
const [accounts, setAccounts] = useState<BASAccount[]>([])
|
||||
const [lines, setLines] = useState<FormLine[]>([])
|
||||
@@ -68,11 +70,14 @@ export default function PaymentBookingDialog({
|
||||
const accountsData = await accountsRes.json()
|
||||
const fetchedAccounts: BASAccount[] = accountsData.data || []
|
||||
|
||||
if (!company?.id) throw new Error('Inget aktivt företag')
|
||||
|
||||
// Fetch company settings
|
||||
const { data: settings, error: settingsError } = await supabase
|
||||
.from('company_settings')
|
||||
.select('accounting_method, entity_type')
|
||||
.single()
|
||||
.eq('company_id', company.id)
|
||||
.maybeSingle()
|
||||
|
||||
if (settingsError) throw new Error('Kunde inte ladda företagsinställningar')
|
||||
if (cancelled) return
|
||||
@@ -116,7 +121,7 @@ export default function PaymentBookingDialog({
|
||||
|
||||
init()
|
||||
return () => { cancelled = true }
|
||||
}, [open, invoice.id])
|
||||
}, [open, invoice.id, company?.id])
|
||||
|
||||
// Balance computation
|
||||
const { totalDebit, totalCredit, isBalanced } = useMemo(() => {
|
||||
|
||||
@@ -15,6 +15,7 @@ import { JournalEntryReviewContent } from '@/components/bookkeeping/JournalEntry
|
||||
import { proposeSendLines } from '@/lib/bookkeeping/propose-send-lines'
|
||||
import { formatCurrency } from '@/lib/utils'
|
||||
import { createClient } from '@/lib/supabase/client'
|
||||
import { useCompany } from '@/contexts/CompanyContext'
|
||||
import { Loader2, Mail, Send } from 'lucide-react'
|
||||
import type { Invoice, InvoiceItem, Customer, EntityType } from '@/types'
|
||||
|
||||
@@ -41,6 +42,7 @@ export default function SendInvoiceDialog({
|
||||
}: SendInvoiceDialogProps) {
|
||||
const { toast } = useToast()
|
||||
const supabase = createClient()
|
||||
const { company } = useCompany()
|
||||
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
const [accountingMethod, setAccountingMethod] = useState<'accrual' | 'cash'>('accrual')
|
||||
@@ -58,11 +60,14 @@ export default function SendInvoiceDialog({
|
||||
|
||||
async function init() {
|
||||
try {
|
||||
if (!company?.id) throw new Error('Inget aktivt företag')
|
||||
|
||||
// Fetch company settings
|
||||
const { data: settings, error } = await supabase
|
||||
.from('company_settings')
|
||||
.select('accounting_method, entity_type')
|
||||
.single()
|
||||
.eq('company_id', company.id)
|
||||
.maybeSingle()
|
||||
|
||||
if (error) throw new Error('Kunde inte ladda företagsinställningar')
|
||||
if (cancelled) return
|
||||
@@ -71,9 +76,10 @@ export default function SendInvoiceDialog({
|
||||
const { data: period } = await supabase
|
||||
.from('fiscal_periods')
|
||||
.select('name')
|
||||
.eq('company_id', company.id)
|
||||
.lte('start_date', invoice.invoice_date)
|
||||
.gte('end_date', invoice.invoice_date)
|
||||
.single()
|
||||
.maybeSingle()
|
||||
|
||||
if (cancelled) return
|
||||
|
||||
@@ -94,7 +100,7 @@ export default function SendInvoiceDialog({
|
||||
|
||||
init()
|
||||
return () => { cancelled = true }
|
||||
}, [open, invoice.id, invoice.invoice_date])
|
||||
}, [open, invoice.id, invoice.invoice_date, company?.id])
|
||||
|
||||
const proposedLines = useMemo(() => {
|
||||
if (!isInitialized || accountingMethod !== 'accrual') return []
|
||||
|
||||
Reference in New Issue
Block a user