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
250 lines
6.9 KiB
Go
250 lines
6.9 KiB
Go
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)
|
|
)
|