feat: add Patentprozesskostenrechner fee calculation engine + API
Pure Go implementation of patent litigation cost calculator with: - Step-based GKG/RVG fee accumulator across 4 historical schedules (2005/2013/2021/2025 + Aktuell alias) - Instance multiplier tables for 8 court types (LG, OLG, BGH NZB/Rev, BPatG, BGH Null, DPMA, BPatG Canc) - Full attorney fee calculation (VG, TG, Erhöhungsgebühr Nr. 1008 VV RVG, Auslagenpauschale) - Prozesskostensicherheit computation - UPC fee data (pre-2026 and 2026 schedules with value-based brackets, recoverable costs ceilings) - Public API: POST /api/fees/calculate, GET /api/fees/schedules (no auth required) - 22 unit tests covering all calculation paths Fixes 3 Excel bugs: - Bug 1: Prozesskostensicherheit VAT formula (subtract → add) - Bug 2: Security for costs uses GKG base for court fee, not RVG - Bug 3: Expert fees included in BPatG instance total
This commit is contained in:
249
backend/internal/services/fee_data.go
Normal file
249
backend/internal/services/fee_data.go
Normal file
@@ -0,0 +1,249 @@
|
||||
package services
|
||||
|
||||
import "math"
|
||||
|
||||
// feeBracket defines one bracket in the GKG/RVG fee schedule.
|
||||
// Each bracket covers a range of Streitwert values.
|
||||
type feeBracket struct {
|
||||
UpperBound float64 // upper bound of this bracket
|
||||
StepSize float64 // step size within this bracket
|
||||
GKGIncrement float64 // GKG fee increment per step
|
||||
RVGIncrement float64 // RVG fee increment per step
|
||||
}
|
||||
|
||||
// feeScheduleData holds the bracket data for a fee schedule version.
|
||||
type feeScheduleData struct {
|
||||
Label string
|
||||
ValidFrom string
|
||||
Brackets []feeBracket
|
||||
AliasOf string // if non-empty, this schedule is an alias for another
|
||||
}
|
||||
|
||||
// feeSchedules contains all historical GKG/RVG fee schedule versions.
|
||||
// Data extracted from Patentprozesskostenrechner.xlsm ListObjects.
|
||||
var feeSchedules = map[string]*feeScheduleData{
|
||||
"2005": {
|
||||
Label: "GKG/RVG 2006-09-01",
|
||||
ValidFrom: "2006-09-01",
|
||||
Brackets: []feeBracket{
|
||||
{300, 300, 25, 25},
|
||||
{1500, 300, 10, 20},
|
||||
{5000, 500, 8, 28},
|
||||
{10000, 1000, 15, 37},
|
||||
{25000, 3000, 23, 40},
|
||||
{50000, 5000, 29, 72},
|
||||
{200000, 15000, 100, 77},
|
||||
{500000, 30000, 150, 118},
|
||||
{math.MaxFloat64, 50000, 150, 150},
|
||||
},
|
||||
},
|
||||
"2013": {
|
||||
Label: "GKG/RVG 2013-08-01",
|
||||
ValidFrom: "2013-08-01",
|
||||
Brackets: []feeBracket{
|
||||
{500, 300, 35, 45},
|
||||
{2000, 500, 18, 35},
|
||||
{10000, 1000, 19, 51},
|
||||
{25000, 3000, 26, 46},
|
||||
{50000, 5000, 35, 75},
|
||||
{200000, 15000, 120, 85},
|
||||
{500000, 30000, 179, 120},
|
||||
{math.MaxFloat64, 50000, 180, 150},
|
||||
},
|
||||
},
|
||||
"2021": {
|
||||
Label: "GKG/RVG 2021-01-01",
|
||||
ValidFrom: "2021-01-01",
|
||||
Brackets: []feeBracket{
|
||||
{500, 300, 38, 49},
|
||||
{2000, 500, 20, 39},
|
||||
{10000, 1000, 21, 56},
|
||||
{25000, 3000, 29, 52},
|
||||
{50000, 5000, 38, 81},
|
||||
{200000, 15000, 132, 94},
|
||||
{500000, 30000, 198, 132},
|
||||
{math.MaxFloat64, 50000, 198, 165},
|
||||
},
|
||||
},
|
||||
"2025": {
|
||||
Label: "GKG/RVG 2025-06-01",
|
||||
ValidFrom: "2025-06-01",
|
||||
Brackets: []feeBracket{
|
||||
{500, 300, 40, 51.5},
|
||||
{2000, 500, 21, 41.5},
|
||||
{10000, 1000, 22.5, 59.5},
|
||||
{25000, 3000, 30.5, 55},
|
||||
{50000, 5000, 40.5, 86},
|
||||
{200000, 15000, 140, 99.5},
|
||||
{500000, 30000, 210, 140},
|
||||
{math.MaxFloat64, 50000, 210, 175},
|
||||
},
|
||||
},
|
||||
"Aktuell": {
|
||||
Label: "Aktuell (= 2025-06-01)",
|
||||
ValidFrom: "2025-06-01",
|
||||
AliasOf: "2025",
|
||||
},
|
||||
}
|
||||
|
||||
// instanceConfig holds the multipliers and fee basis for each court instance.
|
||||
type instanceConfig struct {
|
||||
Label string
|
||||
CourtFactor float64 // multiplier for base court fee
|
||||
CourtSource string // "GKG", "PatKostG", or "fixed"
|
||||
FixedCourtFee float64 // only used when CourtSource is "fixed"
|
||||
RAVGFactor float64 // Rechtsanwalt Verfahrensgebühr factor
|
||||
RATGFactor float64 // Rechtsanwalt Terminsgebühr factor
|
||||
PAVGFactor float64 // Patentanwalt Verfahrensgebühr factor
|
||||
PATGFactor float64 // Patentanwalt Terminsgebühr factor
|
||||
HasPA bool // whether patent attorneys are applicable
|
||||
}
|
||||
|
||||
// instanceConfigs defines the fee parameters for each court instance type.
|
||||
var instanceConfigs = map[string]instanceConfig{
|
||||
"LG": {"LG (Verletzung 1. Instanz)", 3.0, "GKG", 0, 1.3, 1.2, 1.3, 1.2, true},
|
||||
"OLG": {"OLG (Berufung)", 4.0, "GKG", 0, 1.6, 1.2, 1.6, 1.2, true},
|
||||
"BGH_NZB": {"BGH (Nichtzulassungsbeschwerde)", 2.0, "GKG", 0, 2.3, 1.2, 1.6, 1.2, true},
|
||||
"BGH_Rev": {"BGH (Revision)", 5.0, "GKG", 0, 2.3, 1.5, 1.6, 1.5, true},
|
||||
"BPatG": {"BPatG (Nichtigkeitsverfahren)", 4.5, "PatKostG", 0, 1.3, 1.2, 1.3, 1.2, true},
|
||||
"BGH_Null": {"BGH (Nichtigkeitsberufung)", 6.0, "GKG", 0, 1.6, 1.5, 1.6, 1.5, true},
|
||||
"DPMA": {"DPMA (Löschungsverfahren)", 0, "fixed", 300, 1.3, 1.2, 0, 0, false},
|
||||
"BPatG_Canc": {"BPatG (Löschungsbeschwerde)", 0, "fixed", 500, 1.3, 1.2, 0, 0, false},
|
||||
}
|
||||
|
||||
// --- UPC Fee Data ---
|
||||
|
||||
// upcFeeBracket defines one bracket in a UPC fee table.
|
||||
// MaxValue 0 means unlimited (last bracket).
|
||||
type upcFeeBracket struct {
|
||||
MaxValue float64
|
||||
Fee float64
|
||||
}
|
||||
|
||||
type upcFixedFees struct {
|
||||
Infringement float64
|
||||
CounterclaimInfringement float64
|
||||
NonInfringement float64
|
||||
LicenseCompensation float64
|
||||
DetermineDamages float64
|
||||
RevocationStandalone float64
|
||||
CounterclaimRevocation float64
|
||||
ProvisionalMeasures float64
|
||||
}
|
||||
|
||||
type upcScheduleData struct {
|
||||
Label string
|
||||
ValidFrom string
|
||||
FixedFees upcFixedFees
|
||||
ValueBased []upcFeeBracket
|
||||
Recoverable []upcFeeBracket
|
||||
SMReduction float64
|
||||
}
|
||||
|
||||
// upcSchedules contains UPC fee data for pre-2026 and 2026+ schedules.
|
||||
var upcSchedules = map[string]*upcScheduleData{
|
||||
"pre2026": {
|
||||
Label: "UPC (vor 2026)",
|
||||
ValidFrom: "2023-06-01",
|
||||
FixedFees: upcFixedFees{
|
||||
Infringement: 11000,
|
||||
CounterclaimInfringement: 11000,
|
||||
NonInfringement: 11000,
|
||||
LicenseCompensation: 11000,
|
||||
DetermineDamages: 3000,
|
||||
RevocationStandalone: 20000,
|
||||
CounterclaimRevocation: 20000,
|
||||
ProvisionalMeasures: 11000,
|
||||
},
|
||||
ValueBased: []upcFeeBracket{
|
||||
{500000, 0},
|
||||
{750000, 2500},
|
||||
{1000000, 4000},
|
||||
{1500000, 8000},
|
||||
{2000000, 13000},
|
||||
{3000000, 20000},
|
||||
{4000000, 26000},
|
||||
{5000000, 32000},
|
||||
{6000000, 39000},
|
||||
{7000000, 46000},
|
||||
{8000000, 52000},
|
||||
{9000000, 58000},
|
||||
{10000000, 65000},
|
||||
{15000000, 75000},
|
||||
{20000000, 100000},
|
||||
{25000000, 125000},
|
||||
{30000000, 150000},
|
||||
{50000000, 250000},
|
||||
{0, 325000},
|
||||
},
|
||||
Recoverable: []upcFeeBracket{
|
||||
{250000, 38000},
|
||||
{500000, 56000},
|
||||
{1000000, 112000},
|
||||
{2000000, 200000},
|
||||
{4000000, 400000},
|
||||
{8000000, 600000},
|
||||
{16000000, 800000},
|
||||
{30000000, 1200000},
|
||||
{50000000, 1500000},
|
||||
{0, 2000000},
|
||||
},
|
||||
SMReduction: 0.40,
|
||||
},
|
||||
"2026": {
|
||||
Label: "UPC (ab 2026)",
|
||||
ValidFrom: "2026-01-01",
|
||||
FixedFees: upcFixedFees{
|
||||
Infringement: 14600,
|
||||
CounterclaimInfringement: 14600,
|
||||
NonInfringement: 14600,
|
||||
LicenseCompensation: 14600,
|
||||
DetermineDamages: 4000,
|
||||
RevocationStandalone: 26500,
|
||||
CounterclaimRevocation: 26500,
|
||||
ProvisionalMeasures: 14600,
|
||||
},
|
||||
// Estimated ~32% increase on pre-2026 values; replace with official data when available.
|
||||
ValueBased: []upcFeeBracket{
|
||||
{500000, 0},
|
||||
{750000, 3300},
|
||||
{1000000, 5300},
|
||||
{1500000, 10600},
|
||||
{2000000, 17200},
|
||||
{3000000, 26400},
|
||||
{4000000, 34300},
|
||||
{5000000, 42200},
|
||||
{6000000, 51500},
|
||||
{7000000, 60700},
|
||||
{8000000, 68600},
|
||||
{9000000, 76600},
|
||||
{10000000, 85800},
|
||||
{15000000, 99000},
|
||||
{20000000, 132000},
|
||||
{25000000, 165000},
|
||||
{30000000, 198000},
|
||||
{50000000, 330000},
|
||||
{0, 429000},
|
||||
},
|
||||
Recoverable: []upcFeeBracket{
|
||||
{250000, 38000},
|
||||
{500000, 56000},
|
||||
{1000000, 112000},
|
||||
{2000000, 200000},
|
||||
{4000000, 400000},
|
||||
{8000000, 600000},
|
||||
{16000000, 800000},
|
||||
{30000000, 1200000},
|
||||
{50000000, 1500000},
|
||||
{0, 2000000},
|
||||
},
|
||||
SMReduction: 0.50,
|
||||
},
|
||||
}
|
||||
|
||||
// Fee calculation constants (RVG)
|
||||
const (
|
||||
erhoehungsfaktor = 0.3 // Nr. 1008 VV RVG increase per additional client
|
||||
erhoehungsfaktorMax = 2.0 // maximum increase factor
|
||||
auslagenpauschale = 20.0 // Nr. 7002 VV RVG flat expense allowance (EUR)
|
||||
)
|
||||
Reference in New Issue
Block a user