feat: allow replacing completed SIE imports (#227)
* feat: allow replacing completed SIE imports Users who import a SIE file, make adjustments in the source system, and re-export can now replace the old import instead of being permanently blocked by the "overlapping fiscal year" guard. The old import's entries are cancelled (posted → cancelled) and the import is marked as 'replaced'. Nothing is deleted — full audit trail preserved per BFL 5 kap 5§ (rättelse) and BFNAR 2013:2 kap 8. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address Greptile review — atomic RPC, locked_at check - P1: Wrap entry cancellation + import status update in a single DB RPC (replace_sie_import) to prevent inconsistent state on partial failure - P2: Check locked_at in addition to is_closed for fiscal period guard - P2: Use RPC return value for accurate cancelled entry count Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
973a2b81a0
commit
258a64a849
@@ -3,7 +3,8 @@
|
||||
import { useState, useCallback, useEffect } from 'react'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Progress } from '@/components/ui/progress'
|
||||
import { Upload, FileText, AlertCircle, CheckCircle, Loader2, XCircle } from 'lucide-react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Upload, FileText, AlertCircle, CheckCircle, Loader2, XCircle, RefreshCw } from 'lucide-react'
|
||||
|
||||
const LOADING_PHASES = [
|
||||
{ message: 'Läser fil...', progress: 10 },
|
||||
@@ -19,9 +20,12 @@ interface SIEUploadStepProps {
|
||||
errorType?: 'duplicate' | 'duplicate_period' | 'validation' | 'parse'
|
||||
validationErrors?: string[]
|
||||
validationWarnings?: string[]
|
||||
duplicatePeriodImportId?: string | null
|
||||
onReplace?: (importId: string) => Promise<void>
|
||||
isReplacing?: boolean
|
||||
}
|
||||
|
||||
export default function SIEUploadStep({ onFileSelect, isLoading, error, errorType, validationErrors, validationWarnings }: SIEUploadStepProps) {
|
||||
export default function SIEUploadStep({ onFileSelect, isLoading, error, errorType, validationErrors, validationWarnings, duplicatePeriodImportId, onReplace, isReplacing }: SIEUploadStepProps) {
|
||||
const [isDragging, setIsDragging] = useState(false)
|
||||
const [selectedFile, setSelectedFile] = useState<File | null>(null)
|
||||
const [loadingPhase, setLoadingPhase] = useState(0)
|
||||
@@ -192,7 +196,27 @@ export default function SIEUploadStep({ onFileSelect, isLoading, error, errorTyp
|
||||
<p>Om du vill importera om filen, ta först bort den tidigare importen under Bokföring.</p>
|
||||
)}
|
||||
{errorType === 'duplicate_period' && (
|
||||
<p>Varje räkenskapsår kan bara importeras en gång. Ta bort den befintliga importen först om du vill ersätta den.</p>
|
||||
<div className="space-y-2">
|
||||
<p>Den befintliga importens verifikationer kommer att makuleras (status ändras till "makulerad"). De finns kvar som spårbar historik.</p>
|
||||
{duplicatePeriodImportId && onReplace && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="border-warning/50 text-warning hover:bg-warning/10"
|
||||
disabled={isReplacing}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
onReplace(duplicatePeriodImportId)
|
||||
}}
|
||||
>
|
||||
{isReplacing ? (
|
||||
<><Loader2 className="h-4 w-4 mr-2 animate-spin" />Ersätter...</>
|
||||
) : (
|
||||
<><RefreshCw className="h-4 w-4 mr-2" />Ersätt befintlig import</>
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{errorType === 'validation' && (
|
||||
<p>Prova att exportera filen igen från ditt bokföringsprogram. Om felet kvarstår, kontrollera att alla verifikationer är korrekt bokförda i källsystemet.</p>
|
||||
|
||||
Reference in New Issue
Block a user