migrate to table based tinydb
NOTE to migrate database install tinydb & run migrate.py - added new functions to filter data with db queries - in the storage module
This commit is contained in:
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1 +1,7 @@
|
|||||||
__pycache__
|
.vscode
|
||||||
|
__pycache__
|
||||||
|
venv
|
||||||
|
.venv
|
||||||
|
webapp/data/orders.json
|
||||||
|
orders.json
|
||||||
|
orders*.json
|
||||||
532
data/orders.json
532
data/orders.json
@@ -1,532 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"id": "b94528cb-ccf5-41d3-af05-dbd4a75b758e",
|
|
||||||
"structure": "Athanor",
|
|
||||||
"quantity": 1,
|
|
||||||
"me": 0,
|
|
||||||
"status": "done",
|
|
||||||
"created_at": "2025-08-21T16:02:00.451895+00:00",
|
|
||||||
"done_at": "2025-08-21T16:02:20.363756+00:00",
|
|
||||||
"system": "Jita",
|
|
||||||
"industry_structure": "Station",
|
|
||||||
"industry_rig": "None",
|
|
||||||
"reaction_structure": "Athanor",
|
|
||||||
"reaction_rig": "None"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "e0c631c3-0a64-44ac-a64a-cc0647b2a2b9",
|
|
||||||
"structure": "Raitaru",
|
|
||||||
"quantity": 6,
|
|
||||||
"me": 4,
|
|
||||||
"status": "done",
|
|
||||||
"created_at": "2025-08-21T16:02:17.240266+00:00",
|
|
||||||
"done_at": "2025-08-21T16:02:21.570702+00:00",
|
|
||||||
"system": "Jita",
|
|
||||||
"industry_structure": "Station",
|
|
||||||
"industry_rig": "None",
|
|
||||||
"reaction_structure": "Athanor",
|
|
||||||
"reaction_rig": "None"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "0bdf2545-b129-4856-bcd8-23837c4a04bf",
|
|
||||||
"structure": "Athanor",
|
|
||||||
"quantity": 5,
|
|
||||||
"me": 10,
|
|
||||||
"notes": "Test Auftrag",
|
|
||||||
"status": "done",
|
|
||||||
"created_at": "2025-08-21T16:13:36.220731+00:00",
|
|
||||||
"done_at": "2025-08-21T16:13:42.494046+00:00",
|
|
||||||
"system": "Jita",
|
|
||||||
"industry_structure": "Station",
|
|
||||||
"industry_rig": "None",
|
|
||||||
"reaction_structure": "Athanor",
|
|
||||||
"reaction_rig": "None"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "09bed2df-89a0-475a-a0bb-3e942f594e11",
|
|
||||||
"structure": "Raitaru",
|
|
||||||
"quantity": 2,
|
|
||||||
"me": 3,
|
|
||||||
"notes": "",
|
|
||||||
"status": "done",
|
|
||||||
"created_at": "2025-08-21T16:22:08.029669+00:00",
|
|
||||||
"done_at": "2025-08-21T17:27:58.230171+00:00",
|
|
||||||
"system": "Jita",
|
|
||||||
"industry_structure": "Station",
|
|
||||||
"industry_rig": "None",
|
|
||||||
"reaction_structure": "Athanor",
|
|
||||||
"reaction_rig": "None"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "32aea266-0f57-4101-b17e-051cca285381",
|
|
||||||
"structure": "Astrahus",
|
|
||||||
"quantity": 6,
|
|
||||||
"me": 0,
|
|
||||||
"notes": "",
|
|
||||||
"status": "done",
|
|
||||||
"created_at": "2025-08-21T17:28:04.199917+00:00",
|
|
||||||
"done_at": "2025-08-21T19:56:26.687066+00:00",
|
|
||||||
"system": "Jita",
|
|
||||||
"industry_structure": "Station",
|
|
||||||
"industry_rig": "None",
|
|
||||||
"reaction_structure": "Athanor",
|
|
||||||
"reaction_rig": "None"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "38c32e75-ca24-463f-924c-665731736541",
|
|
||||||
"structure": "Athanor",
|
|
||||||
"quantity": 2,
|
|
||||||
"me": 6,
|
|
||||||
"notes": "Test",
|
|
||||||
"system": "Jita",
|
|
||||||
"industry_structure": "Sotiyo",
|
|
||||||
"industry_rig": "T1",
|
|
||||||
"reaction_structure": "Tatara",
|
|
||||||
"reaction_rig": "T1",
|
|
||||||
"status": "done",
|
|
||||||
"created_at": "2025-08-21T19:56:21.284564+00:00",
|
|
||||||
"done_at": "2025-08-22T07:54:33+0100",
|
|
||||||
"cookbook": {
|
|
||||||
"error": 0,
|
|
||||||
"status": 200,
|
|
||||||
"message": {
|
|
||||||
"materialCost": 1469368496.29,
|
|
||||||
"jobCost": 450873981.87,
|
|
||||||
"additionalCost": 0,
|
|
||||||
"totalCost": 1920242478.16,
|
|
||||||
"producedQuantity": 2,
|
|
||||||
"buildCostPerUnit": 960121239.08,
|
|
||||||
"excessMaterialsValue": 0,
|
|
||||||
"blueprintTypeId": 36977,
|
|
||||||
"blueprintName": "Athanor Blueprint"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"last_updated": "2025-08-22T07:33:15+0100",
|
|
||||||
"materials": {
|
|
||||||
"materials": [
|
|
||||||
{
|
|
||||||
"type_id": 21959,
|
|
||||||
"name": "Structure Reprocessing Plant",
|
|
||||||
"quantity": 6.0,
|
|
||||||
"cost_per_unit": 84744021.74,
|
|
||||||
"cost": 508464130.44
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 36957,
|
|
||||||
"name": "Structure Acceleration Coils",
|
|
||||||
"quantity": 2.0,
|
|
||||||
"cost_per_unit": 152817857.14,
|
|
||||||
"cost": 305635714.28
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 36956,
|
|
||||||
"name": "Structure Electromagnetic Sensor",
|
|
||||||
"quantity": 2.0,
|
|
||||||
"cost_per_unit": 141638461.54,
|
|
||||||
"cost": 283276923.08
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21951,
|
|
||||||
"name": "Structure Storage Bay",
|
|
||||||
"quantity": 2.0,
|
|
||||||
"cost_per_unit": 73250833.33,
|
|
||||||
"cost": 146501666.66
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21949,
|
|
||||||
"name": "Structure Hangar Array",
|
|
||||||
"quantity": 2.0,
|
|
||||||
"cost_per_unit": 53526739.13,
|
|
||||||
"cost": 107053478.26
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21947,
|
|
||||||
"name": "Structure Construction Parts",
|
|
||||||
"quantity": 2.0,
|
|
||||||
"cost_per_unit": 52829037.04,
|
|
||||||
"cost": 105658074.08
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21961,
|
|
||||||
"name": "Structure Docking Bay",
|
|
||||||
"quantity": 2.0,
|
|
||||||
"cost_per_unit": 48298064.52,
|
|
||||||
"cost": 96596129.04
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21957,
|
|
||||||
"name": "Structure Repair Facility",
|
|
||||||
"quantity": 2.0,
|
|
||||||
"cost_per_unit": 46331224.49,
|
|
||||||
"cost": 92662448.98
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "6cbd23eaca8941319037b3ac14a4970e",
|
|
||||||
"status": "done",
|
|
||||||
"created_at": "2025-08-22T07:54:47+0100",
|
|
||||||
"structure": "Raitaru",
|
|
||||||
"system": "Jita",
|
|
||||||
"industry_structure": "Sotiyo",
|
|
||||||
"industry_rig": "T1",
|
|
||||||
"reaction_structure": "Athanor",
|
|
||||||
"reaction_rig": "T1",
|
|
||||||
"quantity": 1,
|
|
||||||
"me": 5,
|
|
||||||
"notes": "Test",
|
|
||||||
"blueprint_type_id": 36971,
|
|
||||||
"cookbook": {
|
|
||||||
"error": 0,
|
|
||||||
"status": 200,
|
|
||||||
"message": {
|
|
||||||
"materialCost": 494601665.69,
|
|
||||||
"jobCost": 169775434.21,
|
|
||||||
"additionalCost": 0,
|
|
||||||
"totalCost": 664377099.9,
|
|
||||||
"producedQuantity": 1,
|
|
||||||
"buildCostPerUnit": 664377099.9,
|
|
||||||
"excessMaterialsValue": 0,
|
|
||||||
"blueprintTypeId": 36971,
|
|
||||||
"blueprintName": "Raitaru Blueprint"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"last_updated": "2025-08-22T07:59:54+0100",
|
|
||||||
"materials": {
|
|
||||||
"materials": [
|
|
||||||
{
|
|
||||||
"type_id": 21955,
|
|
||||||
"name": "Structure Factory",
|
|
||||||
"quantity": 1.0,
|
|
||||||
"cost_per_unit": 106032424.24,
|
|
||||||
"cost": 106032424.24
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21959,
|
|
||||||
"name": "Structure Reprocessing Plant",
|
|
||||||
"quantity": 1.0,
|
|
||||||
"cost_per_unit": 84744021.74,
|
|
||||||
"cost": 84744021.74
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21951,
|
|
||||||
"name": "Structure Storage Bay",
|
|
||||||
"quantity": 1.0,
|
|
||||||
"cost_per_unit": 73250833.33,
|
|
||||||
"cost": 73250833.33
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21953,
|
|
||||||
"name": "Structure Laboratory",
|
|
||||||
"quantity": 1.0,
|
|
||||||
"cost_per_unit": 71164821.43,
|
|
||||||
"cost": 71164821.43
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21967,
|
|
||||||
"name": "Structure Office Center",
|
|
||||||
"quantity": 1.0,
|
|
||||||
"cost_per_unit": 67570149.25,
|
|
||||||
"cost": 67570149.25
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21949,
|
|
||||||
"name": "Structure Hangar Array",
|
|
||||||
"quantity": 1.0,
|
|
||||||
"cost_per_unit": 53526739.13,
|
|
||||||
"cost": 53526739.13
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21947,
|
|
||||||
"name": "Structure Construction Parts",
|
|
||||||
"quantity": 1.0,
|
|
||||||
"cost_per_unit": 52829037.04,
|
|
||||||
"cost": 52829037.04
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21961,
|
|
||||||
"name": "Structure Docking Bay",
|
|
||||||
"quantity": 1.0,
|
|
||||||
"cost_per_unit": 48298064.52,
|
|
||||||
"cost": 48298064.52
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21957,
|
|
||||||
"name": "Structure Repair Facility",
|
|
||||||
"quantity": 1.0,
|
|
||||||
"cost_per_unit": 46331224.49,
|
|
||||||
"cost": 46331224.49
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"done_at": "2025-08-22T08:00:14+0100"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "e4661b4a72064437a7f33ced2d446cde",
|
|
||||||
"status": "done",
|
|
||||||
"created_at": "2025-08-22T08:00:05+0100",
|
|
||||||
"structure": "Athanor",
|
|
||||||
"system": "Jita",
|
|
||||||
"industry_structure": "Sotiyo",
|
|
||||||
"industry_rig": "T1",
|
|
||||||
"reaction_structure": "Athanor",
|
|
||||||
"reaction_rig": "T1",
|
|
||||||
"quantity": 1,
|
|
||||||
"me": 0,
|
|
||||||
"notes": "",
|
|
||||||
"blueprint_type_id": 36977,
|
|
||||||
"done_at": "2025-08-22T08:00:15+0100"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "a453ec6587c44d8ebdbb5156c58c9ec7",
|
|
||||||
"status": "done",
|
|
||||||
"created_at": "2025-08-22T08:15:52+0100",
|
|
||||||
"structure": "Keepstar",
|
|
||||||
"system": "Jita",
|
|
||||||
"industry_structure": "Sotiyo",
|
|
||||||
"industry_rig": "T1",
|
|
||||||
"reaction_structure": "Athanor",
|
|
||||||
"reaction_rig": "T1",
|
|
||||||
"quantity": 1,
|
|
||||||
"me": 10,
|
|
||||||
"notes": "",
|
|
||||||
"blueprint_type_id": 36968,
|
|
||||||
"cookbook": {
|
|
||||||
"error": 0,
|
|
||||||
"status": 200,
|
|
||||||
"message": {
|
|
||||||
"materialCost": 156812981803.45,
|
|
||||||
"jobCost": 74872180070.6,
|
|
||||||
"additionalCost": 0,
|
|
||||||
"totalCost": 231685161874.05,
|
|
||||||
"producedQuantity": 1,
|
|
||||||
"buildCostPerUnit": 231685161874.05,
|
|
||||||
"excessMaterialsValue": 0,
|
|
||||||
"blueprintTypeId": 36968,
|
|
||||||
"blueprintName": "Keepstar Blueprint"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"last_updated": "2025-08-22T08:37:05+0100",
|
|
||||||
"materials": {
|
|
||||||
"materials": [
|
|
||||||
{
|
|
||||||
"type_id": 21963,
|
|
||||||
"name": "Structure Market Network",
|
|
||||||
"quantity": 713.0,
|
|
||||||
"cost_per_unit": 166346666.67,
|
|
||||||
"cost": 118605173335.71
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21951,
|
|
||||||
"name": "Structure Storage Bay",
|
|
||||||
"quantity": 179.0,
|
|
||||||
"cost_per_unit": 73250833.33,
|
|
||||||
"cost": 13111899166.07
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21967,
|
|
||||||
"name": "Structure Office Center",
|
|
||||||
"quantity": 179.0,
|
|
||||||
"cost_per_unit": 67570149.25,
|
|
||||||
"cost": 12095056715.75
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21949,
|
|
||||||
"name": "Structure Hangar Array",
|
|
||||||
"quantity": 179.0,
|
|
||||||
"cost_per_unit": 53526739.13,
|
|
||||||
"cost": 9581286304.27
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21947,
|
|
||||||
"name": "Structure Construction Parts",
|
|
||||||
"quantity": 179.0,
|
|
||||||
"cost_per_unit": 52829037.04,
|
|
||||||
"cost": 9456397630.16
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21965,
|
|
||||||
"name": "Structure Medical Center",
|
|
||||||
"quantity": 179.0,
|
|
||||||
"cost_per_unit": 50834772.73,
|
|
||||||
"cost": 9099424318.67
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21961,
|
|
||||||
"name": "Structure Docking Bay",
|
|
||||||
"quantity": 179.0,
|
|
||||||
"cost_per_unit": 48298064.52,
|
|
||||||
"cost": 8645353549.08
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21957,
|
|
||||||
"name": "Structure Repair Facility",
|
|
||||||
"quantity": 179.0,
|
|
||||||
"cost_per_unit": 46331224.49,
|
|
||||||
"cost": 8293289183.71
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21955,
|
|
||||||
"name": "Structure Factory",
|
|
||||||
"quantity": 72.0,
|
|
||||||
"cost_per_unit": 106032424.24,
|
|
||||||
"cost": 7634334545.28
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 36958,
|
|
||||||
"name": "Structure Advertisement Nexus",
|
|
||||||
"quantity": 72.0,
|
|
||||||
"cost_per_unit": 86114000.0,
|
|
||||||
"cost": 6200208000.0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21959,
|
|
||||||
"name": "Structure Reprocessing Plant",
|
|
||||||
"quantity": 72.0,
|
|
||||||
"cost_per_unit": 84744021.74,
|
|
||||||
"cost": 6101569565.28
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21953,
|
|
||||||
"name": "Structure Laboratory",
|
|
||||||
"quantity": 72.0,
|
|
||||||
"cost_per_unit": 71164821.43,
|
|
||||||
"cost": 5123867142.96
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 36957,
|
|
||||||
"name": "Structure Acceleration Coils",
|
|
||||||
"quantity": 8.0,
|
|
||||||
"cost_per_unit": 152817857.14,
|
|
||||||
"cost": 1222542857.12
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 36956,
|
|
||||||
"name": "Structure Electromagnetic Sensor",
|
|
||||||
"quantity": 8.0,
|
|
||||||
"cost_per_unit": 141638461.54,
|
|
||||||
"cost": 1133107692.32
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 3810,
|
|
||||||
"name": "Marines",
|
|
||||||
"quantity": 891.0,
|
|
||||||
"cost_per_unit": 7474.2,
|
|
||||||
"cost": 6659512.2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 13267,
|
|
||||||
"name": "Janitor",
|
|
||||||
"quantity": 223.0,
|
|
||||||
"cost_per_unit": 6525.04,
|
|
||||||
"cost": 1455083.92
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type_id": 21969,
|
|
||||||
"name": "Structure Mission Network",
|
|
||||||
"quantity": 8.0,
|
|
||||||
"cost_per_unit": 0.0,
|
|
||||||
"cost": 0.0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"done_at": "2025-08-22T11:25:47+0100"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "f14623326be343e790e769a0de50d43a",
|
|
||||||
"status": "done",
|
|
||||||
"created_at": "2025-08-22T09:45:25+0100",
|
|
||||||
"structure": "Athanor",
|
|
||||||
"system": "Jita",
|
|
||||||
"industry_structure": "Sotiyo",
|
|
||||||
"industry_rig": "T1",
|
|
||||||
"reaction_structure": "Athanor",
|
|
||||||
"reaction_rig": "None",
|
|
||||||
"quantity": 1,
|
|
||||||
"me": 5,
|
|
||||||
"notes": "",
|
|
||||||
"blueprint_type_id": 36977,
|
|
||||||
"done_at": "2025-08-22T11:46:35+0100"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "bfa32ea583ba44e58872ceb84518c546",
|
|
||||||
"status": "done",
|
|
||||||
"created_at": "2025-08-22T11:45:30+0100",
|
|
||||||
"structure": "Keepstar",
|
|
||||||
"system": "Jita",
|
|
||||||
"industry_structure": "Sotiyo",
|
|
||||||
"industry_rig": "T2",
|
|
||||||
"reaction_structure": "Tatara",
|
|
||||||
"reaction_rig": "T2",
|
|
||||||
"quantity": 1,
|
|
||||||
"me": 6,
|
|
||||||
"notes": "Test",
|
|
||||||
"blueprint_type_id": 36968,
|
|
||||||
"done_at": "2025-08-22T11:46:27+0100"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "63eedb769b854322a75606380954b748",
|
|
||||||
"status": "done",
|
|
||||||
"created_at": "2025-08-22T11:46:53+0100",
|
|
||||||
"structure": "Fortizar",
|
|
||||||
"system": "Amarr",
|
|
||||||
"industry_structure": "Sotiyo",
|
|
||||||
"industry_rig": "T2",
|
|
||||||
"reaction_structure": "Athanor",
|
|
||||||
"reaction_rig": "None",
|
|
||||||
"quantity": 1,
|
|
||||||
"me": 0,
|
|
||||||
"notes": "",
|
|
||||||
"blueprint_type_id": 36967,
|
|
||||||
"done_at": "2025-08-22T12:13:41+0100"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "644be14fb305436ca035eaeea7d7a4e7",
|
|
||||||
"status": "done",
|
|
||||||
"created_at": "2025-08-22T11:47:47+0100",
|
|
||||||
"structure": "Raitaru",
|
|
||||||
"system": "Jita",
|
|
||||||
"industry_structure": "Sotiyo",
|
|
||||||
"industry_rig": "T1",
|
|
||||||
"reaction_structure": "Athanor",
|
|
||||||
"reaction_rig": "None",
|
|
||||||
"quantity": 5,
|
|
||||||
"me": 0,
|
|
||||||
"notes": "",
|
|
||||||
"blueprint_type_id": 36971,
|
|
||||||
"done_at": "2025-08-22T12:13:43+0100"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "6a1c0282910d4f9d95b0fac76438f725",
|
|
||||||
"status": "open",
|
|
||||||
"created_at": "2025-08-22T12:13:50+0100",
|
|
||||||
"structure": "Astrahus",
|
|
||||||
"system": "Jita",
|
|
||||||
"industry_structure": "Sotiyo",
|
|
||||||
"industry_rig": "T1",
|
|
||||||
"reaction_structure": "Athanor",
|
|
||||||
"reaction_rig": "None",
|
|
||||||
"quantity": 1,
|
|
||||||
"me": 5,
|
|
||||||
"notes": "",
|
|
||||||
"blueprint_type_id": 36966,
|
|
||||||
"cache": {
|
|
||||||
"materials": {
|
|
||||||
"error": 0,
|
|
||||||
"message": {
|
|
||||||
"additionalCost": 0,
|
|
||||||
"blueprintName": "Astrahus Blueprint",
|
|
||||||
"blueprintTypeId": 36966,
|
|
||||||
"buildCostPerUnit": 1180755487.44,
|
|
||||||
"excessMaterialsValue": 0,
|
|
||||||
"jobCost": 346965820.03,
|
|
||||||
"materialCost": 833789667.41,
|
|
||||||
"producedQuantity": 1,
|
|
||||||
"totalCost": 1180755487.44
|
|
||||||
},
|
|
||||||
"status": 200
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
Flask==3.1.2
|
Flask==3.1.2
|
||||||
Requests==2.32.5
|
Requests==2.32.5
|
||||||
|
tinydb==4.8.2
|
||||||
59
webapp/data/migrate.py
Normal file
59
webapp/data/migrate.py
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import os, json
|
||||||
|
from tinydb import TinyDB
|
||||||
|
from tinydb.storages import Storage
|
||||||
|
|
||||||
|
# Paths
|
||||||
|
OLD_FILE = "orders.json"
|
||||||
|
ARCHIVE_FILE = "orders_old.json"
|
||||||
|
NEW_FILE = "orders_new.json" # final TinyDB JSON file
|
||||||
|
TABLE_NAME = "orders"
|
||||||
|
|
||||||
|
|
||||||
|
class PrettyJSONStorage(Storage):
|
||||||
|
"""Custom TinyDB storage that pretty-prints JSON."""
|
||||||
|
def __init__(self, path):
|
||||||
|
self.path = path
|
||||||
|
|
||||||
|
def read(self):
|
||||||
|
try:
|
||||||
|
with open(self.path, "r", encoding="utf-8") as f:
|
||||||
|
return json.load(f)
|
||||||
|
except FileNotFoundError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def write(self, data):
|
||||||
|
with open(self.path, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
|
||||||
|
def migrate():
|
||||||
|
if not os.path.isfile(OLD_FILE):
|
||||||
|
print("No old JSON file found. Nothing to migrate.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Load old orders
|
||||||
|
with open(OLD_FILE, "r", encoding="utf-8") as f:
|
||||||
|
orders = json.load(f) or []
|
||||||
|
|
||||||
|
if not orders:
|
||||||
|
print("No orders found in the old JSON.")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(orders)
|
||||||
|
|
||||||
|
# Open TinyDB and insert into table
|
||||||
|
db = TinyDB(NEW_FILE, storage=PrettyJSONStorage)
|
||||||
|
orders_table = db.table(TABLE_NAME)
|
||||||
|
for order in orders:
|
||||||
|
orders_table.insert(order)
|
||||||
|
|
||||||
|
# Rename old file to archive
|
||||||
|
os.rename(OLD_FILE, ARCHIVE_FILE)
|
||||||
|
os.rename(NEW_FILE, OLD_FILE)
|
||||||
|
print(f"Migrated {len(orders)} orders into table '{TABLE_NAME}'.")
|
||||||
|
print(f"Old JSON file renamed to '{ARCHIVE_FILE}'.")
|
||||||
|
print(f"New TinyDB JSON file is '{OLD_FILE}'.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
migrate()
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -2,18 +2,14 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import time
|
import time
|
||||||
from flask import Blueprint, render_template, redirect, url_for
|
from flask import Blueprint, render_template, redirect, url_for
|
||||||
from webapp.storage.orders import load_orders, update_order
|
from webapp.storage.orders import load_archived, mark_archived
|
||||||
|
|
||||||
bp = Blueprint("archive", __name__)
|
bp = Blueprint("archive", __name__)
|
||||||
|
|
||||||
@bp.get("/archiv")
|
@bp.get("/archiv")
|
||||||
def archive_index():
|
def archive_index():
|
||||||
"""Zeigt ausschließlich Aufträge mit status == 'archived'."""
|
"""Zeigt ausschließlich Aufträge mit status == 'archived'."""
|
||||||
archived = [o for o in load_orders() if o.get("status") == "archived"]
|
archived = load_archived()
|
||||||
archived.sort(
|
|
||||||
key=lambda o: (o.get("archived_at") or o.get("done_at") or o.get("created_at") or ""),
|
|
||||||
reverse=True,
|
|
||||||
)
|
|
||||||
return render_template("archive.html", archived_orders=archived)
|
return render_template("archive.html", archived_orders=archived)
|
||||||
|
|
||||||
@bp.post("/archiv/add/<order_id>")
|
@bp.post("/archiv/add/<order_id>")
|
||||||
@@ -23,5 +19,5 @@ def archive_add(order_id: str):
|
|||||||
Danach BLEIBEN wir auf der Strukturen-Seite (kein Wechsel zur Archiv-Seite).
|
Danach BLEIBEN wir auf der Strukturen-Seite (kein Wechsel zur Archiv-Seite).
|
||||||
"""
|
"""
|
||||||
now = time.strftime("%Y-%m-%dT%H:%M:%S%z", time.gmtime())
|
now = time.strftime("%Y-%m-%dT%H:%M:%S%z", time.gmtime())
|
||||||
update_order(order_id, {"status": "archived", "archived_at": now})
|
mark_archived(order_id)
|
||||||
return redirect(url_for("structures.structures")) # zurück zu /strukturen
|
return redirect(url_for("structures.structures")) # zurück zu /strukturen
|
||||||
|
|||||||
@@ -10,17 +10,17 @@ from webapp.services.ccookbook import (
|
|||||||
)
|
)
|
||||||
# Storage
|
# Storage
|
||||||
from webapp.storage.orders import (
|
from webapp.storage.orders import (
|
||||||
load_orders, update_order,
|
update_order, get_order_by_id,
|
||||||
cache_costs, cache_materials,
|
cache_costs, cache_materials, load_pending
|
||||||
)
|
)
|
||||||
|
|
||||||
bp = Blueprint("cookbook", __name__, url_prefix="/api")
|
bp = Blueprint("cookbook", __name__, url_prefix="/api")
|
||||||
|
|
||||||
|
# ----------------------------- Helpers ----------------------------------------
|
||||||
|
|
||||||
def _now() -> str:
|
def _now() -> str:
|
||||||
return time.strftime("%Y-%m-%dT%H:%M:%S%z", time.gmtime())
|
return time.strftime("%Y-%m-%dT%H:%M:%S%z", time.gmtime())
|
||||||
|
|
||||||
# ----------------------------- Helpers ----------------------------------------
|
|
||||||
|
|
||||||
def _arg(name: str, default: str = "") -> str:
|
def _arg(name: str, default: str = "") -> str:
|
||||||
v = request.args.get(name)
|
v = request.args.get(name)
|
||||||
return v if v is not None else default
|
return v if v is not None else default
|
||||||
@@ -31,12 +31,6 @@ def _to_int(s: str, default: int = 0) -> int:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return default
|
return default
|
||||||
|
|
||||||
def _order_by_id(order_id: str) -> Dict[str, Any] | None:
|
|
||||||
for o in load_orders():
|
|
||||||
if o.get("id") == order_id:
|
|
||||||
return o
|
|
||||||
return None
|
|
||||||
|
|
||||||
# ----------------------------- Endpoints – Raw --------------------------------
|
# ----------------------------- Endpoints – Raw --------------------------------
|
||||||
|
|
||||||
@bp.get("/cookbook/build_cost")
|
@bp.get("/cookbook/build_cost")
|
||||||
@@ -113,7 +107,7 @@ def api_cache(order_id: str):
|
|||||||
|
|
||||||
@bp.post("/order/<order_id>/refresh")
|
@bp.post("/order/<order_id>/refresh")
|
||||||
def api_refresh_one(order_id: str):
|
def api_refresh_one(order_id: str):
|
||||||
o = _order_by_id(order_id)
|
o = get_order_by_id(order_id)
|
||||||
if not o:
|
if not o:
|
||||||
return jsonify({"error": "order not found"}), 404
|
return jsonify({"error": "order not found"}), 404
|
||||||
bp_id = o.get("blueprint_type_id")
|
bp_id = o.get("blueprint_type_id")
|
||||||
@@ -172,7 +166,7 @@ def api_refresh_one(order_id: str):
|
|||||||
|
|
||||||
@bp.post("/orders/refresh_all")
|
@bp.post("/orders/refresh_all")
|
||||||
def api_refresh_all():
|
def api_refresh_all():
|
||||||
orders = [o for o in load_orders() if o.get("status") == "open" and o.get("blueprint_type_id")]
|
orders = [o for o in load_pending() if o.get("blueprint_type_id")]
|
||||||
done = 0
|
done = 0
|
||||||
for o in orders:
|
for o in orders:
|
||||||
try:
|
try:
|
||||||
@@ -195,8 +189,8 @@ def api_open_costs():
|
|||||||
"""
|
"""
|
||||||
items: List[Dict[str, Any]] = []
|
items: List[Dict[str, Any]] = []
|
||||||
total = 0.0
|
total = 0.0
|
||||||
for o in load_orders():
|
for o in load_pending():
|
||||||
if o.get("status") != "open" or not o.get("blueprint_type_id"):
|
if not o.get("blueprint_type_id"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
entry: Dict[str, Any] = {
|
entry: Dict[str, Any] = {
|
||||||
@@ -258,8 +252,8 @@ def api_open_materials():
|
|||||||
if cost is not None:
|
if cost is not None:
|
||||||
row["cost"] += float(cost or 0)
|
row["cost"] += float(cost or 0)
|
||||||
|
|
||||||
for o in load_orders():
|
for o in load_pending():
|
||||||
if o.get("status") != "open" or not o.get("blueprint_type_id"):
|
if not o.get("blueprint_type_id"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
mats = o.get("materials")
|
mats = o.get("materials")
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import uuid, time
|
|||||||
from typing import List, Dict, Any
|
from typing import List, Dict, Any
|
||||||
from flask import Blueprint, render_template, request, redirect, url_for
|
from flask import Blueprint, render_template, request, redirect, url_for
|
||||||
|
|
||||||
from webapp.storage.orders import load_orders, add_order, mark_done
|
from webapp.storage.orders import load_pending,load_done, add_order, mark_done
|
||||||
from webapp.services.blueprints import resolve_blueprint_id
|
from webapp.services.blueprints import resolve_blueprint_id
|
||||||
|
|
||||||
bp = Blueprint("structures", __name__)
|
bp = Blueprint("structures", __name__)
|
||||||
@@ -16,12 +16,7 @@ REAC_STRUCTS= ["Athanor", "Tatara"]
|
|||||||
REAC_RIGS = ["None", "T1", "T2"]
|
REAC_RIGS = ["None", "T1", "T2"]
|
||||||
|
|
||||||
def _split_orders() -> Dict[str, List[Dict[str, Any]]]:
|
def _split_orders() -> Dict[str, List[Dict[str, Any]]]:
|
||||||
orders = load_orders()
|
return {"open": load_pending(), "done": load_done()}
|
||||||
open_orders = [o for o in orders if o.get("status") == "open"]
|
|
||||||
done_orders = [o for o in orders if o.get("status") == "done"]
|
|
||||||
open_orders.sort(key=lambda o: o.get("created_at",""), reverse=True)
|
|
||||||
done_orders.sort(key=lambda o: o.get("done_at","") or "", reverse=True)
|
|
||||||
return {"open": open_orders, "done": done_orders}
|
|
||||||
|
|
||||||
@bp.route("/strukturen", methods=["GET", "POST"])
|
@bp.route("/strukturen", methods=["GET", "POST"])
|
||||||
def structures():
|
def structures():
|
||||||
|
|||||||
@@ -1,55 +1,117 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import os, json, time
|
import os, json, time
|
||||||
from typing import List, Dict, Any
|
from typing import List, Dict, Any
|
||||||
from flask import current_app
|
from flask import current_app, g
|
||||||
|
from tinydb import TinyDB, Query
|
||||||
|
from tinydb.storages import Storage
|
||||||
|
|
||||||
FILE_NAME = "orders.json"
|
FILE_NAME = "orders.json"
|
||||||
|
|
||||||
def _file_path() -> str:
|
PRODUCTION = 'dev'
|
||||||
return os.path.join(current_app.root_path, "data", FILE_NAME)
|
|
||||||
|
class PrettyJSONStorage(Storage):
|
||||||
|
"""Custom TinyDB storage that pretty-prints JSON."""
|
||||||
|
def __init__(self, path):
|
||||||
|
self.path = path
|
||||||
|
|
||||||
|
def read(self):
|
||||||
|
try:
|
||||||
|
with open(self.path, "r", encoding="utf-8") as f:
|
||||||
|
return json.load(f)
|
||||||
|
except FileNotFoundError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def write(self, data):
|
||||||
|
with open(self.path, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_db() -> TinyDB:
|
||||||
|
"""
|
||||||
|
Return a persistent TinyDB instance per Flask app context.
|
||||||
|
Stored in `g` to avoid reopening the file multiple times.
|
||||||
|
"""
|
||||||
|
if "orders_db" not in g:
|
||||||
|
db_path = os.path.join(current_app.root_path, "data", FILE_NAME)
|
||||||
|
if PRODUCTION == "dev":
|
||||||
|
g.orders_db = TinyDB(db_path, storage=PrettyJSONStorage )
|
||||||
|
else:
|
||||||
|
g.orders_db = TinyDB(db_path)
|
||||||
|
return g.orders_db
|
||||||
|
|
||||||
|
|
||||||
|
def get_orders_table():
|
||||||
|
"""Return the orders table."""
|
||||||
|
return get_db().table("orders")
|
||||||
|
|
||||||
def load_orders() -> List[Dict[str, Any]]:
|
def load_orders() -> List[Dict[str, Any]]:
|
||||||
p = _file_path()
|
"""Return all orders as a list of dicts."""
|
||||||
if not os.path.isfile(p): return []
|
table = get_orders_table()
|
||||||
try:
|
return table.all()
|
||||||
with open(p, "r", encoding="utf-8") as f:
|
|
||||||
return json.load(f) or []
|
|
||||||
except Exception:
|
|
||||||
return []
|
|
||||||
|
|
||||||
def _save_orders(orders: List[Dict[str, Any]]) -> None:
|
def get_order_by_id(order_id: str) -> Dict[str, Any] | None:
|
||||||
p = _file_path()
|
"""Return a single order by its ID, or None if not found."""
|
||||||
os.makedirs(os.path.dirname(p), exist_ok=True)
|
table = get_orders_table()
|
||||||
with open(p, "w", encoding="utf-8") as f:
|
Order = Query()
|
||||||
json.dump(orders, f, ensure_ascii=False, indent=2)
|
result = table.get(Order.id == order_id)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def load_archived() -> List[Dict[str, Any]]:
|
||||||
|
"""Return all archived orders, sorted by archived/done/created date descending."""
|
||||||
|
table = get_orders_table()
|
||||||
|
Order = Query()
|
||||||
|
archived = table.search(Order.status == "archived")
|
||||||
|
|
||||||
|
def sort_key(o: Dict[str, Any]) -> str:
|
||||||
|
return o.get("archived_at") or o.get("done_at") or o.get("created_at") or ""
|
||||||
|
|
||||||
|
archived.sort(key=sort_key, reverse=True)
|
||||||
|
return archived
|
||||||
|
|
||||||
|
def load_pending() -> List[Dict[str, Any]]:
|
||||||
|
"""Return all orders with status 'open', sorted by created_at descending."""
|
||||||
|
table = get_orders_table()
|
||||||
|
Order = Query()
|
||||||
|
pending = table.search(Order.status == "open")
|
||||||
|
pending.sort(key=lambda o: o.get("created_at", ""), reverse=True)
|
||||||
|
return pending
|
||||||
|
|
||||||
|
|
||||||
|
def load_done() -> List[Dict[str, Any]]:
|
||||||
|
"""Return all orders with status 'done', sorted by done_at descending."""
|
||||||
|
table = get_orders_table()
|
||||||
|
Order = Query()
|
||||||
|
done = table.search(Order.status == "done")
|
||||||
|
done.sort(key=lambda o: o.get("done_at") or "", reverse=True)
|
||||||
|
return done
|
||||||
|
|
||||||
def add_order(order: Dict[str, Any]) -> None:
|
def add_order(order: Dict[str, Any]) -> None:
|
||||||
orders = load_orders()
|
table = get_orders_table()
|
||||||
orders.append(order)
|
table.insert(order)
|
||||||
_save_orders(orders)
|
|
||||||
|
|
||||||
def mark_done(order_id: str) -> bool:
|
def mark_done(order_id: str) -> bool:
|
||||||
orders = load_orders()
|
table = get_orders_table()
|
||||||
changed = False
|
Order = Query()
|
||||||
now = time.strftime("%Y-%m-%dT%H:%M:%S%z", time.gmtime())
|
now = time.strftime("%Y-%m-%dT%H:%M:%S%z", time.gmtime())
|
||||||
for o in orders:
|
updated = table.update({"status": "done", "done_at": now}, Order.id == order_id)
|
||||||
if o.get("id") == order_id and o.get("status") != "done":
|
return bool(updated)
|
||||||
o["status"] = "done"
|
|
||||||
o["done_at"] = now
|
def mark_archived(order_id: str) -> bool:
|
||||||
changed = True
|
"""Mark an order as archived and set archived_at timestamp."""
|
||||||
if changed: _save_orders(orders)
|
now = time.strftime("%Y-%m-%dT%H:%M:%S%z", time.gmtime())
|
||||||
return changed
|
table = get_orders_table()
|
||||||
|
Order = Query()
|
||||||
|
updated = table.update({"status": "archived", "archived_at": now}, Order.id == order_id)
|
||||||
|
return bool(updated)
|
||||||
|
|
||||||
def update_order(order_id: str, patch: Dict[str, Any]) -> bool:
|
def update_order(order_id: str, patch: Dict[str, Any]) -> bool:
|
||||||
orders = load_orders()
|
table = get_orders_table()
|
||||||
ok = False
|
Order = Query()
|
||||||
for o in orders:
|
updated = table.update(patch, Order.id == order_id)
|
||||||
if o.get("id") == order_id:
|
return bool(updated)
|
||||||
o.update(patch)
|
|
||||||
ok = True
|
|
||||||
break
|
|
||||||
if ok: _save_orders(orders)
|
|
||||||
return ok
|
|
||||||
|
|
||||||
def cache_costs(order_id: str, costs: Dict[str, Any]) -> bool:
|
def cache_costs(order_id: str, costs: Dict[str, Any]) -> bool:
|
||||||
now = time.strftime("%Y-%m-%dT%H:%M:%S%z", time.gmtime())
|
now = time.strftime("%Y-%m-%dT%H:%M:%S%z", time.gmtime())
|
||||||
@@ -57,4 +119,4 @@ def cache_costs(order_id: str, costs: Dict[str, Any]) -> bool:
|
|||||||
|
|
||||||
def cache_materials(order_id: str, mats: Dict[str, Any]) -> bool:
|
def cache_materials(order_id: str, mats: Dict[str, Any]) -> bool:
|
||||||
now = time.strftime("%Y-%m-%dT%H:%M:%S%z", time.gmtime())
|
now = time.strftime("%Y-%m-%dT%H:%M:%S%z", time.gmtime())
|
||||||
return update_order(order_id, {"materials": mats, "last_updated": now})
|
return update_order(order_id, {"materials": mats, "last_updated": now})
|
||||||
Reference in New Issue
Block a user