Refactor to generic ERP base
Remove influencer-specific features (campaigns, TikTok, gifts, shadow ledger, contracts, briefings) and consolidate into a clean ERP foundation with core bookkeeping, invoicing, receipts, tax reporting, and calendar functionality. Reorganize database migrations into a clean numbered sequence. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
a25d10a528
commit
0aecf5b41c
@@ -3,12 +3,9 @@ import type {
|
||||
NEDeclaration,
|
||||
NEDeclarationRutor,
|
||||
NEAccountMapping,
|
||||
NEGiftBreakdown,
|
||||
NEGiftItem,
|
||||
FiscalPeriod,
|
||||
JournalEntry,
|
||||
JournalEntryLine,
|
||||
Gift,
|
||||
} from '@/types'
|
||||
|
||||
/**
|
||||
@@ -295,67 +292,6 @@ export async function generateNEDeclaration(
|
||||
rutor.R11 = totalRevenue - totalExpenses
|
||||
breakdown.R11.total = rutor.R11
|
||||
|
||||
// Fetch gifts for the period
|
||||
const { data: gifts } = await supabase
|
||||
.from('gifts')
|
||||
.select('*')
|
||||
.eq('user_id', userId)
|
||||
.gte('date', period.period_start)
|
||||
.lte('date', period.period_end)
|
||||
|
||||
// Build gift breakdown
|
||||
let giftBreakdown: NEGiftBreakdown | undefined
|
||||
if (gifts && gifts.length > 0) {
|
||||
const giftItems: NEGiftItem[] = []
|
||||
let r1Total = 0
|
||||
let r2Total = 0
|
||||
let r6Total = 0
|
||||
|
||||
for (const gift of gifts as Gift[]) {
|
||||
const classification = gift.classification
|
||||
if (!classification || !classification.taxable) continue
|
||||
|
||||
const item: NEGiftItem = {
|
||||
id: gift.id,
|
||||
date: gift.date,
|
||||
brandName: gift.brand_name,
|
||||
description: gift.description,
|
||||
marketValue: gift.estimated_value,
|
||||
vatLiable: classification.vatLiable,
|
||||
vatAmount: classification.vatAmount,
|
||||
deductibleAsExpense: classification.deductibleAsExpense,
|
||||
neIncomeRuta: classification.neIncomeRuta,
|
||||
neExpenseRuta: classification.neExpenseRuta,
|
||||
}
|
||||
giftItems.push(item)
|
||||
|
||||
// Accumulate totals based on NE ruta
|
||||
if (classification.neIncomeRuta === 'R1') {
|
||||
r1Total += classification.valueExclVat // Exkl moms för R1
|
||||
} else if (classification.neIncomeRuta === 'R2') {
|
||||
r2Total += gift.estimated_value
|
||||
}
|
||||
|
||||
if (classification.neExpenseRuta === 'R6') {
|
||||
r6Total += gift.estimated_value
|
||||
}
|
||||
}
|
||||
|
||||
if (giftItems.length > 0) {
|
||||
giftBreakdown = {
|
||||
gifts: giftItems,
|
||||
summary: {
|
||||
r1Total: roundToKrona(r1Total),
|
||||
r2Total: roundToKrona(r2Total),
|
||||
r6Total: roundToKrona(r6Total),
|
||||
totalTaxable: roundToKrona(r1Total + r2Total),
|
||||
totalDeductible: roundToKrona(r6Total),
|
||||
netTaxableIncome: roundToKrona(r1Total + r2Total - r6Total),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add warnings
|
||||
if (!(period as FiscalPeriod).is_closed) {
|
||||
warnings.push('Räkenskapsåret är inte stängt. Siffrorna kan ändras.')
|
||||
@@ -365,19 +301,6 @@ export async function generateNEDeclaration(
|
||||
warnings.push('Inga bokförda intäkter eller kostnader hittades för perioden.')
|
||||
}
|
||||
|
||||
// Check for gifts without journal entries
|
||||
if (giftBreakdown && giftBreakdown.gifts.length > 0) {
|
||||
const giftsWithoutEntries = (gifts as Gift[]).filter(
|
||||
(g) => g.classification?.taxable && !g.journal_entry_id
|
||||
)
|
||||
if (giftsWithoutEntries.length > 0) {
|
||||
warnings.push(
|
||||
`${giftsWithoutEntries.length} skattepliktiga gåvor saknar bokföringsverifikation. ` +
|
||||
'Dessa bör bokföras för att inkluderas i NE-bilagan.'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
fiscalYear: {
|
||||
id: period.id,
|
||||
@@ -388,7 +311,6 @@ export async function generateNEDeclaration(
|
||||
},
|
||||
rutor,
|
||||
breakdown,
|
||||
giftBreakdown,
|
||||
companyInfo: {
|
||||
companyName: settings?.company_name || 'Okänt företag',
|
||||
orgNumber: settings?.org_number || null,
|
||||
|
||||
@@ -52,7 +52,7 @@ export async function generateSIEExport(
|
||||
lines.push('#FLAGGA 0')
|
||||
lines.push('#FORMAT PC8')
|
||||
lines.push('#SIETYP 4')
|
||||
lines.push(`#PROGRAM "${options.program_name || 'InfluencerBiz'}" "1.0"`)
|
||||
lines.push(`#PROGRAM "${options.program_name || 'ERPBase'}" "1.0"`)
|
||||
lines.push(`#GEN ${formatSIEDate(now)}`)
|
||||
|
||||
if (options.org_number) {
|
||||
|
||||
@@ -54,7 +54,7 @@ export function generateSRUFile(declaration: NEDeclaration): SRUFile {
|
||||
// File header
|
||||
records.push({ fieldCode: 'PRODUKT', value: 'KONTROLLUPPGIFTER' })
|
||||
records.push({ fieldCode: 'SESSION', value: '1' })
|
||||
records.push({ fieldCode: 'PROGRAMNAMN', value: 'InfluencerBiz' })
|
||||
records.push({ fieldCode: 'PROGRAMNAMN', value: 'ERPBase' })
|
||||
records.push({ fieldCode: 'PROGRAMVERSION', value: '1.0' })
|
||||
records.push({
|
||||
fieldCode: 'SKAPAT',
|
||||
|
||||
@@ -328,8 +328,6 @@ function getVatRateForCategory(category: string | null): number {
|
||||
'uncategorized',
|
||||
'income_services',
|
||||
'income_products',
|
||||
'income_sponsorship',
|
||||
'income_affiliate',
|
||||
'income_other',
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user