Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
import { useState, useMemo } from 'react';
|
|
|
|
|
import {
|
|
|
|
|
Typography,
|
|
|
|
|
Button,
|
|
|
|
|
Card,
|
|
|
|
|
Table,
|
|
|
|
|
Space,
|
|
|
|
|
Tag,
|
|
|
|
|
Modal,
|
|
|
|
|
Form,
|
|
|
|
|
Input,
|
Audit v3: VAT alignment, security, encoding, UX, compliance
VAT System Alignment (LEGAL - Critical):
- Align frontend VAT codes with backend (S25→U25, K25→I25, etc.)
- Add missing codes: UEU, IVV, IVY, REP
- Fix output VAT account 5710→5611 to match StandardDanishAccounts
- Invoice posting now checks fiscal year status before allowing send
- Disallow custom invoice number override (always use auto-numbering)
Security:
- Fix open redirect in AuthController (validate returnUrl is local)
- Store seller CVR/name/address on invoice events (Momsloven §52)
Backend Compliance:
- Add description validation at posting (Bogføringsloven §7)
- SAF-T: add DefaultCurrencyCode, TaxAccountingBasis to header
- SAF-T: add TaxTable to MasterFiles with all VAT codes
- SAF-T: always write balance elements even when zero
- Add financial income account 9100 Renteindtægter
Danish Encoding (~25 fixes):
- Kassekladde: Bogført, Bogføring, Vælg, være, på, Tilføj, Differens
- AttachmentUpload: træk, Understøtter, påkrævet, Bogføringsloven
- keyboardShortcuts: Bogfør, Bogføring display name
- ShortcutsHelpModal: åbne
- DataTable: Genindlæs
- documentProcessing: være
- CloseFiscalYearWizard: årsafslutning
Bugs Fixed:
- Non-null assertion crashes in Kunder.tsx and Produkter.tsx (company!.id)
- StatusBadge typo "Succces"→"Succes"
- HTML entity ø in Kassekladde→proper UTF-8
- AmountText showSign prop was dead code (true || showSign)
UX Improvements:
- Add PageHeader to Bankafstemning and Dashboard loading/empty states
- Responsive columns in Bankafstemning (xs/sm/lg breakpoints)
- Disable misleading buttons: Settings preferences, Kontooversigt edit,
Loenforstaelse export — with tooltips explaining status
- Add DemoDataDisclaimer to UserSettings
- Fix breadcrumb self-references on 3 pages
- Replace Dashboard fake progress bar with honest message
- Standardize date format DD-MM-YYYY in Bankafstemning and Ordrer
- Replace Input type="number" with InputNumber in Ordrer
Quality:
- Remove 8 redundant console.error statements
- Fix Kreditnotaer breadcrumb "Salg"→"Fakturering" for consistency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 01:15:45 +01:00
|
|
|
InputNumber,
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
Select,
|
Audit v2: fix security, data integrity, compliance, bugs, encoding, UX
Backend Security & Data Integrity:
- Block negative debit/credit amounts that bypass balance validation
- Require document date at posting (was optional, bypassing fiscal year checks)
- Fix event sourcing anti-pattern: timestamps now stored in events, not UtcNow in Apply
- Add [Authorize] to BankingController OAuth callback
- Add company access check on attachment downloads
- Validate CVR in CompanyAggregate.Create and CompanyAggregate.Update
- Require company CVR for invoice creation (Momsloven §52)
- Delete leftover WeatherForecastController
- Fix duplicate migration number 007 (renamed to 007b)
- Remove dead code in VatCalculationService (identical if/else branches)
Accounting Compliance:
- Add missing VAT accounts to StandardDanishAccounts (5610, 5611, 5620)
- Populate SAF-T TaxInformation on transaction lines (was always null)
- Add AuditFileCountry and TaxRegistrationNumber to SAF-T header
Critical Frontend Bugs:
- Fix Dashboard <a href> causing full page reloads (now uses React Router Link)
- Wire Kassekladde filters to actual data (account, status, date range)
- Pre-populate form when editing existing Kassekladde drafts
- Add detail drawer for "Vis detaljer" action (was just a toast)
- Toggle advanced filters with "Flere filtre" button
- CloseFiscalYearWizard now actually posts closing entries via mutations
- "Create next year" checkbox now creates the next fiscal year
Danish Character Encoding (~50 fixes):
- Fix ø/æ/å across Momsindberetning, DocumentUploadModal, Bankafstemning,
Kontooversigt, CloseFiscalYearWizard, vatCodes, periodStore, periods,
accounting, types/periods
Dead Buttons & UX:
- Disable Momsindberetning PDF/Export buttons with tooltips
- FiscalYearSelector "Administrer" now navigates to Settings
- Settings bank tab now uses real BankConnectionsTab component
- Bankafstemning save button disabled with development tooltip
- Replace hardcoded account options with real API data (Bankafstemning, Fakturaer)
- Header help button shows info message, notification bell shows popover
Consistency & Quality:
- Remove 7 console.log statements from production code
- Adopt PageHeader on 6 remaining pages (Kreditnotaer, Settings, Admin, etc.)
- Standardize loading states to Skeleton pattern (5 pages)
- Replace deprecated bodyStyle prop on Ant Design Cards
- Standardize date format to DD-MM-YYYY
- Fix sidebar width mismatch in designTokens
- Fix Kontooversigt breadcrumb pointing to non-existent route
Accessibility:
- Add aria-label to sidebar navigation
- Add +/- prefix to AmountText for color-blind users
- Fix CompanySwitcher permanent skeleton when no companies
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 00:18:19 +01:00
|
|
|
Skeleton,
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
Alert,
|
|
|
|
|
Drawer,
|
|
|
|
|
Descriptions,
|
|
|
|
|
Row,
|
|
|
|
|
Col,
|
|
|
|
|
Statistic,
|
|
|
|
|
DatePicker,
|
|
|
|
|
Divider,
|
|
|
|
|
List,
|
|
|
|
|
Checkbox,
|
|
|
|
|
Radio,
|
|
|
|
|
Tooltip,
|
|
|
|
|
} from 'antd';
|
|
|
|
|
import { showSuccess, showError, showWarning } from '@/lib/errorHandling';
|
|
|
|
|
import {
|
|
|
|
|
PlusOutlined,
|
|
|
|
|
SearchOutlined,
|
|
|
|
|
EyeOutlined,
|
|
|
|
|
CheckOutlined,
|
|
|
|
|
StopOutlined,
|
|
|
|
|
FileTextOutlined,
|
|
|
|
|
ShoppingCartOutlined,
|
|
|
|
|
FileDoneOutlined,
|
|
|
|
|
BarcodeOutlined,
|
|
|
|
|
} from '@ant-design/icons';
|
|
|
|
|
import dayjs from 'dayjs';
|
|
|
|
|
import { useCompany } from '@/hooks/useCompany';
|
|
|
|
|
import { useCurrentFiscalYear } from '@/stores/periodStore';
|
|
|
|
|
import { useOrders } from '@/api/queries/orderQueries';
|
|
|
|
|
import { useActiveCustomers, type Customer } from '@/api/queries/customerQueries';
|
|
|
|
|
import { useActiveProducts, type Product } from '@/api/queries/productQueries';
|
|
|
|
|
import {
|
|
|
|
|
useCreateOrder,
|
|
|
|
|
useAddOrderLine,
|
|
|
|
|
useConfirmOrder,
|
|
|
|
|
useCancelOrder,
|
|
|
|
|
useConvertOrderToInvoice,
|
|
|
|
|
type CreateOrderInput,
|
|
|
|
|
type AddOrderLineInput,
|
|
|
|
|
type CancelOrderInput,
|
|
|
|
|
type InvoiceOrderLinesInput,
|
|
|
|
|
} from '@/api/mutations/orderMutations';
|
|
|
|
|
import { formatCurrency, formatDate } from '@/lib/formatters';
|
|
|
|
|
import { spacing } from '@/styles/designTokens';
|
|
|
|
|
import { accountingColors } from '@/styles/theme';
|
|
|
|
|
import { AmountText } from '@/components/shared/AmountText';
|
|
|
|
|
import { EmptyState } from '@/components/shared/EmptyState';
|
2026-02-05 21:35:26 +01:00
|
|
|
import { PageHeader } from '@/components/shared/PageHeader';
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
import type { ColumnsType } from 'antd/es/table';
|
|
|
|
|
import type { Order, OrderLine, OrderStatus } from '@/types/order';
|
|
|
|
|
import { ORDER_STATUS_LABELS, ORDER_STATUS_COLORS } from '@/types/order';
|
|
|
|
|
|
|
|
|
|
const { Title, Text } = Typography;
|
|
|
|
|
|
|
|
|
|
export default function Ordrer() {
|
|
|
|
|
const { company } = useCompany();
|
|
|
|
|
const currentFiscalYear = useCurrentFiscalYear();
|
|
|
|
|
|
|
|
|
|
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
|
|
|
|
const [isAddLineModalOpen, setIsAddLineModalOpen] = useState(false);
|
|
|
|
|
const [isCancelModalOpen, setIsCancelModalOpen] = useState(false);
|
|
|
|
|
const [isConvertModalOpen, setIsConvertModalOpen] = useState(false);
|
|
|
|
|
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
|
|
|
|
|
const [selectedOrder, setSelectedOrder] = useState<Order | null>(null);
|
|
|
|
|
const [selectedLinesToInvoice, setSelectedLinesToInvoice] = useState<number[]>([]);
|
|
|
|
|
const [searchText, setSearchText] = useState('');
|
|
|
|
|
const [statusFilter, setStatusFilter] = useState<OrderStatus | 'all'>('all');
|
|
|
|
|
const [addLineMode, setAddLineMode] = useState<'product' | 'freetext'>('product');
|
|
|
|
|
const [selectedProductId, setSelectedProductId] = useState<string | null>(null);
|
|
|
|
|
const [createForm] = Form.useForm();
|
|
|
|
|
const [addLineForm] = Form.useForm();
|
|
|
|
|
const [cancelForm] = Form.useForm();
|
|
|
|
|
|
|
|
|
|
// Fetch orders
|
|
|
|
|
const {
|
|
|
|
|
data: orders = [],
|
|
|
|
|
isLoading: loading,
|
|
|
|
|
error,
|
|
|
|
|
refetch,
|
|
|
|
|
} = useOrders(company?.id);
|
|
|
|
|
|
|
|
|
|
// Fetch customers for dropdown
|
|
|
|
|
const { data: customers = [] } = useActiveCustomers(company?.id);
|
|
|
|
|
|
|
|
|
|
// Fetch products for dropdown
|
|
|
|
|
const { data: products = [] } = useActiveProducts(company?.id);
|
|
|
|
|
|
|
|
|
|
// Mutations
|
|
|
|
|
const createOrderMutation = useCreateOrder();
|
|
|
|
|
const addOrderLineMutation = useAddOrderLine();
|
|
|
|
|
const confirmOrderMutation = useConfirmOrder();
|
|
|
|
|
const cancelOrderMutation = useCancelOrder();
|
|
|
|
|
const convertToInvoiceMutation = useConvertOrderToInvoice();
|
|
|
|
|
|
|
|
|
|
// Filter orders
|
|
|
|
|
const filteredOrders = useMemo(() => {
|
|
|
|
|
return orders.filter((order) => {
|
|
|
|
|
const matchesSearch =
|
|
|
|
|
searchText === '' ||
|
|
|
|
|
order.orderNumber.toLowerCase().includes(searchText.toLowerCase()) ||
|
|
|
|
|
order.customerName.toLowerCase().includes(searchText.toLowerCase());
|
|
|
|
|
|
|
|
|
|
const matchesStatus = statusFilter === 'all' || order.status === statusFilter;
|
|
|
|
|
|
|
|
|
|
return matchesSearch && matchesStatus;
|
|
|
|
|
});
|
|
|
|
|
}, [orders, searchText, statusFilter]);
|
|
|
|
|
|
|
|
|
|
// Statistics
|
|
|
|
|
const stats = useMemo(() => {
|
|
|
|
|
const total = orders.length;
|
|
|
|
|
const drafts = orders.filter((o) => o.status === 'draft').length;
|
|
|
|
|
const confirmed = orders.filter((o) => o.status === 'confirmed').length;
|
|
|
|
|
const totalValue = orders
|
|
|
|
|
.filter((o) => o.status !== 'cancelled')
|
|
|
|
|
.reduce((sum, o) => sum + o.amountTotal, 0);
|
|
|
|
|
const invoicedValue = orders.reduce((sum, o) => sum + (o.amountTotal - (o.uninvoicedAmount ?? 0)), 0);
|
|
|
|
|
return { total, drafts, confirmed, totalValue, invoicedValue };
|
|
|
|
|
}, [orders]);
|
|
|
|
|
|
|
|
|
|
const handleCreateOrder = () => {
|
|
|
|
|
createForm.resetFields();
|
|
|
|
|
createForm.setFieldsValue({
|
|
|
|
|
orderDate: dayjs(),
|
|
|
|
|
});
|
|
|
|
|
setIsCreateModalOpen(true);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleSubmitCreate = async () => {
|
|
|
|
|
if (!company || !currentFiscalYear) {
|
2026-02-05 21:35:26 +01:00
|
|
|
showError('Virksomhed eller regnskabsår ikke valgt');
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
const values = await createForm.validateFields();
|
|
|
|
|
const input: CreateOrderInput = {
|
|
|
|
|
companyId: company.id,
|
|
|
|
|
fiscalYearId: currentFiscalYear.id,
|
|
|
|
|
customerId: values.customerId,
|
|
|
|
|
orderDate: values.orderDate?.toISOString(),
|
|
|
|
|
expectedDeliveryDate: values.expectedDeliveryDate?.toISOString(),
|
|
|
|
|
notes: values.notes || undefined,
|
|
|
|
|
reference: values.reference || undefined,
|
|
|
|
|
};
|
|
|
|
|
const result = await createOrderMutation.mutateAsync(input);
|
|
|
|
|
showSuccess('Ordre oprettet');
|
|
|
|
|
setIsCreateModalOpen(false);
|
|
|
|
|
createForm.resetFields();
|
|
|
|
|
setSelectedOrder(result);
|
|
|
|
|
setIsDrawerOpen(true);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
if (err instanceof Error) {
|
|
|
|
|
showError(err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleViewOrder = (order: Order) => {
|
|
|
|
|
setSelectedOrder(order);
|
|
|
|
|
setIsDrawerOpen(true);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleOpenAddLineModal = () => {
|
|
|
|
|
addLineForm.resetFields();
|
|
|
|
|
addLineForm.setFieldsValue({
|
|
|
|
|
quantity: 1,
|
Audit v4: VAT calc, SAF-T compliance, security hardening, frontend quality
Backend (17 files):
- VAT: REP 25% deductibility (§42), EU reverse charge double-entry (IEUV/IEUY/IVY),
IVY rate 0%→25%, VatReport Box C/D populated, Basis1 from real revenue
- SAF-T: correct OECD namespace, closing balance net calc, zero-amount fallback,
credit note auto-numbering (§52)
- Security: BankingController CSRF state token + company auth check,
attachment canonical path traversal check, discount 0-100% validation,
deactivated product/customer update guard
- Quality: redact bank API logs, remove dead code (VatCalcService,
PaymentMatchingService), CompanyAggregate IEmit interfaces, fix URL encoding
Frontend (15 files):
- Fix double "kr." in AmountText and Dashboard Statistic components
- Fix UserSettings Switch defaultChecked desync with Form state
- Remove dual useCompany/useCompanyStore pattern (Dashboard, Moms, Bank)
- Correct SKAT VAT deadline calculation per period type
- Add half-yearly/yearly VAT period options
- Guard console.error with import.meta.env.DEV
- Use shared formatDate in BankConnectionsTab
- Remove dead NONE vatCode check, purge 7 legacy VAT codes from type union
- Migrate S25→U25, K25→I25 across all pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 01:38:52 +01:00
|
|
|
vatCode: 'U25',
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
});
|
|
|
|
|
setAddLineMode('product');
|
|
|
|
|
setSelectedProductId(null);
|
|
|
|
|
setIsAddLineModalOpen(true);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleProductSelect = (productId: string) => {
|
|
|
|
|
setSelectedProductId(productId);
|
|
|
|
|
const product = products.find((p: Product) => p.id === productId);
|
|
|
|
|
if (product) {
|
|
|
|
|
addLineForm.setFieldsValue({
|
|
|
|
|
description: product.name,
|
|
|
|
|
unitPrice: product.unitPrice,
|
|
|
|
|
unit: product.unit || 'stk',
|
Audit v4: VAT calc, SAF-T compliance, security hardening, frontend quality
Backend (17 files):
- VAT: REP 25% deductibility (§42), EU reverse charge double-entry (IEUV/IEUY/IVY),
IVY rate 0%→25%, VatReport Box C/D populated, Basis1 from real revenue
- SAF-T: correct OECD namespace, closing balance net calc, zero-amount fallback,
credit note auto-numbering (§52)
- Security: BankingController CSRF state token + company auth check,
attachment canonical path traversal check, discount 0-100% validation,
deactivated product/customer update guard
- Quality: redact bank API logs, remove dead code (VatCalcService,
PaymentMatchingService), CompanyAggregate IEmit interfaces, fix URL encoding
Frontend (15 files):
- Fix double "kr." in AmountText and Dashboard Statistic components
- Fix UserSettings Switch defaultChecked desync with Form state
- Remove dual useCompany/useCompanyStore pattern (Dashboard, Moms, Bank)
- Correct SKAT VAT deadline calculation per period type
- Add half-yearly/yearly VAT period options
- Guard console.error with import.meta.env.DEV
- Use shared formatDate in BankConnectionsTab
- Remove dead NONE vatCode check, purge 7 legacy VAT codes from type union
- Migrate S25→U25, K25→I25 across all pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 01:38:52 +01:00
|
|
|
vatCode: product.vatCode || 'U25',
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleSubmitAddLine = async () => {
|
|
|
|
|
if (!selectedOrder) return;
|
|
|
|
|
try {
|
|
|
|
|
const values = await addLineForm.validateFields();
|
|
|
|
|
const input: AddOrderLineInput = {
|
|
|
|
|
orderId: selectedOrder.id,
|
|
|
|
|
productId: addLineMode === 'product' && selectedProductId ? selectedProductId : undefined,
|
|
|
|
|
description: values.description,
|
|
|
|
|
quantity: Number(values.quantity),
|
|
|
|
|
unitPrice: Number(values.unitPrice),
|
|
|
|
|
unit: values.unit || undefined,
|
|
|
|
|
discountPercent: values.discountPercent ? Number(values.discountPercent) : undefined,
|
|
|
|
|
vatCode: values.vatCode,
|
|
|
|
|
};
|
|
|
|
|
const updatedOrder = await addOrderLineMutation.mutateAsync(input);
|
|
|
|
|
showSuccess('Linje tilføjet');
|
|
|
|
|
setIsAddLineModalOpen(false);
|
|
|
|
|
addLineForm.resetFields();
|
|
|
|
|
setSelectedProductId(null);
|
|
|
|
|
setSelectedOrder(updatedOrder);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
if (err instanceof Error) {
|
|
|
|
|
showError(err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleConfirmOrder = async () => {
|
|
|
|
|
if (!selectedOrder) return;
|
|
|
|
|
if (selectedOrder.lines.length === 0) {
|
2026-02-05 21:35:26 +01:00
|
|
|
showWarning('Tilføj mindst en linje før bekræftelse');
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
await confirmOrderMutation.mutateAsync(selectedOrder.id);
|
2026-02-05 21:35:26 +01:00
|
|
|
showSuccess('Ordre bekræftet');
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
// Refresh would happen via query invalidation
|
|
|
|
|
} catch (err) {
|
|
|
|
|
if (err instanceof Error) {
|
|
|
|
|
showError(err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleOpenCancelModal = () => {
|
|
|
|
|
cancelForm.resetFields();
|
|
|
|
|
setIsCancelModalOpen(true);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleSubmitCancel = async () => {
|
|
|
|
|
if (!selectedOrder) return;
|
|
|
|
|
try {
|
|
|
|
|
const values = await cancelForm.validateFields();
|
|
|
|
|
const input: CancelOrderInput = {
|
|
|
|
|
orderId: selectedOrder.id,
|
|
|
|
|
reason: values.reason,
|
|
|
|
|
};
|
|
|
|
|
await cancelOrderMutation.mutateAsync(input);
|
|
|
|
|
showSuccess('Ordre annulleret');
|
|
|
|
|
setIsCancelModalOpen(false);
|
|
|
|
|
cancelForm.resetFields();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
if (err instanceof Error) {
|
|
|
|
|
showError(err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleOpenConvertModal = () => {
|
|
|
|
|
if (!selectedOrder) return;
|
|
|
|
|
// Pre-select uninvoiced lines
|
|
|
|
|
const uninvoicedLines = selectedOrder.lines
|
|
|
|
|
.filter((line) => !line.isInvoiced)
|
|
|
|
|
.map((line) => line.lineNumber);
|
|
|
|
|
setSelectedLinesToInvoice(uninvoicedLines);
|
|
|
|
|
setIsConvertModalOpen(true);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleSubmitConvert = async () => {
|
|
|
|
|
if (!selectedOrder || selectedLinesToInvoice.length === 0) {
|
2026-02-05 21:35:26 +01:00
|
|
|
showWarning('Vælg mindst en linje at fakturere');
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
const input: InvoiceOrderLinesInput = {
|
|
|
|
|
orderId: selectedOrder.id,
|
|
|
|
|
lineNumbers: selectedLinesToInvoice,
|
|
|
|
|
};
|
|
|
|
|
const invoice = await convertToInvoiceMutation.mutateAsync(input);
|
|
|
|
|
showSuccess(`Faktura ${invoice.invoiceNumber} oprettet fra ordre`);
|
|
|
|
|
setIsConvertModalOpen(false);
|
|
|
|
|
setSelectedLinesToInvoice([]);
|
|
|
|
|
// Refresh the selected order to show updated invoice tracking
|
|
|
|
|
refetch();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
if (err instanceof Error) {
|
|
|
|
|
showError(err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Check if order can show the convert to invoice button
|
|
|
|
|
const canShowConvertToInvoice = (order: Order): boolean => {
|
|
|
|
|
if (order.status === 'cancelled' || order.status === 'fully_invoiced') {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Show for draft (disabled) and confirmed/partially_invoiced (enabled)
|
|
|
|
|
return order.status === 'draft' || order.lines.some((line) => !line.isInvoiced);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Check if convert to invoice button should be disabled
|
|
|
|
|
const isConvertToInvoiceDisabled = (order: Order): boolean => {
|
|
|
|
|
if (order.status === 'draft') {
|
|
|
|
|
return true; // Must confirm order first
|
|
|
|
|
}
|
|
|
|
|
return !order.lines.some((line) => !line.isInvoiced);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const columns: ColumnsType<Order> = [
|
|
|
|
|
{
|
|
|
|
|
title: 'Ordrenr.',
|
|
|
|
|
dataIndex: 'orderNumber',
|
|
|
|
|
key: 'orderNumber',
|
|
|
|
|
width: 140,
|
|
|
|
|
sorter: (a, b) => a.orderNumber.localeCompare(b.orderNumber),
|
|
|
|
|
render: (value: string) => <Text code>{value}</Text>,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Kunde',
|
|
|
|
|
dataIndex: 'customerName',
|
|
|
|
|
key: 'customerName',
|
|
|
|
|
sorter: (a, b) => a.customerName.localeCompare(b.customerName),
|
|
|
|
|
ellipsis: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Dato',
|
|
|
|
|
dataIndex: 'orderDate',
|
|
|
|
|
key: 'orderDate',
|
|
|
|
|
width: 100,
|
|
|
|
|
sorter: (a, b) => (a.orderDate || '').localeCompare(b.orderDate || ''),
|
|
|
|
|
render: (value: string | undefined) => (value ? formatDate(value) : '-'),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Forventet levering',
|
|
|
|
|
dataIndex: 'expectedDeliveryDate',
|
|
|
|
|
key: 'expectedDeliveryDate',
|
|
|
|
|
width: 130,
|
|
|
|
|
render: (value: string | undefined) => (value ? formatDate(value) : '-'),
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-02-05 21:35:26 +01:00
|
|
|
title: 'Beløb',
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
dataIndex: 'amountTotal',
|
|
|
|
|
key: 'amountTotal',
|
|
|
|
|
width: 120,
|
|
|
|
|
align: 'right',
|
|
|
|
|
sorter: (a, b) => a.amountTotal - b.amountTotal,
|
|
|
|
|
render: (value: number) => <AmountText amount={value} />,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Faktureret',
|
|
|
|
|
dataIndex: 'amountInvoiced',
|
|
|
|
|
key: 'amountInvoiced',
|
|
|
|
|
width: 120,
|
|
|
|
|
align: 'right',
|
|
|
|
|
render: (value: number, record: Order) =>
|
|
|
|
|
record.status === 'cancelled' ? '-' : <AmountText amount={value} />,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Status',
|
|
|
|
|
dataIndex: 'status',
|
|
|
|
|
key: 'status',
|
|
|
|
|
width: 140,
|
|
|
|
|
align: 'center',
|
|
|
|
|
filters: [
|
|
|
|
|
{ text: 'Kladde', value: 'draft' },
|
2026-02-05 21:35:26 +01:00
|
|
|
{ text: 'Bekræftet', value: 'confirmed' },
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
{ text: 'Delvist faktureret', value: 'partially_invoiced' },
|
|
|
|
|
{ text: 'Fuldt faktureret', value: 'fully_invoiced' },
|
|
|
|
|
{ text: 'Annulleret', value: 'cancelled' },
|
|
|
|
|
],
|
|
|
|
|
onFilter: (value, record) => record.status === value,
|
|
|
|
|
render: (value: OrderStatus) => (
|
|
|
|
|
<Tag color={ORDER_STATUS_COLORS[value]}>{ORDER_STATUS_LABELS[value]}</Tag>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '',
|
|
|
|
|
key: 'actions',
|
|
|
|
|
width: 80,
|
|
|
|
|
align: 'center',
|
|
|
|
|
render: (_: unknown, record: Order) => (
|
|
|
|
|
<Button
|
|
|
|
|
type="text"
|
|
|
|
|
size="small"
|
|
|
|
|
icon={<EyeOutlined />}
|
|
|
|
|
onClick={() => handleViewOrder(record)}
|
|
|
|
|
/>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div>
|
2026-02-05 21:35:26 +01:00
|
|
|
<PageHeader
|
|
|
|
|
title="Ordrer"
|
|
|
|
|
subtitle={company?.name}
|
|
|
|
|
breadcrumbs={[{ title: 'Fakturering', path: '/fakturaer' }, { title: 'Ordrer' }]}
|
|
|
|
|
extra={
|
|
|
|
|
<Button type="primary" icon={<PlusOutlined />} onClick={handleCreateOrder}>
|
|
|
|
|
Ny ordre
|
|
|
|
|
</Button>
|
|
|
|
|
}
|
|
|
|
|
/>
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
|
|
|
|
|
{/* Error State */}
|
|
|
|
|
{error && (
|
|
|
|
|
<Alert
|
2026-02-05 21:35:26 +01:00
|
|
|
message="Fejl ved indlæsning af ordrer"
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
description={error.message}
|
|
|
|
|
type="error"
|
|
|
|
|
showIcon
|
|
|
|
|
style={{ marginBottom: spacing.lg }}
|
|
|
|
|
action={
|
|
|
|
|
<Button size="small" onClick={() => refetch()}>
|
2026-02-05 21:35:26 +01:00
|
|
|
Prøv igen
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
</Button>
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{/* Statistics */}
|
|
|
|
|
<Row gutter={[spacing.lg, spacing.lg]} style={{ marginBottom: spacing.lg }}>
|
|
|
|
|
<Col xs={12} sm={6}>
|
|
|
|
|
<Card size="small">
|
|
|
|
|
<Statistic title="Ordrer i alt" value={stats.total} />
|
|
|
|
|
</Card>
|
|
|
|
|
</Col>
|
|
|
|
|
<Col xs={12} sm={6}>
|
|
|
|
|
<Card size="small">
|
|
|
|
|
<Statistic
|
|
|
|
|
title="Kladder"
|
|
|
|
|
value={stats.drafts}
|
|
|
|
|
valueStyle={{ color: '#8c8c8c' }}
|
|
|
|
|
/>
|
|
|
|
|
</Card>
|
|
|
|
|
</Col>
|
|
|
|
|
<Col xs={12} sm={6}>
|
|
|
|
|
<Card size="small">
|
|
|
|
|
<Statistic
|
2026-02-05 21:35:26 +01:00
|
|
|
title="Bekræftede"
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
value={stats.confirmed}
|
|
|
|
|
valueStyle={{ color: accountingColors.credit }}
|
|
|
|
|
/>
|
|
|
|
|
</Card>
|
|
|
|
|
</Col>
|
|
|
|
|
<Col xs={12} sm={6}>
|
|
|
|
|
<Card size="small">
|
|
|
|
|
<Statistic
|
2026-02-05 21:35:26 +01:00
|
|
|
title="Samlet værdi"
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
value={stats.totalValue}
|
|
|
|
|
precision={2}
|
|
|
|
|
valueStyle={{ color: accountingColors.credit }}
|
|
|
|
|
formatter={(value) => formatCurrency(value as number)}
|
|
|
|
|
/>
|
|
|
|
|
</Card>
|
|
|
|
|
</Col>
|
|
|
|
|
</Row>
|
|
|
|
|
|
|
|
|
|
{/* Filters */}
|
|
|
|
|
<Card size="small" style={{ marginBottom: spacing.lg }}>
|
|
|
|
|
<Space wrap>
|
|
|
|
|
<Input
|
2026-02-05 21:35:26 +01:00
|
|
|
placeholder="Søg ordre..."
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
prefix={<SearchOutlined />}
|
|
|
|
|
value={searchText}
|
|
|
|
|
onChange={(e) => setSearchText(e.target.value)}
|
|
|
|
|
style={{ width: 250 }}
|
|
|
|
|
allowClear
|
|
|
|
|
/>
|
|
|
|
|
<Select
|
|
|
|
|
value={statusFilter}
|
|
|
|
|
onChange={setStatusFilter}
|
|
|
|
|
style={{ width: 180 }}
|
|
|
|
|
options={[
|
|
|
|
|
{ value: 'all', label: 'Alle status' },
|
|
|
|
|
{ value: 'draft', label: 'Kladde' },
|
2026-02-05 21:35:26 +01:00
|
|
|
{ value: 'confirmed', label: 'Bekræftet' },
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
{ value: 'partially_invoiced', label: 'Delvist faktureret' },
|
|
|
|
|
{ value: 'fully_invoiced', label: 'Fuldt faktureret' },
|
|
|
|
|
{ value: 'cancelled', label: 'Annulleret' },
|
|
|
|
|
]}
|
|
|
|
|
/>
|
|
|
|
|
</Space>
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
{/* Order Table */}
|
|
|
|
|
<Card size="small">
|
|
|
|
|
{loading ? (
|
Audit v2: fix security, data integrity, compliance, bugs, encoding, UX
Backend Security & Data Integrity:
- Block negative debit/credit amounts that bypass balance validation
- Require document date at posting (was optional, bypassing fiscal year checks)
- Fix event sourcing anti-pattern: timestamps now stored in events, not UtcNow in Apply
- Add [Authorize] to BankingController OAuth callback
- Add company access check on attachment downloads
- Validate CVR in CompanyAggregate.Create and CompanyAggregate.Update
- Require company CVR for invoice creation (Momsloven §52)
- Delete leftover WeatherForecastController
- Fix duplicate migration number 007 (renamed to 007b)
- Remove dead code in VatCalculationService (identical if/else branches)
Accounting Compliance:
- Add missing VAT accounts to StandardDanishAccounts (5610, 5611, 5620)
- Populate SAF-T TaxInformation on transaction lines (was always null)
- Add AuditFileCountry and TaxRegistrationNumber to SAF-T header
Critical Frontend Bugs:
- Fix Dashboard <a href> causing full page reloads (now uses React Router Link)
- Wire Kassekladde filters to actual data (account, status, date range)
- Pre-populate form when editing existing Kassekladde drafts
- Add detail drawer for "Vis detaljer" action (was just a toast)
- Toggle advanced filters with "Flere filtre" button
- CloseFiscalYearWizard now actually posts closing entries via mutations
- "Create next year" checkbox now creates the next fiscal year
Danish Character Encoding (~50 fixes):
- Fix ø/æ/å across Momsindberetning, DocumentUploadModal, Bankafstemning,
Kontooversigt, CloseFiscalYearWizard, vatCodes, periodStore, periods,
accounting, types/periods
Dead Buttons & UX:
- Disable Momsindberetning PDF/Export buttons with tooltips
- FiscalYearSelector "Administrer" now navigates to Settings
- Settings bank tab now uses real BankConnectionsTab component
- Bankafstemning save button disabled with development tooltip
- Replace hardcoded account options with real API data (Bankafstemning, Fakturaer)
- Header help button shows info message, notification bell shows popover
Consistency & Quality:
- Remove 7 console.log statements from production code
- Adopt PageHeader on 6 remaining pages (Kreditnotaer, Settings, Admin, etc.)
- Standardize loading states to Skeleton pattern (5 pages)
- Replace deprecated bodyStyle prop on Ant Design Cards
- Standardize date format to DD-MM-YYYY
- Fix sidebar width mismatch in designTokens
- Fix Kontooversigt breadcrumb pointing to non-existent route
Accessibility:
- Add aria-label to sidebar navigation
- Add +/- prefix to AmountText for color-blind users
- Fix CompanySwitcher permanent skeleton when no companies
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 00:18:19 +01:00
|
|
|
<Skeleton active paragraph={{ rows: 8 }} />
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
) : filteredOrders.length > 0 ? (
|
|
|
|
|
<Table
|
|
|
|
|
dataSource={filteredOrders}
|
|
|
|
|
columns={columns}
|
|
|
|
|
rowKey="id"
|
|
|
|
|
size="small"
|
|
|
|
|
pagination={{ pageSize: 20, showSizeChanger: true }}
|
|
|
|
|
/>
|
|
|
|
|
) : (
|
|
|
|
|
<EmptyState
|
|
|
|
|
variant="default"
|
|
|
|
|
title="Ingen ordrer"
|
2026-02-05 21:35:26 +01:00
|
|
|
description={searchText ? 'Ingen ordrer matcher din søgning' : 'Opret din første ordre'}
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
primaryAction={
|
|
|
|
|
!searchText
|
|
|
|
|
? {
|
|
|
|
|
label: 'Opret ordre',
|
|
|
|
|
onClick: handleCreateOrder,
|
|
|
|
|
icon: <PlusOutlined />,
|
|
|
|
|
}
|
|
|
|
|
: undefined
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
{/* Create Order Modal */}
|
|
|
|
|
<Modal
|
|
|
|
|
title="Opret ordre"
|
|
|
|
|
open={isCreateModalOpen}
|
|
|
|
|
onCancel={() => setIsCreateModalOpen(false)}
|
|
|
|
|
onOk={handleSubmitCreate}
|
|
|
|
|
okText="Opret"
|
|
|
|
|
cancelText="Annuller"
|
|
|
|
|
confirmLoading={createOrderMutation.isPending}
|
|
|
|
|
>
|
|
|
|
|
<Form form={createForm} layout="vertical">
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="customerId"
|
|
|
|
|
label="Kunde"
|
2026-02-05 21:35:26 +01:00
|
|
|
rules={[{ required: true, message: 'Vælg kunde' }]}
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
>
|
|
|
|
|
<Select
|
|
|
|
|
showSearch
|
2026-02-05 21:35:26 +01:00
|
|
|
placeholder="Vælg kunde"
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
optionFilterProp="children"
|
|
|
|
|
filterOption={(input, option) =>
|
|
|
|
|
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
|
|
|
|
|
}
|
|
|
|
|
options={customers.map((c: Customer) => ({
|
|
|
|
|
value: c.id,
|
|
|
|
|
label: `${c.customerNumber} - ${c.name}`,
|
|
|
|
|
}))}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
<Row gutter={16}>
|
|
|
|
|
<Col span={12}>
|
|
|
|
|
<Form.Item name="orderDate" label="Ordredato">
|
|
|
|
|
<DatePicker style={{ width: '100%' }} format="DD-MM-YYYY" />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Col>
|
|
|
|
|
<Col span={12}>
|
|
|
|
|
<Form.Item name="expectedDeliveryDate" label="Forventet levering">
|
|
|
|
|
<DatePicker style={{ width: '100%' }} format="DD-MM-YYYY" />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Col>
|
|
|
|
|
</Row>
|
|
|
|
|
<Form.Item name="reference" label="Reference">
|
|
|
|
|
<Input placeholder="Projektnavn, tilbudsnr., etc." />
|
|
|
|
|
</Form.Item>
|
2026-02-05 21:35:26 +01:00
|
|
|
<Form.Item name="notes" label="Bemærkninger">
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
<Input.TextArea rows={2} />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Form>
|
|
|
|
|
</Modal>
|
|
|
|
|
|
|
|
|
|
{/* Order Detail Drawer */}
|
|
|
|
|
<Drawer
|
|
|
|
|
title={
|
|
|
|
|
selectedOrder && (
|
|
|
|
|
<Space>
|
|
|
|
|
<ShoppingCartOutlined />
|
|
|
|
|
<span>Ordre {selectedOrder.orderNumber}</span>
|
|
|
|
|
<Tag color={ORDER_STATUS_COLORS[selectedOrder.status]}>
|
|
|
|
|
{ORDER_STATUS_LABELS[selectedOrder.status]}
|
|
|
|
|
</Tag>
|
|
|
|
|
</Space>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
placement="right"
|
|
|
|
|
width={700}
|
|
|
|
|
open={isDrawerOpen}
|
|
|
|
|
onClose={() => {
|
|
|
|
|
setIsDrawerOpen(false);
|
|
|
|
|
setSelectedOrder(null);
|
|
|
|
|
}}
|
|
|
|
|
extra={
|
|
|
|
|
selectedOrder && (
|
|
|
|
|
<Space>
|
|
|
|
|
{selectedOrder.status === 'draft' && (
|
|
|
|
|
<>
|
|
|
|
|
<Button
|
|
|
|
|
icon={<PlusOutlined />}
|
|
|
|
|
onClick={handleOpenAddLineModal}
|
|
|
|
|
loading={addOrderLineMutation.isPending}
|
|
|
|
|
>
|
2026-02-05 21:35:26 +01:00
|
|
|
Tilføj linje
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
type="primary"
|
|
|
|
|
icon={<CheckOutlined />}
|
|
|
|
|
onClick={handleConfirmOrder}
|
|
|
|
|
loading={confirmOrderMutation.isPending}
|
|
|
|
|
disabled={selectedOrder.lines.length === 0}
|
|
|
|
|
>
|
2026-02-05 21:35:26 +01:00
|
|
|
Bekræft
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
</Button>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
{canShowConvertToInvoice(selectedOrder) && (
|
|
|
|
|
<Tooltip
|
2026-02-05 21:35:26 +01:00
|
|
|
title={selectedOrder.status === 'draft' ? 'Bekræft ordren først' : undefined}
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
>
|
|
|
|
|
<Button
|
|
|
|
|
type="primary"
|
|
|
|
|
icon={<FileDoneOutlined />}
|
|
|
|
|
onClick={handleOpenConvertModal}
|
|
|
|
|
disabled={isConvertToInvoiceDisabled(selectedOrder)}
|
|
|
|
|
>
|
|
|
|
|
Opret faktura
|
|
|
|
|
</Button>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
)}
|
|
|
|
|
{selectedOrder.status !== 'cancelled' && selectedOrder.status !== 'fully_invoiced' && (
|
|
|
|
|
<Button danger icon={<StopOutlined />} onClick={handleOpenCancelModal}>
|
|
|
|
|
Annuller
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
</Space>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
{selectedOrder && (
|
|
|
|
|
<div>
|
|
|
|
|
<Descriptions column={2} size="small" bordered style={{ marginBottom: spacing.lg }}>
|
|
|
|
|
<Descriptions.Item label="Kunde" span={2}>
|
|
|
|
|
{selectedOrder.customerName}
|
|
|
|
|
</Descriptions.Item>
|
|
|
|
|
<Descriptions.Item label="Ordredato">
|
|
|
|
|
{selectedOrder.orderDate ? formatDate(selectedOrder.orderDate) : '-'}
|
|
|
|
|
</Descriptions.Item>
|
|
|
|
|
<Descriptions.Item label="Forventet levering">
|
|
|
|
|
{selectedOrder.expectedDeliveryDate ? formatDate(selectedOrder.expectedDeliveryDate) : '-'}
|
|
|
|
|
</Descriptions.Item>
|
|
|
|
|
{selectedOrder.reference && (
|
|
|
|
|
<Descriptions.Item label="Reference" span={2}>
|
|
|
|
|
{selectedOrder.reference}
|
|
|
|
|
</Descriptions.Item>
|
|
|
|
|
)}
|
|
|
|
|
</Descriptions>
|
|
|
|
|
|
|
|
|
|
<Title level={5}>Linjer</Title>
|
|
|
|
|
{selectedOrder.lines.length > 0 ? (
|
|
|
|
|
<List
|
|
|
|
|
size="small"
|
|
|
|
|
bordered
|
|
|
|
|
dataSource={selectedOrder.lines}
|
|
|
|
|
renderItem={(line: OrderLine) => {
|
|
|
|
|
const linkedProduct = line.productId
|
|
|
|
|
? products.find((p: Product) => p.id === line.productId)
|
|
|
|
|
: null;
|
|
|
|
|
return (
|
|
|
|
|
<List.Item>
|
|
|
|
|
<List.Item.Meta
|
|
|
|
|
title={
|
|
|
|
|
<Space>
|
|
|
|
|
<span>{line.description}</span>
|
|
|
|
|
{line.productId && (
|
|
|
|
|
<Tag color="purple" icon={<BarcodeOutlined />}>
|
|
|
|
|
{linkedProduct?.productNumber || 'Produkt'}
|
|
|
|
|
</Tag>
|
|
|
|
|
)}
|
|
|
|
|
{line.isInvoiced && (
|
|
|
|
|
<Tag color="green" icon={<FileTextOutlined />}>
|
|
|
|
|
Faktureret
|
|
|
|
|
</Tag>
|
|
|
|
|
)}
|
|
|
|
|
</Space>
|
|
|
|
|
}
|
|
|
|
|
description={
|
|
|
|
|
<Space>
|
|
|
|
|
<span>
|
|
|
|
|
{line.quantity} {line.unit || 'stk'} x {formatCurrency(line.unitPrice)}
|
|
|
|
|
</span>
|
|
|
|
|
{line.discountPercent > 0 && (
|
|
|
|
|
<Tag color="orange">-{line.discountPercent}%</Tag>
|
|
|
|
|
)}
|
|
|
|
|
<Tag>{line.vatCode}</Tag>
|
|
|
|
|
{line.isInvoiced && line.invoicedAt && (
|
|
|
|
|
<Tag color="blue">
|
Audit v3: VAT alignment, security, encoding, UX, compliance
VAT System Alignment (LEGAL - Critical):
- Align frontend VAT codes with backend (S25→U25, K25→I25, etc.)
- Add missing codes: UEU, IVV, IVY, REP
- Fix output VAT account 5710→5611 to match StandardDanishAccounts
- Invoice posting now checks fiscal year status before allowing send
- Disallow custom invoice number override (always use auto-numbering)
Security:
- Fix open redirect in AuthController (validate returnUrl is local)
- Store seller CVR/name/address on invoice events (Momsloven §52)
Backend Compliance:
- Add description validation at posting (Bogføringsloven §7)
- SAF-T: add DefaultCurrencyCode, TaxAccountingBasis to header
- SAF-T: add TaxTable to MasterFiles with all VAT codes
- SAF-T: always write balance elements even when zero
- Add financial income account 9100 Renteindtægter
Danish Encoding (~25 fixes):
- Kassekladde: Bogført, Bogføring, Vælg, være, på, Tilføj, Differens
- AttachmentUpload: træk, Understøtter, påkrævet, Bogføringsloven
- keyboardShortcuts: Bogfør, Bogføring display name
- ShortcutsHelpModal: åbne
- DataTable: Genindlæs
- documentProcessing: være
- CloseFiscalYearWizard: årsafslutning
Bugs Fixed:
- Non-null assertion crashes in Kunder.tsx and Produkter.tsx (company!.id)
- StatusBadge typo "Succces"→"Succes"
- HTML entity ø in Kassekladde→proper UTF-8
- AmountText showSign prop was dead code (true || showSign)
UX Improvements:
- Add PageHeader to Bankafstemning and Dashboard loading/empty states
- Responsive columns in Bankafstemning (xs/sm/lg breakpoints)
- Disable misleading buttons: Settings preferences, Kontooversigt edit,
Loenforstaelse export — with tooltips explaining status
- Add DemoDataDisclaimer to UserSettings
- Fix breadcrumb self-references on 3 pages
- Replace Dashboard fake progress bar with honest message
- Standardize date format DD-MM-YYYY in Bankafstemning and Ordrer
- Replace Input type="number" with InputNumber in Ordrer
Quality:
- Remove 8 redundant console.error statements
- Fix Kreditnotaer breadcrumb "Salg"→"Fakturering" for consistency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 01:15:45 +01:00
|
|
|
Faktureret: {dayjs(line.invoicedAt).format('DD-MM-YYYY')}
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
</Tag>
|
|
|
|
|
)}
|
|
|
|
|
</Space>
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
<AmountText amount={line.amountTotal} style={{ fontWeight: 'bold' }} />
|
|
|
|
|
</List.Item>
|
|
|
|
|
);
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
) : (
|
|
|
|
|
<Alert
|
|
|
|
|
message="Ingen linjer endnu"
|
2026-02-05 21:35:26 +01:00
|
|
|
description="Tilføj linjer for at kunne bekræfte ordren."
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
type="info"
|
|
|
|
|
showIcon
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<Divider />
|
|
|
|
|
|
|
|
|
|
<Row gutter={16}>
|
|
|
|
|
<Col span={12}>
|
|
|
|
|
{selectedOrder.notes && (
|
|
|
|
|
<>
|
2026-02-05 21:35:26 +01:00
|
|
|
<Text type="secondary">Bemærkninger:</Text>
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
<p>{selectedOrder.notes}</p>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
{selectedOrder.cancelledReason && (
|
|
|
|
|
<>
|
2026-02-05 21:35:26 +01:00
|
|
|
<Text type="secondary">Annulleringsårsag:</Text>
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
<p style={{ color: 'red' }}>{selectedOrder.cancelledReason}</p>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</Col>
|
|
|
|
|
<Col span={12}>
|
|
|
|
|
<div style={{ textAlign: 'right' }}>
|
|
|
|
|
<div style={{ marginBottom: 4 }}>
|
2026-02-05 21:35:26 +01:00
|
|
|
<Text type="secondary">Beløb ex. moms: </Text>
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
<Text>{formatCurrency(selectedOrder.amountExVat)}</Text>
|
|
|
|
|
</div>
|
|
|
|
|
<div style={{ marginBottom: 4 }}>
|
|
|
|
|
<Text type="secondary">Moms: </Text>
|
|
|
|
|
<Text>{formatCurrency(selectedOrder.amountVat)}</Text>
|
|
|
|
|
</div>
|
|
|
|
|
<div style={{ marginBottom: 4 }}>
|
|
|
|
|
<Text strong>Total: </Text>
|
|
|
|
|
<Text strong style={{ fontSize: 16 }}>
|
|
|
|
|
{formatCurrency(selectedOrder.amountTotal)}
|
|
|
|
|
</Text>
|
|
|
|
|
</div>
|
|
|
|
|
{(selectedOrder.uninvoicedAmount ?? selectedOrder.amountTotal) < selectedOrder.amountTotal && (
|
|
|
|
|
<div style={{ marginBottom: 4 }}>
|
|
|
|
|
<Text type="secondary">Faktureret: </Text>
|
|
|
|
|
<Text type="success">{formatCurrency(selectedOrder.amountTotal - (selectedOrder.uninvoicedAmount ?? 0))}</Text>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
{(selectedOrder.uninvoicedAmount ?? 0) > 0 &&
|
|
|
|
|
selectedOrder.status !== 'cancelled' && (
|
|
|
|
|
<div>
|
|
|
|
|
<Text type="secondary">Resterende: </Text>
|
|
|
|
|
<Text type="warning" strong>
|
|
|
|
|
{formatCurrency(selectedOrder.uninvoicedAmount ?? 0)}
|
|
|
|
|
</Text>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</Col>
|
|
|
|
|
</Row>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</Drawer>
|
|
|
|
|
|
|
|
|
|
{/* Cancel Order Modal */}
|
|
|
|
|
<Modal
|
|
|
|
|
title="Annuller ordre"
|
|
|
|
|
open={isCancelModalOpen}
|
|
|
|
|
onCancel={() => setIsCancelModalOpen(false)}
|
|
|
|
|
onOk={handleSubmitCancel}
|
|
|
|
|
okText="Annuller ordre"
|
|
|
|
|
okButtonProps={{ danger: true }}
|
|
|
|
|
cancelText="Fortryd"
|
|
|
|
|
confirmLoading={cancelOrderMutation.isPending}
|
|
|
|
|
>
|
|
|
|
|
<Alert
|
|
|
|
|
message="Advarsel"
|
2026-02-05 21:35:26 +01:00
|
|
|
description="At annullere ordren kan ikke fortrydes. Eventuelle delfaktureringer forbliver uændrede."
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
type="warning"
|
|
|
|
|
showIcon
|
|
|
|
|
style={{ marginBottom: spacing.lg }}
|
|
|
|
|
/>
|
|
|
|
|
<Form form={cancelForm} layout="vertical">
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="reason"
|
2026-02-05 21:35:26 +01:00
|
|
|
label="Årsag til annullering"
|
|
|
|
|
rules={[{ required: true, message: 'Angiv årsag' }]}
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
>
|
|
|
|
|
<Input.TextArea rows={3} placeholder="Beskriv hvorfor ordren annulleres" />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Form>
|
|
|
|
|
</Modal>
|
|
|
|
|
|
|
|
|
|
{/* Add Line Modal */}
|
|
|
|
|
<Modal
|
2026-02-05 21:35:26 +01:00
|
|
|
title="Tilføj linje"
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
open={isAddLineModalOpen}
|
|
|
|
|
onCancel={() => {
|
|
|
|
|
setIsAddLineModalOpen(false);
|
|
|
|
|
setSelectedProductId(null);
|
|
|
|
|
}}
|
|
|
|
|
onOk={handleSubmitAddLine}
|
2026-02-05 21:35:26 +01:00
|
|
|
okText="Tilføj"
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
cancelText="Annuller"
|
|
|
|
|
confirmLoading={addOrderLineMutation.isPending}
|
|
|
|
|
width={550}
|
|
|
|
|
>
|
|
|
|
|
<Form form={addLineForm} layout="vertical">
|
|
|
|
|
<Form.Item label="Linjetype" style={{ marginBottom: spacing.md }}>
|
|
|
|
|
<Radio.Group
|
|
|
|
|
value={addLineMode}
|
|
|
|
|
onChange={(e) => {
|
|
|
|
|
setAddLineMode(e.target.value);
|
|
|
|
|
setSelectedProductId(null);
|
|
|
|
|
addLineForm.resetFields();
|
|
|
|
|
addLineForm.setFieldsValue({
|
|
|
|
|
quantity: 1,
|
Audit v4: VAT calc, SAF-T compliance, security hardening, frontend quality
Backend (17 files):
- VAT: REP 25% deductibility (§42), EU reverse charge double-entry (IEUV/IEUY/IVY),
IVY rate 0%→25%, VatReport Box C/D populated, Basis1 from real revenue
- SAF-T: correct OECD namespace, closing balance net calc, zero-amount fallback,
credit note auto-numbering (§52)
- Security: BankingController CSRF state token + company auth check,
attachment canonical path traversal check, discount 0-100% validation,
deactivated product/customer update guard
- Quality: redact bank API logs, remove dead code (VatCalcService,
PaymentMatchingService), CompanyAggregate IEmit interfaces, fix URL encoding
Frontend (15 files):
- Fix double "kr." in AmountText and Dashboard Statistic components
- Fix UserSettings Switch defaultChecked desync with Form state
- Remove dual useCompany/useCompanyStore pattern (Dashboard, Moms, Bank)
- Correct SKAT VAT deadline calculation per period type
- Add half-yearly/yearly VAT period options
- Guard console.error with import.meta.env.DEV
- Use shared formatDate in BankConnectionsTab
- Remove dead NONE vatCode check, purge 7 legacy VAT codes from type union
- Migrate S25→U25, K25→I25 across all pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 01:38:52 +01:00
|
|
|
vatCode: 'U25',
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
optionType="button"
|
|
|
|
|
buttonStyle="solid"
|
|
|
|
|
>
|
2026-02-05 21:35:26 +01:00
|
|
|
<Radio.Button value="product">Vælg produkt</Radio.Button>
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
<Radio.Button value="freetext">Fritekst</Radio.Button>
|
|
|
|
|
</Radio.Group>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
{addLineMode === 'product' && (
|
|
|
|
|
<Form.Item
|
|
|
|
|
label="Produkt"
|
|
|
|
|
required
|
|
|
|
|
validateStatus={addLineMode === 'product' && !selectedProductId ? 'error' : undefined}
|
2026-02-05 21:35:26 +01:00
|
|
|
help={addLineMode === 'product' && !selectedProductId ? 'Vælg et produkt' : undefined}
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
>
|
|
|
|
|
<Select
|
|
|
|
|
showSearch
|
2026-02-05 21:35:26 +01:00
|
|
|
placeholder="Søg efter produkt..."
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
optionFilterProp="children"
|
|
|
|
|
value={selectedProductId}
|
|
|
|
|
onChange={handleProductSelect}
|
|
|
|
|
filterOption={(input, option) =>
|
|
|
|
|
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
|
|
|
|
|
}
|
|
|
|
|
options={products.map((p: Product) => ({
|
|
|
|
|
value: p.id,
|
|
|
|
|
label: `${p.productNumber || ''} ${p.name}`.trim(),
|
|
|
|
|
}))}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="description"
|
|
|
|
|
label="Beskrivelse"
|
|
|
|
|
rules={[{ required: true, message: 'Angiv beskrivelse' }]}
|
|
|
|
|
>
|
|
|
|
|
<Input
|
|
|
|
|
placeholder="Vare eller ydelse"
|
|
|
|
|
disabled={addLineMode === 'product' && !!selectedProductId}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
<Row gutter={16}>
|
|
|
|
|
<Col span={8}>
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="quantity"
|
|
|
|
|
label="Antal"
|
|
|
|
|
rules={[{ required: true, message: 'Angiv antal' }]}
|
|
|
|
|
>
|
Audit v3: VAT alignment, security, encoding, UX, compliance
VAT System Alignment (LEGAL - Critical):
- Align frontend VAT codes with backend (S25→U25, K25→I25, etc.)
- Add missing codes: UEU, IVV, IVY, REP
- Fix output VAT account 5710→5611 to match StandardDanishAccounts
- Invoice posting now checks fiscal year status before allowing send
- Disallow custom invoice number override (always use auto-numbering)
Security:
- Fix open redirect in AuthController (validate returnUrl is local)
- Store seller CVR/name/address on invoice events (Momsloven §52)
Backend Compliance:
- Add description validation at posting (Bogføringsloven §7)
- SAF-T: add DefaultCurrencyCode, TaxAccountingBasis to header
- SAF-T: add TaxTable to MasterFiles with all VAT codes
- SAF-T: always write balance elements even when zero
- Add financial income account 9100 Renteindtægter
Danish Encoding (~25 fixes):
- Kassekladde: Bogført, Bogføring, Vælg, være, på, Tilføj, Differens
- AttachmentUpload: træk, Understøtter, påkrævet, Bogføringsloven
- keyboardShortcuts: Bogfør, Bogføring display name
- ShortcutsHelpModal: åbne
- DataTable: Genindlæs
- documentProcessing: være
- CloseFiscalYearWizard: årsafslutning
Bugs Fixed:
- Non-null assertion crashes in Kunder.tsx and Produkter.tsx (company!.id)
- StatusBadge typo "Succces"→"Succes"
- HTML entity ø in Kassekladde→proper UTF-8
- AmountText showSign prop was dead code (true || showSign)
UX Improvements:
- Add PageHeader to Bankafstemning and Dashboard loading/empty states
- Responsive columns in Bankafstemning (xs/sm/lg breakpoints)
- Disable misleading buttons: Settings preferences, Kontooversigt edit,
Loenforstaelse export — with tooltips explaining status
- Add DemoDataDisclaimer to UserSettings
- Fix breadcrumb self-references on 3 pages
- Replace Dashboard fake progress bar with honest message
- Standardize date format DD-MM-YYYY in Bankafstemning and Ordrer
- Replace Input type="number" with InputNumber in Ordrer
Quality:
- Remove 8 redundant console.error statements
- Fix Kreditnotaer breadcrumb "Salg"→"Fakturering" for consistency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 01:15:45 +01:00
|
|
|
<InputNumber min={0} step={1} style={{ width: '100%' }} />
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
</Form.Item>
|
|
|
|
|
</Col>
|
|
|
|
|
<Col span={8}>
|
|
|
|
|
<Form.Item name="unit" label="Enhed">
|
|
|
|
|
<Input
|
|
|
|
|
placeholder="stk"
|
|
|
|
|
disabled={addLineMode === 'product' && !!selectedProductId}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Col>
|
|
|
|
|
<Col span={8}>
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="unitPrice"
|
|
|
|
|
label="Enhedspris"
|
|
|
|
|
rules={[{ required: true, message: 'Angiv pris' }]}
|
|
|
|
|
>
|
Audit v3: VAT alignment, security, encoding, UX, compliance
VAT System Alignment (LEGAL - Critical):
- Align frontend VAT codes with backend (S25→U25, K25→I25, etc.)
- Add missing codes: UEU, IVV, IVY, REP
- Fix output VAT account 5710→5611 to match StandardDanishAccounts
- Invoice posting now checks fiscal year status before allowing send
- Disallow custom invoice number override (always use auto-numbering)
Security:
- Fix open redirect in AuthController (validate returnUrl is local)
- Store seller CVR/name/address on invoice events (Momsloven §52)
Backend Compliance:
- Add description validation at posting (Bogføringsloven §7)
- SAF-T: add DefaultCurrencyCode, TaxAccountingBasis to header
- SAF-T: add TaxTable to MasterFiles with all VAT codes
- SAF-T: always write balance elements even when zero
- Add financial income account 9100 Renteindtægter
Danish Encoding (~25 fixes):
- Kassekladde: Bogført, Bogføring, Vælg, være, på, Tilføj, Differens
- AttachmentUpload: træk, Understøtter, påkrævet, Bogføringsloven
- keyboardShortcuts: Bogfør, Bogføring display name
- ShortcutsHelpModal: åbne
- DataTable: Genindlæs
- documentProcessing: være
- CloseFiscalYearWizard: årsafslutning
Bugs Fixed:
- Non-null assertion crashes in Kunder.tsx and Produkter.tsx (company!.id)
- StatusBadge typo "Succces"→"Succes"
- HTML entity ø in Kassekladde→proper UTF-8
- AmountText showSign prop was dead code (true || showSign)
UX Improvements:
- Add PageHeader to Bankafstemning and Dashboard loading/empty states
- Responsive columns in Bankafstemning (xs/sm/lg breakpoints)
- Disable misleading buttons: Settings preferences, Kontooversigt edit,
Loenforstaelse export — with tooltips explaining status
- Add DemoDataDisclaimer to UserSettings
- Fix breadcrumb self-references on 3 pages
- Replace Dashboard fake progress bar with honest message
- Standardize date format DD-MM-YYYY in Bankafstemning and Ordrer
- Replace Input type="number" with InputNumber in Ordrer
Quality:
- Remove 8 redundant console.error statements
- Fix Kreditnotaer breadcrumb "Salg"→"Fakturering" for consistency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 01:15:45 +01:00
|
|
|
<InputNumber
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
min={0}
|
|
|
|
|
step={0.01}
|
Audit v3: VAT alignment, security, encoding, UX, compliance
VAT System Alignment (LEGAL - Critical):
- Align frontend VAT codes with backend (S25→U25, K25→I25, etc.)
- Add missing codes: UEU, IVV, IVY, REP
- Fix output VAT account 5710→5611 to match StandardDanishAccounts
- Invoice posting now checks fiscal year status before allowing send
- Disallow custom invoice number override (always use auto-numbering)
Security:
- Fix open redirect in AuthController (validate returnUrl is local)
- Store seller CVR/name/address on invoice events (Momsloven §52)
Backend Compliance:
- Add description validation at posting (Bogføringsloven §7)
- SAF-T: add DefaultCurrencyCode, TaxAccountingBasis to header
- SAF-T: add TaxTable to MasterFiles with all VAT codes
- SAF-T: always write balance elements even when zero
- Add financial income account 9100 Renteindtægter
Danish Encoding (~25 fixes):
- Kassekladde: Bogført, Bogføring, Vælg, være, på, Tilføj, Differens
- AttachmentUpload: træk, Understøtter, påkrævet, Bogføringsloven
- keyboardShortcuts: Bogfør, Bogføring display name
- ShortcutsHelpModal: åbne
- DataTable: Genindlæs
- documentProcessing: være
- CloseFiscalYearWizard: årsafslutning
Bugs Fixed:
- Non-null assertion crashes in Kunder.tsx and Produkter.tsx (company!.id)
- StatusBadge typo "Succces"→"Succes"
- HTML entity ø in Kassekladde→proper UTF-8
- AmountText showSign prop was dead code (true || showSign)
UX Improvements:
- Add PageHeader to Bankafstemning and Dashboard loading/empty states
- Responsive columns in Bankafstemning (xs/sm/lg breakpoints)
- Disable misleading buttons: Settings preferences, Kontooversigt edit,
Loenforstaelse export — with tooltips explaining status
- Add DemoDataDisclaimer to UserSettings
- Fix breadcrumb self-references on 3 pages
- Replace Dashboard fake progress bar with honest message
- Standardize date format DD-MM-YYYY in Bankafstemning and Ordrer
- Replace Input type="number" with InputNumber in Ordrer
Quality:
- Remove 8 redundant console.error statements
- Fix Kreditnotaer breadcrumb "Salg"→"Fakturering" for consistency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 01:15:45 +01:00
|
|
|
style={{ width: '100%' }}
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
disabled={addLineMode === 'product' && !!selectedProductId}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Col>
|
|
|
|
|
</Row>
|
|
|
|
|
<Row gutter={16}>
|
|
|
|
|
<Col span={12}>
|
|
|
|
|
<Form.Item name="discountPercent" label="Rabat (%)">
|
Audit v3: VAT alignment, security, encoding, UX, compliance
VAT System Alignment (LEGAL - Critical):
- Align frontend VAT codes with backend (S25→U25, K25→I25, etc.)
- Add missing codes: UEU, IVV, IVY, REP
- Fix output VAT account 5710→5611 to match StandardDanishAccounts
- Invoice posting now checks fiscal year status before allowing send
- Disallow custom invoice number override (always use auto-numbering)
Security:
- Fix open redirect in AuthController (validate returnUrl is local)
- Store seller CVR/name/address on invoice events (Momsloven §52)
Backend Compliance:
- Add description validation at posting (Bogføringsloven §7)
- SAF-T: add DefaultCurrencyCode, TaxAccountingBasis to header
- SAF-T: add TaxTable to MasterFiles with all VAT codes
- SAF-T: always write balance elements even when zero
- Add financial income account 9100 Renteindtægter
Danish Encoding (~25 fixes):
- Kassekladde: Bogført, Bogføring, Vælg, være, på, Tilføj, Differens
- AttachmentUpload: træk, Understøtter, påkrævet, Bogføringsloven
- keyboardShortcuts: Bogfør, Bogføring display name
- ShortcutsHelpModal: åbne
- DataTable: Genindlæs
- documentProcessing: være
- CloseFiscalYearWizard: årsafslutning
Bugs Fixed:
- Non-null assertion crashes in Kunder.tsx and Produkter.tsx (company!.id)
- StatusBadge typo "Succces"→"Succes"
- HTML entity ø in Kassekladde→proper UTF-8
- AmountText showSign prop was dead code (true || showSign)
UX Improvements:
- Add PageHeader to Bankafstemning and Dashboard loading/empty states
- Responsive columns in Bankafstemning (xs/sm/lg breakpoints)
- Disable misleading buttons: Settings preferences, Kontooversigt edit,
Loenforstaelse export — with tooltips explaining status
- Add DemoDataDisclaimer to UserSettings
- Fix breadcrumb self-references on 3 pages
- Replace Dashboard fake progress bar with honest message
- Standardize date format DD-MM-YYYY in Bankafstemning and Ordrer
- Replace Input type="number" with InputNumber in Ordrer
Quality:
- Remove 8 redundant console.error statements
- Fix Kreditnotaer breadcrumb "Salg"→"Fakturering" for consistency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 01:15:45 +01:00
|
|
|
<InputNumber min={0} max={100} step={1} style={{ width: '100%' }} />
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
</Form.Item>
|
|
|
|
|
</Col>
|
|
|
|
|
<Col span={12}>
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="vatCode"
|
|
|
|
|
label="Momskode"
|
2026-02-05 21:35:26 +01:00
|
|
|
rules={[{ required: true, message: 'Vælg momskode' }]}
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
>
|
|
|
|
|
<Select
|
|
|
|
|
disabled={addLineMode === 'product' && !!selectedProductId}
|
|
|
|
|
options={[
|
Audit v4: VAT calc, SAF-T compliance, security hardening, frontend quality
Backend (17 files):
- VAT: REP 25% deductibility (§42), EU reverse charge double-entry (IEUV/IEUY/IVY),
IVY rate 0%→25%, VatReport Box C/D populated, Basis1 from real revenue
- SAF-T: correct OECD namespace, closing balance net calc, zero-amount fallback,
credit note auto-numbering (§52)
- Security: BankingController CSRF state token + company auth check,
attachment canonical path traversal check, discount 0-100% validation,
deactivated product/customer update guard
- Quality: redact bank API logs, remove dead code (VatCalcService,
PaymentMatchingService), CompanyAggregate IEmit interfaces, fix URL encoding
Frontend (15 files):
- Fix double "kr." in AmountText and Dashboard Statistic components
- Fix UserSettings Switch defaultChecked desync with Form state
- Remove dual useCompany/useCompanyStore pattern (Dashboard, Moms, Bank)
- Correct SKAT VAT deadline calculation per period type
- Add half-yearly/yearly VAT period options
- Guard console.error with import.meta.env.DEV
- Use shared formatDate in BankConnectionsTab
- Remove dead NONE vatCode check, purge 7 legacy VAT codes from type union
- Migrate S25→U25, K25→I25 across all pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 01:38:52 +01:00
|
|
|
{ value: 'U25', label: 'U25 - Salgsmoms 25%' },
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
{ value: 'S0', label: 'S0 - Momsfrit salg' },
|
|
|
|
|
]}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Col>
|
|
|
|
|
</Row>
|
|
|
|
|
</Form>
|
|
|
|
|
</Modal>
|
|
|
|
|
|
|
|
|
|
{/* Convert to Invoice Modal */}
|
|
|
|
|
<Modal
|
|
|
|
|
title="Opret faktura fra ordre"
|
|
|
|
|
open={isConvertModalOpen}
|
|
|
|
|
onCancel={() => {
|
|
|
|
|
setIsConvertModalOpen(false);
|
|
|
|
|
setSelectedLinesToInvoice([]);
|
|
|
|
|
}}
|
|
|
|
|
onOk={handleSubmitConvert}
|
|
|
|
|
okText="Opret faktura"
|
|
|
|
|
cancelText="Annuller"
|
|
|
|
|
confirmLoading={convertToInvoiceMutation.isPending}
|
|
|
|
|
width={600}
|
|
|
|
|
>
|
|
|
|
|
<Alert
|
2026-02-05 21:35:26 +01:00
|
|
|
message="Vælg linjer til fakturering"
|
|
|
|
|
description="Vælg hvilke ordrelinjer der skal inkluderes i fakturaen. Du kan fakturere delvist og oprette flere fakturaer senere."
|
Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores
Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00
|
|
|
type="info"
|
|
|
|
|
showIcon
|
|
|
|
|
style={{ marginBottom: spacing.lg }}
|
|
|
|
|
/>
|
|
|
|
|
{selectedOrder && (
|
|
|
|
|
<List
|
|
|
|
|
size="small"
|
|
|
|
|
bordered
|
|
|
|
|
dataSource={selectedOrder.lines.filter((line) => !line.isInvoiced)}
|
|
|
|
|
renderItem={(line: OrderLine) => (
|
|
|
|
|
<List.Item>
|
|
|
|
|
<Checkbox
|
|
|
|
|
checked={selectedLinesToInvoice.includes(line.lineNumber)}
|
|
|
|
|
onChange={(e) => {
|
|
|
|
|
if (e.target.checked) {
|
|
|
|
|
setSelectedLinesToInvoice([...selectedLinesToInvoice, line.lineNumber]);
|
|
|
|
|
} else {
|
|
|
|
|
setSelectedLinesToInvoice(
|
|
|
|
|
selectedLinesToInvoice.filter((n) => n !== line.lineNumber)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Space direction="vertical" size={0}>
|
|
|
|
|
<Text>{line.description}</Text>
|
|
|
|
|
<Text type="secondary">
|
|
|
|
|
{line.quantity} {line.unit || 'stk'} x{' '}
|
|
|
|
|
{formatCurrency(line.unitPrice)} ={' '}
|
|
|
|
|
{formatCurrency(line.amountTotal)}
|
|
|
|
|
</Text>
|
|
|
|
|
</Space>
|
|
|
|
|
</Checkbox>
|
|
|
|
|
</List.Item>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</Modal>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|