fix: address user feedback — AI loan categorization, invoice UX, email extension, supplier module
- #43: Improve AI categorization to use account 2350 for loan repayments instead of incorrectly suggesting 2440 (supplier payables). Add explicit prompt guidance distinguishing loans from supplier debts. - #45: Change unclear invoice unit "mån" to "månad" - #46: Enable email extension in extensions.config.json so it appears in the marketplace and can be activated by users - #47: Change "Makulera" to "Ta bort utkast" for draft invoices — reserve "Makulera" terminology for proforma invoices only - #48: Show field-level validation errors when supplier creation fails instead of generic "Validation failed" message - #49: Temporarily hide Leverantörer and Leverantörsfakturor from sidebar pending module rework Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
31dec292fe
commit
a2ea52954c
@@ -29,6 +29,7 @@ import {
|
||||
Bell,
|
||||
AlertTriangle,
|
||||
MessageSquare,
|
||||
Trash2,
|
||||
} from 'lucide-react'
|
||||
import type { Invoice, InvoiceItem, Customer, InvoiceStatus, InvoiceReminder, InvoiceDocumentType } from '@/types'
|
||||
|
||||
@@ -875,12 +876,12 @@ export default function InvoiceDetailPage({ params }: { params: Promise<{ id: st
|
||||
)}
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full"
|
||||
className="w-full text-destructive hover:text-destructive"
|
||||
onClick={() => updateStatus('cancelled')}
|
||||
disabled={isUpdating}
|
||||
>
|
||||
<XCircle className="mr-2 h-4 w-4" />
|
||||
Makulera
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
Ta bort utkast
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -49,7 +49,7 @@ const schema = z.object({
|
||||
type FormData = z.infer<typeof schema>
|
||||
|
||||
const currencies: Currency[] = ['SEK', 'EUR', 'USD', 'GBP', 'NOK', 'DKK']
|
||||
const units = ['st', 'tim', 'dag', 'mån', 'km', 'kg']
|
||||
const units = ['st', 'tim', 'dag', 'månad', 'km', 'kg']
|
||||
|
||||
export default function NewInvoicePage() {
|
||||
const router = useRouter()
|
||||
|
||||
@@ -68,7 +68,8 @@ export default function SupplierDetailPage() {
|
||||
})
|
||||
const result = await res.json()
|
||||
if (!res.ok) {
|
||||
toast({ title: 'Fel', description: result.error, variant: 'destructive' })
|
||||
const fieldErrors = result.errors?.map((e: { field: string; message: string }) => `${e.field}: ${e.message}`).join(', ')
|
||||
toast({ title: 'Fel', description: fieldErrors || result.error || 'Kunde inte uppdatera leverantör', variant: 'destructive' })
|
||||
} else {
|
||||
toast({ title: 'Sparat', description: 'Leverantören har uppdaterats' })
|
||||
setSupplier({ ...result.data, stats: supplier?.stats })
|
||||
|
||||
@@ -69,9 +69,10 @@ export default function SuppliersPage() {
|
||||
const result = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
const fieldErrors = result.errors?.map((e: { field: string; message: string }) => `${e.field}: ${e.message}`).join(', ')
|
||||
toast({
|
||||
title: 'Fel',
|
||||
description: result.error || 'Kunde inte skapa leverantör',
|
||||
description: fieldErrors || result.error || 'Kunde inte skapa leverantör',
|
||||
variant: 'destructive',
|
||||
})
|
||||
} else {
|
||||
|
||||
@@ -42,6 +42,7 @@ interface NavItem {
|
||||
icon: typeof LayoutDashboard
|
||||
group: string
|
||||
modes?: EntityType[] // If set, only visible for these entity types. If not set, visible to all.
|
||||
hidden?: boolean // Temporarily hide from sidebar
|
||||
}
|
||||
|
||||
// All nav items for sidebar and mobile drawer
|
||||
@@ -50,8 +51,9 @@ const navItems: NavItem[] = [
|
||||
{ href: '/deadlines', label: 'Deadlines', icon: Calendar, group: 'main' },
|
||||
{ href: '/invoices', label: 'Fakturor', icon: Receipt, group: 'finans' },
|
||||
{ href: '/customers', label: 'Kunder', icon: Users, group: 'finans' },
|
||||
{ href: '/suppliers', label: 'Leverantörer', icon: Building2, group: 'finans' },
|
||||
{ href: '/supplier-invoices', label: 'Leverantörsfakturor', icon: FileInput, group: 'finans' },
|
||||
// Temporarily hidden pending module rework (see feedback #49)
|
||||
{ href: '/suppliers', label: 'Leverantörer', icon: Building2, group: 'finans', hidden: true },
|
||||
{ href: '/supplier-invoices', label: 'Leverantörsfakturor', icon: FileInput, group: 'finans', hidden: true },
|
||||
{ href: '/transactions', label: 'Transaktioner', icon: ArrowLeftRight, group: 'finans' },
|
||||
{ href: '/bookkeeping', label: 'Bokföring', icon: BookOpen, group: 'finans' },
|
||||
{ href: '/reports', label: 'Rapporter', icon: BarChart3, group: 'finans' },
|
||||
@@ -131,9 +133,9 @@ export default function DashboardNav({ companyName, entityType, enabledExtension
|
||||
|
||||
const closeMobileMenu = () => setIsMobileMenuOpen(false)
|
||||
|
||||
// Filter nav items by entity type
|
||||
// Filter nav items by entity type and hidden flag
|
||||
const filteredItems = navItems.filter(item =>
|
||||
!item.modes || item.modes.includes(entityType)
|
||||
!item.hidden && (!item.modes || item.modes.includes(entityType))
|
||||
)
|
||||
|
||||
const mainItems = filteredItems.filter(i => i.group === 'main')
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"$schema":"./extensions.schema.json","extensions":["enable-banking","ai-categorization","ai-chat"]}
|
||||
{"$schema":"./extensions.schema.json","extensions":["enable-banking","ai-categorization","ai-chat","email"]}
|
||||
|
||||
@@ -110,6 +110,8 @@ function getCategoryAccountMap(entityType: EntityType): Record<string, { account
|
||||
expense_bank_fees: { account: '6570', label: 'Bankavgifter' },
|
||||
expense_card_fees: { account: '6570', label: 'Kortavgifter' },
|
||||
expense_currency_exchange: { account: '7960', label: 'Valutakursförluster' },
|
||||
expense_interest: { account: '8410', label: 'Räntekostnader' },
|
||||
financial_loan_repayment: { account: '2350', label: 'Amortering lån (kreditinstitut)' },
|
||||
expense_other: { account: '6991', label: 'Övriga kostnader' },
|
||||
}
|
||||
}
|
||||
@@ -275,7 +277,8 @@ REGLER:
|
||||
6. taxCode: "MPI" för avdragsgilla affärskostnader med moms, "MP1" för intäkter med moms, null för momsfria
|
||||
7. templateId är OBLIGATORISKT — välj alltid den mest passande mallen från listan ovan, även för alternativa förslag
|
||||
8. isPrivate ska ALLTID vara false — användaren avgör själv vad som är privat
|
||||
9. Ange TVÅ förslag per transaktion: ett primärt (mest troligt) och ett alternativt (näst mest troligt, annan kategori, lägre confidence). Båda ska vara affärskategorier.`
|
||||
9. Ange TVÅ förslag per transaktion: ett primärt (mest troligt) och ett alternativt (näst mest troligt, annan kategori, lägre confidence). Båda ska vara affärskategorier.
|
||||
10. SKULDER: Konto 2440 (leverantörsskulder) ska BARA användas för leverantörsfakturor. Lån/amorteringar från banker eller kreditinstitut (Almi, Nordea, SEB, Handelsbanken, Swedbank, etc.) ska använda 2350 (skulder till kreditinstitut) via mallen financial_loan_repayment. Räntebetalningar ska använda 8410 (räntekostnader).`
|
||||
|
||||
const historyContext =
|
||||
context.recentHistory.length > 0
|
||||
|
||||
@@ -106,7 +106,8 @@ VANLIGA BAS-KONTON:
|
||||
Utgifter: 5010 Lokalhyra | 5410 Forbrukningsinventarier | 5420 Programvara | 5460 Forbrukningsvaror | 5611 Bil/drivmedel | 5800 Resekostnader | 5910 Annonsering | 6071 Representation mat | 6200 Telefon/internet | 6530 Redovisning/konsult | 6570 Bankavgifter | 6991 Ovriga kostnader | ${entityType === 'aktiebolag' ? '7610' : '6991'} Utbildning
|
||||
Intakter: 3001 Forsaljning 25% | 3002 Forsaljning 12% | 3003 Forsaljning 6% | 3305 Export | 3308 EU-tjanster | 3900 Ovriga intakter
|
||||
Moms: 2611 Utg moms 25% | 2621 Utg moms 12% | 2631 Utg moms 6% | 2641 Ing moms | 2645 Beraknad ing moms
|
||||
Ovrigt: 1510 Kundfordringar | 1930 Foretagskonto | 2440 Leverantorsskulder | ${privateAccount} Privat
|
||||
Skulder: 2350 Skulder till kreditinstitut (banklan, Almi) | 2440 Leverantorsskulder (ENBART for leverantorsfakturor)
|
||||
Ovrigt: 1510 Kundfordringar | 1930 Foretagskonto | 8410 Rantekostnader | ${privateAccount} Privat
|
||||
|
||||
MOMSREGLER:
|
||||
- standard_25: Normala varor/tjanster (25%)
|
||||
|
||||
@@ -4,4 +4,5 @@ export const ENABLED_EXTENSION_IDS: ReadonlySet<string> = new Set([
|
||||
'enable-banking',
|
||||
'ai-categorization',
|
||||
'ai-chat',
|
||||
'email',
|
||||
])
|
||||
|
||||
@@ -3,9 +3,11 @@ import type { Extension } from '../types'
|
||||
import { enableBankingExtension } from '@/extensions/general/enable-banking'
|
||||
import { aiCategorizationExtension } from '@/extensions/general/ai-categorization'
|
||||
import { aiChatExtension } from '@/extensions/general/ai-chat'
|
||||
import { emailExtension } from '@/extensions/general/email'
|
||||
|
||||
export const FIRST_PARTY_EXTENSIONS: Extension[] = [
|
||||
enableBankingExtension,
|
||||
aiCategorizationExtension,
|
||||
aiChatExtension,
|
||||
emailExtension,
|
||||
]
|
||||
|
||||
@@ -57,5 +57,20 @@ export const EXTENSION_DEFINITIONS: Record<string, ExtensionDefinition[]> = {
|
||||
"event": "open-ai-chat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "email",
|
||||
"name": "E-post (Resend)",
|
||||
"sector": "general",
|
||||
"category": "operations",
|
||||
"icon": "Mail",
|
||||
"dataPattern": "core",
|
||||
"description": "Skicka fakturor och påminnelser via e-post",
|
||||
"longDescription": "Aktiverar e-postfunktioner: skicka fakturor till kunder, automatiska betalningspåminnelser (15/30/45 dagar), och e-postmeddelanden. Kräver ett Resend-konto med verifierad domän.",
|
||||
"readsCoreTables": [
|
||||
"invoices",
|
||||
"customers",
|
||||
"company_settings"
|
||||
]
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user