jeffrey1963 commited on
Commit
e4bca1c
·
verified ·
1 Parent(s): 725ecc4

Create equipment_catalog.py

Browse files
Files changed (1) hide show
  1. equipment_catalog.py +145 -0
equipment_catalog.py ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass, asdict
2
+ from typing import Dict, Any, Optional, List
3
+ import json, os
4
+ from datetime import date
5
+
6
+ CATALOG_PATH = "equipment_catalog.json"
7
+ ASSETS_PATH = "purchased_assets.json"
8
+
9
+ @dataclass
10
+ class EquipmentSpec:
11
+ # Identity
12
+ id: str
13
+ name: str
14
+ category: str # "tractor", "planter", etc.
15
+ brand: str
16
+ model: str
17
+
18
+ # Economics
19
+ list_price: float
20
+ expected_life_years: int
21
+ salvage_value_pct: float # straight-line baseline (% of cost)
22
+
23
+ # Ops (extend as needed)
24
+ rated_hp: Optional[int] = None
25
+ transport_speed_mph: Optional[float] = None
26
+
27
+ # Depreciation (ASAE defaults for tractors; can refine later)
28
+ dep_method_default: str = "ASAE"
29
+ asae_dep1: Optional[float] = 0.67
30
+ asae_dep2: Optional[float] = 0.94
31
+
32
+ # K-State / ASAE repair model (tractor-ish defaults; refine per class)
33
+ repair_rf1: Optional[float] = 0.007
34
+ repair_rf2: Optional[float] = 2.0
35
+ eul_hours: Optional[int] = 12000
36
+
37
+ fuel_type: Optional[str] = "diesel"
38
+ notes: Optional[str] = None
39
+
40
+
41
+ def default_catalog() -> List[EquipmentSpec]:
42
+ return [
43
+ EquipmentSpec(
44
+ id="jd-6155m",
45
+ name="John Deere 6155M",
46
+ category="tractor",
47
+ brand="John Deere",
48
+ model="6155M",
49
+ list_price=185000.0,
50
+ expected_life_years=12,
51
+ salvage_value_pct=0.18,
52
+ rated_hp=155,
53
+ transport_speed_mph=24.0,
54
+ notes="Mid-range row-crop tractor.",
55
+ ),
56
+ EquipmentSpec(
57
+ id="caseih-maxxum-125",
58
+ name="Case IH Maxxum 125",
59
+ category="tractor",
60
+ brand="Case IH",
61
+ model="Maxxum 125",
62
+ list_price=165000.0,
63
+ expected_life_years=12,
64
+ salvage_value_pct=0.17,
65
+ rated_hp=125,
66
+ transport_speed_mph=25.0,
67
+ ),
68
+ EquipmentSpec(
69
+ id="kubota-m7-151",
70
+ name="Kubota M7-151",
71
+ category="tractor",
72
+ brand="Kubota",
73
+ model="M7-151",
74
+ list_price=150000.0,
75
+ expected_life_years=12,
76
+ salvage_value_pct=0.16,
77
+ rated_hp=150,
78
+ transport_speed_mph=24.0,
79
+ ),
80
+ EquipmentSpec(
81
+ id="nh-t7-190",
82
+ name="New Holland T7.190",
83
+ category="tractor",
84
+ brand="New Holland",
85
+ model="T7.190",
86
+ list_price=178000.0,
87
+ expected_life_years=12,
88
+ salvage_value_pct=0.17,
89
+ rated_hp=165,
90
+ transport_speed_mph=31.0,
91
+ ),
92
+ ]
93
+
94
+
95
+ def _atomic_write_json(path: str, data: Any):
96
+ tmp = path + ".tmp"
97
+ with open(tmp, "w") as f:
98
+ json.dump(data, f, indent=2, default=str)
99
+ os.replace(tmp, path)
100
+
101
+ def ensure_catalog_file():
102
+ if not os.path.exists(CATALOG_PATH):
103
+ items = [asdict(x) for x in default_catalog()]
104
+ _atomic_write_json(CATALOG_PATH, items)
105
+
106
+ def load_catalog() -> Dict[str, EquipmentSpec]:
107
+ ensure_catalog_file()
108
+ with open(CATALOG_PATH, "r") as f:
109
+ raw = json.load(f)
110
+ cat: Dict[str, EquipmentSpec] = {}
111
+ for item in raw:
112
+ cat[item["id"]] = EquipmentSpec(**item)
113
+ return cat
114
+
115
+ def load_assets() -> list:
116
+ if not os.path.exists(ASSETS_PATH):
117
+ _atomic_write_json(ASSETS_PATH, [])
118
+ return []
119
+ with open(ASSETS_PATH, "r") as f:
120
+ return json.load(f)
121
+
122
+ def add_asset_from_catalog(spec: EquipmentSpec, purchase_price: Optional[float] = None) -> Dict[str, Any]:
123
+ assets = load_assets()
124
+ entry = {
125
+ "asset_id": f"{spec.id}-{len(assets)+1}",
126
+ "catalog_id": spec.id,
127
+ "name": spec.name,
128
+ "category": spec.category,
129
+ "brand": spec.brand,
130
+ "model": spec.model,
131
+ "purchase_date": str(date.today()),
132
+ "cost": float(purchase_price) if purchase_price is not None else float(spec.list_price),
133
+ "expected_life_years": spec.expected_life_years,
134
+ "salvage_value_pct": spec.salvage_value_pct,
135
+ "dep_method": spec.dep_method_default,
136
+ "asae_dep1": spec.asae_dep1,
137
+ "asae_dep2": spec.asae_dep2,
138
+ "repair": {"rf1": spec.repair_rf1, "rf2": spec.repair_rf2, "eul_hours": spec.eul_hours},
139
+ "ops": {"rated_hp": spec.rated_hp, "transport_speed_mph": spec.transport_speed_mph, "fuel": spec.fuel_type},
140
+ "notes": spec.notes,
141
+ "hours_used": 0,
142
+ }
143
+ assets.append(entry)
144
+ _atomic_write_json(ASSETS_PATH, assets)
145
+ return entry