From ff200598095adfba59b89b162410806f77f2d6c5 Mon Sep 17 00:00:00 2001 From: Nico Melone Date: Thu, 24 Aug 2023 17:51:28 -0500 Subject: [PATCH] v1 finalized --- Billing-Report-2023-08-22.xlsx | Bin 0 -> 28162 bytes Billing-Report-2023-08-23.xlsx | Bin 0 -> 28856 bytes billing.log | 540 +++++++++++++++++++++++++++++++ hp-billing-report.ipynb | 558 ++++++++++++++++++++++++--------- hp-billing-report.py | 534 +++++++++++++++++++++++++++++++ mistawayData.py | 265 ++++++++++++++++ output.xlsx | Bin 27201 -> 0 bytes reportBuilder.py | 155 +++++++++ requirements.txt | 6 + thingsBoardData.py | 130 ++++++++ 10 files changed, 2041 insertions(+), 147 deletions(-) create mode 100644 Billing-Report-2023-08-22.xlsx create mode 100644 Billing-Report-2023-08-23.xlsx create mode 100644 hp-billing-report.py create mode 100644 mistawayData.py delete mode 100644 output.xlsx create mode 100644 reportBuilder.py create mode 100644 requirements.txt create mode 100644 thingsBoardData.py diff --git a/Billing-Report-2023-08-22.xlsx b/Billing-Report-2023-08-22.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..7efd4f263d3064844bb1d6f55ffbb24792b17a94 GIT binary patch literal 28162 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 JSp59&{{XCGNAdsw literal 0 HcmV?d00001 diff --git a/Billing-Report-2023-08-23.xlsx b/Billing-Report-2023-08-23.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..13aeb6f839708fbfaeaa0c1c544af985206a7791 GIT binary patch literal 28856 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 31.654963:\n", + " so = \"Banay\"\n", + " price = 75\n", + " elif location.within(denali_east):\n", + " so = \"Denali East\"\n", + " if type == \"dual_flowmeter\":\n", + " price = 75\n", + " elif type == \"plcfreshwater\":\n", + " price = 55\n", + " cellular_cost = 0\n", + " billing_type = \"Networked\"\n", + " else: #if location.within(jitterbug):\n", + " so = \"Jitterbug\"\n", + " if type == \"dual_flowmeter\":\n", + " price = 75\n", + " elif type == \"plcfreshwater\":\n", + " price = 55\n", + " cellular_cost = 0\n", + " billing_type = \"Networked\"\n", + " \n", + " \n", + " if so not in mistaway_data[customer]:\n", + " mistaway_data[customer][so] = {}\n", + "\n", + " mistaway_data[customer][so][device] = {\n", + " \"Sales Price\": price,\n", + " \"Platform Cost\": 10,\n", + " \"Platform\": \"Mistaway\", # \"thingsboard\", \"mistaway\"\n", + " \"Cellular Cost\": cellular_cost,\n", + " \"Billing Type\": billing_type # \"stand-alone\", \"AP\", \"AP-bundled\", \"networked\", \"stand-alone-wifi\"\n", + " }\n", " \n", " \n", " " @@ -323,7 +485,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -332,22 +494,97 @@ " for c in customers.data:\n", " cname = c.name\n", " cid = c.id.id\n", - " if cname != \"Test Company\":\n", + " if cname not in [\"Test Company\", \"Amerus Safety Solutions\"]:\n", + " #create new company if it doesn't exist\n", " if cname not in thingsboard_data:\n", - " thingsboard_data[cname] = {f\"HPSO-1\": {}}\n", + " thingsboard_data[cname] = {}\n", + " #get devices of a company\n", " devices = rest_client.get_customer_devices(customer_id=cid, page_size=pageSize, page=page)\n", + " #go through each device and store its data in the dict\n", " for device in devices.data:\n", + " cellular_cost = 15\n", + " #fix naming to work with JSON/dict\n", " if '\"' in device.name:\n", " deviceName = device.name.replace('\"', 'in')\n", " else:\n", " deviceName = device.name\n", - " thingsboard_data[cname][\"HPSO-1\"][deviceName] = {\n", - " \"Sales Price\": 75,\n", - " \"Platform Cost\": 0,\n", - " \"Platform\": \"ThingsBoard\", # \"thingsboard\", \"mistaway\"\n", - " \"Cellular Cost\": 15,\n", - " \"Billing Type\": \"Stand-Alone\" # \"stand-alone\", \"AP\", \"AP-bundled\", \"networked\", \"stand-alone-wifi\"\n", - " }\n", + " # Sort Device details\n", + " if cname == \"Chuda Resources\":\n", + " so = \"Water Wells\"\n", + " price = 75\n", + " billing_type = \"Stand-Alone\"\n", + " elif cname == \"Henry Petroleum\":\n", + " so = \"Check Meters\"\n", + " price = 50\n", + " billing_type = \"Stand-Alone\"\n", + " elif cname == \"Faskens\":\n", + " if device.type == \"tankalarms\":\n", + " so = \"Tanks\"\n", + " billing_type = \"Stand-Alone\"\n", + " price = 50\n", + " elif device.type in [\"advvfdipp\", \"plcfreshwater\"]:\n", + " so = \"Water Wells\"\n", + " billing_type = \"Stand-Alone\"\n", + " price = 50\n", + " elif device.type == \"plcpond\":\n", + " so = \"Ponds\"\n", + " billing_type = \"Stand-Alone\"\n", + " price = 50\n", + " else:\n", + " so = \"HPSO-1\"\n", + " billing_type = \"Stand-Alone\"\n", + " price = 50\n", + " elif cname == \"Henry Resources\":\n", + " if deviceName == \"Pearl Central\":\n", + " so = \"Henry Resources\"\n", + " price = 300\n", + " billing_type = \"Stand-Alone-WiFi\"\n", + " else:\n", + " so = \"Henry Resources\"\n", + " price = 275\n", + " billing_type = \"Stand-Alone\"\n", + " elif cname == \"ConocoPhillips\":\n", + " if device.type == \"flowmeterskid\":\n", + " so = \"Portable Meter\"\n", + " price = 50\n", + " billing_type = \"Stand-Alone\"\n", + " elif device.type == \"plcfreshwater\":\n", + " so = \"Water Well\"\n", + " price = 50\n", + " cellular_cost = 0\n", + " billing_type = \"Networked\"\n", + " elif device.type == \"advvfdipp\":\n", + " so = \"Santa Rosa\"\n", + " price = 50\n", + " billing_type = \"Stand-Alone\"\n", + " elif device.type == \"Gateway\":\n", + " so = \"AP\"\n", + " price = 0\n", + " billing_type = \"AP-bundled\"\n", + " elif device.type == \"cpdualflowmeter\":\n", + " so = \"Pond/Flowmeter\"\n", + " price = 50\n", + " billing_type = \"Networked\"\n", + " elif cname == \"Saulsbury Ventures\":\n", + " so = \"Saulsbury Ventures\"\n", + " price = 50\n", + " billing_type = \"Stand-Alone\"\n", + " else:\n", + " so = \"HPSO-1\"\n", + " price = 50\n", + " billing_type = \"Stand-Alone\"\n", + " \n", + " #make a new Sales Order if it doesn't exist\n", + " if so not in thingsboard_data[cname]:\n", + " thingsboard_data[cname][so] = {}\n", + " #add device to Sales Order under Company\n", + " thingsboard_data[cname][so][deviceName] = {\n", + " \"Sales Price\": price,\n", + " \"Platform Cost\": 0,\n", + " \"Platform\": \"ThingsBoard\", # \"thingsboard\", \"mistaway\"\n", + " \"Cellular Cost\": cellular_cost,\n", + " \"Billing Type\": billing_type # \"stand-alone\", \"AP\", \"AP-bundled\", \"networked\", \"stand-alone-wifi\"\n", + " }\n", " return thingsboard_data" ] }, @@ -374,7 +611,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ @@ -383,7 +620,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ @@ -403,47 +640,36 @@ }, { "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'CrownQuest': {'HPSO-1': {'Nail Ranch 37 SR 2-3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wrage 21 SR 2-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wrage 28 SR 2-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Free 40 WS 2-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 1 WS 1-9': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 1 WS 1-10B': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 39 WS 1-3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 4 WS 1-10': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Horton 34 WS 10-5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Rig Pump #3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Rig Pump #4': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'CQ Wrage Ranch 32 SR 1-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'LimeQuest 5 WS 10-10': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson Ranch 34 SR 2-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Nail Ranch 2 SR 3-3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Nail Ranch 38 SR 2-3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Nail Ranch 25 SR 2-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Nail Ranch 28 SR 3-3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Nail Ranch 38 SR 1-3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Nail Ranch 3 SR 3-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Nail Ranch 28 SR 2-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Nail Ranch 28 SR 1-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Guitar 22 SR 3-3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson Ranch 33 SR 2-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson Ranch 35 SR 1-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson Ranch 1 SR 2-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Limequest Transfer Lite': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'S. Wilkinson Transfer Lite': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Nail Ranch 2 SR 2-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Horton Transfer Lite': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'South Wilkinson Transfer #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson Ranch 37 SR 2-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 39 WS 1-5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 39 WS 1-4': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 39 WS 1-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Free 40 WS 1-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 39 WS 1-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Free 32 WS 2-7': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Free 32 WS 3-10C': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Free 40 WS 6-5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Free 40 WS 1-4': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Free 40 WS 1-6': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Free 32 WS 3-10A': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 34 WS 9-10': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 33 WS 10-3A': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 33 WS 10-3B': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 33 WS 10-1B': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 33 WS 6-7': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Free 32 WS 3-10B': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'LimeQuest 5 WS 9-9': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'LimeQuest 5 WS 6-8': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'LimeQuest 5 WS 2-4': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'LimeQuest 5 WS 8-5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'LimeQuest 5 WS 7-5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'LimeQuest 5 WS 4-7': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Horton 23 WS 5-6': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Horton 23 WS 8-6': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Horton 23 WS 6-5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Horton 23 WS 6-6': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Horton 34 WS 1-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Horton 34 WS 1-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Horton 23 WS 5-3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Horton 23 WS 5-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Horton 23 WS 5-5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 37 WS 1-9B': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 39 WS 2-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 37 WS 1-8': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 1 WS 9-4B': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'ToolBox South': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Rig Pump #8': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'LimeQuest 5 WS 7-9': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Horton 34 WS 1-4': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'LimeQuest 5 WS 3-5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Free Transfer Pit': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 34 WS 5-10': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 33 WS 5-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 33 WS 6-3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 37 WS 7-8': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 33 WS 4-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 37 WS 8-8': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 34 WS 1-8': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 39 WS 2-4': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 37 WS 10-9': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 33 WS 3-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 34 WS 2-10': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 37 WS 1-5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 37 WS 3-5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 37 WS 3-6': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 37 WS 5-7': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 34 WS 10-9': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 39 WS 1-10': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 37 WS 4-7': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 39 WS 2-8': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson Ranch 39 SR 1-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 37 WS 1-7': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'LimeQuest 5 WS 8-9': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'LimeQuest 5 WS 1-4': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'LimeQuest 10 WS 3-6': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wrage 33 SR 3-3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'N. Wilkinson Transfer Lite': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 33 WS 10-4': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 34 WS 9-9': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 1 WS 2-10': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 33 ws 10-1A': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 37 WS 1-10': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 1 WS 1-10A': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Rig Pump #7': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Horton 34 WS 1-3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 39 ws 3-8': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 34 WS 6-10': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Free 40 SR 2-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 33 WS 7-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Nail Ranch 12 SR 1-3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 33 WS 6-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'LimeQuest 6 SR 1-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 39 WS 1-7': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 1 WS 2-9': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 34 WS 10-10': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 39 WS 2-10': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Free 40 WS 1-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 39 WS 1-6': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'ToolBox North': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 33 WS 10-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Nail Ranch 37 SR 3-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 37 WS 8-6': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Rig Pump #6': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 37 WS 5-5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Rig Pump #10': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'LLL 6 SR 1-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 39 WS 1-9': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 39 WS 1-8': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wilkinson 39 WS 2-6': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'LimeQuest 5 WS 10-9': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Rig Pump #11': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Rig Pump #12': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}}}, 'Summit Petroleum': {'HPSO-1': {'Bowling WW 4-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 7-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 5-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Bowling WW 37-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 504': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 18 #4': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 18 #9': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Windham 108-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Windham 108-3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Florence WW #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Florence WW #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Madelyn Kate #3 WW': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Jessica WW #3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Windham 108-7': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Windham 108-6': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Windham 108-5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Windham 107-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Windham 107-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Windham 108-8': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Windham 108-10': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Windham 108-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Windham 108-9': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Jessica WW #7': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Carmanita WW 12-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Carmanita WW 12-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay North Frac Pit': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay South Frac Pit': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay South Inlet': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 18 #3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Carmanita WW 12-3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 8-5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 8-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 6-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 18 #10': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Carmanita WW 12-4': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 18 #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Caden WW #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Caden WW #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Caden WW #3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Caden WW #4': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Lisa WW #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Madeline WW #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Caden WW #6': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Laurie Gwen WW #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Jessica WW #4': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Jessica WW #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Jessica WW #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Denali East Frac Pit': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 8-4': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Jessica WW #5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Map Rock Transfer Pump Monitor': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay North Pit Inlet #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay North Pit Outlet #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Yvonne Frac Pit': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Denali Frac Pit': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Cindy #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Cindy #3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Cindy #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Lindsey #3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Elizabeth 1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Railway 12-3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Railway 12-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Elizabeth B1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Elizabeth B2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Rhonda 1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Sec 46 #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Cynthia 1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Nancy #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Nancy #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Rhonda Pit': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Jitterbug 28-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Reagan #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Aurora 7': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Aurora 8': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Aurora 9': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Aurora 10': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Aurora 11': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Aurora 6': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'RebJean #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Terri #6': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'RobJane #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'RobJane #3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'RebJean #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'RobJane #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Kelsey #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Stephanie 41 #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Kelsey #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Stephanie 41 #3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'RobJane #4': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Terri #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Terri #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Terri #3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Terri #4': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Mary 43 #3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Mary 43 #5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Mary 43 #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Mary 43 #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'KD #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'KD #4': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'KD #7': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'KD #5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Bobbie #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Bobbie #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Elizabeth A1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Patty #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Rhonda 2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Terri Transfer Pump Monitor': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Trumann 1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Trumann 3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Trumann 4': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Trumann 5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Trumann 2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Patty #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Kate A1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Kate A2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Kate B1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Tessa Lyn': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Patty #3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Smith #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Smith #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Dorcus': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Monique #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Monique #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Monique #3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Dawn #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Dawn #3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Yvonne Transfer Pump 3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Yvonne Transfer Pump 2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Yvonne Transfer Pump 1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Bobbie #3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Kelsey Pit': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 18 #5': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 5-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 8-3': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 18 #7': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 806 North': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 806 South': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 18 #8': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Denali East Inlet': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Lindsey #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Lindsey #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Denali East Transfer Pump Monitor': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Map Rock Transfer Pump Monitor #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Terri Frac Pit': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Dawn Frac Pit': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Barnett 19-2 WW': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Laney A #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Barnett 24-1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Nancy Pit': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 18 #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 18 #6': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 6-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW #7': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Banay WW 7-2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Penny North': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Penny South': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Terri Pit Inlet': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Baylee Pit': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}}}, 'Keegan Faudree Water': {'HPSO-1': {'Faudree Frac Pit Pump #1': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Faudree Frac Pit Pump #2': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Faudree West Tank Transfer': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Faudree East Transfer': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}}}, 'Henry Resources': {'HPSO-1': {'Melinda 252': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Gwendolyn SWD Transfer Station': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Benners North': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Avery Central': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Lisa Central': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'RankinBaker SWD': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wynn Central': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Sadie Central': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Benners Central': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Denise Central': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Emma Central': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Hollis Central': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Meredith Central': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'John J Bush Central': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Joshua Central': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Gwendolyn 23': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Noel Central': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Gwendolyn 24': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Gila S2': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Pearl Central': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Benedum Central': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}}}, 'Wishbone Water': {'HPSO-1': {'Wishbone Water #27 SR': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wishbone Water Well #14 SR': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wishbone/SM Booster Station': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}}}, 'Patriot Resources': {'HPSO-1': {'Transfer Addax Pit': {'Sales Price': 75, 'Platform Cost': 10, 'Platform': 'Mistaway', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}}}, 'Saulsbury Ventures': {'HPSO-1': {'Power Plant Transfer': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Triple 4in': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'InHand-Demo': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Dove Lease Checkmeter': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Single 12in': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}}}, 'Chuda Resources': {'HPSO-1': {'Chuda Flow Meter #1': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Chuda Flow Meter #4': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Chuda Flow Meter #2': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Chuda Flow Meter #3': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}}}, 'Faskens': {'HPSO-1': {'BV-602': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BZ-201': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'AU-3401': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BP Pond': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BL-3201': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BW-72': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'AW Battery': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BZ-202': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BN Pond': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BE-71': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'CI-401': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BJ-701': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BI-31': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BE-601': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BP-201': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'AA-101': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'AV-701': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'FB-501': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BQ-41': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BX-101': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BN-2202': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Fee BM Battery': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BP Battery': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BK-1701': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BQ-301': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Valve Controller': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BV-601': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'AW-901': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'CG-701': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'AS-11': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BL-3401': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BE-51': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BW-041': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'CG-601': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BM-1501': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BX-901': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'CI-501': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'AT-101': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BX-902': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'AW-3401': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BN-301': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BV Battery': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'S-601': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'CF Pond': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BY-501': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BK-801': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'CI-1301': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BP-601': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'CF-1501': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BV-101': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'BJ-101': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'AA Pond': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}}}, 'Amerus Safety Solutions': {'HPSO-1': {'Camera Trailer 107': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 200': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 129': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 202': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 206': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 201': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 102': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 110': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 203': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 204': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 116': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 101': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 127': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 109': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 128': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 112': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 114': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 120': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 119': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 103': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 100': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 205': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 105': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 106': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 126': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 111': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 115': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 117': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 122': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 113': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 104': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 108': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 123': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Camera Trailer 130': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}}}, 'Henry Petroleum': {'HPSO-1': {'Davis Check Meter': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Great Western Check Meter': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Francis Hill Check Meter': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Foundation Check Meter': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Wess Hill Check Meter': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Lively Check Meter': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Glasscock Check Meter': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Mann Check Meter': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}}}, 'Test Company': {'HPSO-1': {'HP Test Location 2': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'HP Test Location': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}}}, 'ConocoPhillips': {'HPSO-1': {'CRMWD': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well 42': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well A 35': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well 36': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well A 41': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well A 39': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well A 37': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well B 36': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well 45': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well A 34': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well A 43': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well A 46': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well 38': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well A 40': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well A 44': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Prod Well 27': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well A 30': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well 29': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well 31': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well 28': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Pond A Gateway': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Headlee 3401 WS in3 Meter': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Purity-B': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'HP Inlet - 10in': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well A 33': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Ratliff Well A 32': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Tree Gateway': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'HP Outlet - 8in': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Parks Inlet #2 - 10in': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Yukon A': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Parks Inlet #1- 10in': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Pond A': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Purity-A': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Yukon B': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, '12in Flow Meter': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Parks Outlet - 6in': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Tree 22': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Tree 14': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Tree Pond': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Tree 17': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Tree 26': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Tree 13': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Tree 21': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Tree 20': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Tree 19': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Tree 25': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Tree 15': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Tree 16': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Tree 18': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}, 'Tree 23': {'Sales Price': 75, 'Platform Cost': 0, 'Platform': 'ThingsBoard', 'Cellular Cost': 15, 'Billing Type': 'Stand-Alone'}}}}\n" - ] - } - ], - "source": [ - "print(excel_data)" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "#Build report from data" - ] - }, - { - "cell_type": "code", - "execution_count": 25, + "execution_count": 41, "metadata": {}, "outputs": [], "source": [ + "#Build report from data\n", "import xlsxwriter\n", "import pandas as pd\n", "\n", "# Create a new Excel writer object\n", - "with pd.ExcelWriter(\"output.xlsx\", engine=\"xlsxwriter\") as writer:\n", + "with pd.ExcelWriter(f\"Billing-Report-{dt.date(dt.now())}.xlsx\", engine=\"xlsxwriter\") as writer:\n", + " # Formats\n", + " bold_format = writer.book.add_format({'bold': True})\n", + " header_format = writer.book.add_format({'bold': True, 'center_across': True, 'border': True, 'bottom': True})\n", + " currency_format = writer.book.add_format({'num_format': \"[$$-409]#,##0.00\"})\n", + " bold_currency_format = writer.book.add_format({'num_format': \"[$$-409]#,##0.00\", 'bold': True})\n", + " highlight_format = writer.book.add_format({'bg_color': \"yellow\"})\n", + " # Setting up overview sheet\n", + " overview = writer.book.add_worksheet(\"Overview\")\n", + " overview_row = 1\n", + " overview.write(0,0, \"Customer\", header_format)\n", + " overview.write(0,1, \"Revenue\", header_format)\n", + " overview.write(0,2, \"Platform Cost\", header_format)\n", + " overview.write(0,3, \"Cellular Cost\", header_format)\n", + " overview.write(0,4, \"Profit\", header_format)\n", "\n", + " \n", " # Loop through customers\n", " for customer, orders in excel_data.items():\n", - " \n", " rows = []\n", - "\n", + " counts = {}\n", " # Loop through each sales order for the customer\n", " for order, items in orders.items():\n", " for item, details in items.items():\n", @@ -453,21 +679,59 @@ " }\n", " row.update(details)\n", " rows.append(row)\n", - " \n", + " counts[order] = len(items)\n", + " \n", " # Convert the data to a DataFrame\n", " df = pd.DataFrame(rows)\n", " \n", " # Sort by sales order\n", " df = df.sort_values(by=\"Sales Order\")\n", - " \n", + " \n", " # Write to a specific sheet in the Excel file\n", " df.to_excel(writer, sheet_name=customer, index=False)\n", - "\n", " for column in df:\n", " column_length = max(df[column].astype(str).map(len).max(), len(column))\n", " col_idx = df.columns.get_loc(column)\n", - " writer.sheets[customer].set_column(col_idx, col_idx, column_length)\n", - " " + " if col_idx in [2,3,5]:\n", + " writer.sheets[customer].set_column(col_idx, col_idx, column_length, currency_format)\n", + " else:\n", + " writer.sheets[customer].set_column(col_idx, col_idx, column_length)\n", + " \n", + " # Get the dimensions of the dataframe.\n", + " (max_row, max_col) = df.shape\n", + " #Apply highlighting\n", + " writer.sheets[customer].conditional_format(f\"G2:G{max_row+1}\", {\"type\": \"text\", \"criteria\": \"not containing\", \"value\": \"AP-bundled\", \"format\": highlight_format})\n", + "\n", + " #writer.sheets[customer].set_column(2,3,None,currency_format)\n", + " #manually adding extra calculated values\n", + " sales_formula = f\"C2:C{max_row+1}\"\n", + " platform_formula = f\"D2:D{max_row+1}\"\n", + " cellular_formula = f\"F2:F{max_row+1}\"\n", + " profit_formula = f\"=B{max_row+3} - B{max_row+4} - B{max_row+5}\"\n", + " writer.sheets[customer].write(f'A{max_row+3}', \"Revenue\", bold_format)\n", + " writer.sheets[customer].write(f'A{max_row+4}', \"Platform Cost\", bold_format)\n", + " writer.sheets[customer].write(f'A{max_row+5}', \"Cellular Cost\", bold_format)\n", + " writer.sheets[customer].write(f'A{max_row+6}', \"Profit\", bold_format)\n", + " writer.sheets[customer].write(f'B{max_row+3}', '=SUM(' + sales_formula + ')', bold_currency_format)\n", + " writer.sheets[customer].write(f'B{max_row+4}', '=SUM(' + platform_formula + ')', bold_currency_format)\n", + " writer.sheets[customer].write(f'B{max_row+5}', '=SUM(' + cellular_formula + ')', bold_currency_format)\n", + " writer.sheets[customer].write_formula(f'B{max_row+6}', profit_formula, bold_currency_format)\n", + " for ind,order in enumerate(counts):\n", + " writer.sheets[customer].write(f'A{max_row+8+ind}', order)\n", + " writer.sheets[customer].write(f'B{max_row+8+ind}', counts[order])\n", + " overview.write(overview_row,0, customer)\n", + " overview.write(overview_row,1, f\"='{customer}'!B{max_row+3}\")\n", + " overview.write(overview_row,2, f\"='{customer}'!B{max_row+4}\")\n", + " overview.write(overview_row,3, f\"='{customer}'!B{max_row+5}\")\n", + " overview.write(overview_row,4, f\"='{customer}'!B{max_row+6}\")\n", + " overview_row += 1\n", + " overview.write(overview_row,0, \"Total\", bold_format)\n", + " overview.write(overview_row,1, f\"=SUM(B2:B{overview_row})\", bold_currency_format)\n", + " overview.write(overview_row,2, f\"=SUM(C2:C{overview_row})+399\", bold_currency_format)\n", + " overview.write(overview_row,3, f\"=SUM(D2:D{overview_row})\", bold_currency_format)\n", + " overview.write(overview_row,4, f\"=B{overview_row+1} - C{overview_row+1} - D{overview_row+1}\", bold_currency_format)\n", + "\n", + " overview.set_column(0,4, 18)" ] } ], diff --git a/hp-billing-report.py b/hp-billing-report.py new file mode 100644 index 0000000..cb78117 --- /dev/null +++ b/hp-billing-report.py @@ -0,0 +1,534 @@ +# %% +import lattice +import logging +import json + +logger = logging.getLogger('billing_reports') +logger.setLevel(logging.INFO) + +fh = logging.FileHandler('/Users/nico/Documents/Github/hp-billing-report/billing.log') +fh.setLevel(logging.INFO) + +ch = logging.StreamHandler() +ch.setLevel(logging.ERROR) + +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +fh.setFormatter(formatter) +ch.setFormatter(formatter) + +logger.addHandler(fh) +logger.addHandler(ch) + +# %% +#Mistaway data collection +from datetime import datetime as dt + +json_file_output = False +console_output = False + +# %% +nodes = lattice.getNodes() + +# %% +# Find a value for a given key in a given dictionary +def _findItem(obj, key): + if key in obj: return obj[key] + for k, v in obj.items(): + if isinstance(v,dict): + item = _findItem(v, key) + if item is not None: + return item + +# %% +# recursively go through folders to build folder structure +def putFolder(folder, fs): + try: + if not folder["id"] == folder["parentFolderId"]: + parent = _findItem(fs, folder["parentFolderId"]) + parent[folder["id"]] = folder + putFolder(parent,fs) + else: + fs[folder["id"]] = folder + return fs + except Exception as e: + logger.error(f"Exception in putFolder: {e}") + + +# %% +# Go through every folder and build a proper folder structure +# Output to JSON file +folders = lattice.getFolders() +foldermap = {} +#print(json.dumps(folders, indent=4)) +for folder in folders: + logger.debug(folder) + putFolder(folder,foldermap) +if console_output: + print(json.dumps(foldermap, indent=4)) +if json_file_output: + with open("./folderMap" + str(dt.date(dt.now())) +".json", "w") as f: + json.dump(foldermap, f, indent=4) + +# %% +# Go through every node and collect unique device id (MAC) +# Output to JSON file +foldersTracker = [] +vanityMap = {} +deviceTypes = {} +for type in lattice.getNodeTypes(): + deviceTypes[type["id"]] = type["name"] +for node in nodes: + if not node["uniqueId"][-6:] in [":00:00", ":00:30"]: + if not node["folderId"] in foldersTracker: + foldersTracker.append(node["folderId"]) + folder = _findItem(foldermap, node["folderId"]) + if folder: + deviceName = folder["name"] + latitude = folder["location"]["lat"] + longitude = folder["location"]["lng"] + pfolder = _findItem(foldermap, folder["parentFolderId"]) + ppfolder = _findItem(foldermap, pfolder["parentFolderId"]) + customer = ppfolder["name"] + vanityMap[node["uniqueId"]] = {"deviceName": deviceName, "deviceType": deviceTypes[node["nodeTypeId"]], "customer": customer, "latitude": latitude, "longitude": longitude} + else: + logger.info("Folder does not exist: " + str(node["folderId"])) + else: + logger.info("Folder already in list: " + str(node["folderId"])) +#print(vanityMap) +if json_file_output: + with open("./deviceMap" + str(dt.date(dt.now())) +".json", "w") as f: + json.dump(vanityMap, f, indent=4) + + +# %% +""" +Data to be collected: + { + "customer":{ + "sales_order": { + "billable_item_1": { + "sales_price": 75, + "platform_cost": 10, + "platform": "thingsboard", # "thingsboard", "mistaway" + "cellular_cost": 15, + "billing_type": "stand-alone" # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + }, + "billable_item_2:{...}, + ... + }, + "sales_order_2":{...} + }, + "customer_2":{...} + } +""" + +# %% +mistaway_data = {} +from shapely.geometry import Point, Polygon + +denali_east = Polygon([(31.441289, -102.175343),(31.467676, -101.936571), (31.321496, -101.943604),(31.304714, -102.139878) ]) +jitterbug = [] +for key, value in vanityMap.items(): + customer = value["customer"] + device = value["deviceName"] + type = value["deviceType"] + location = Point(value["latitude"], value["longitude"]) + if not device in ["Melinda 252"]: + cellular_cost = 15 + so = "HPSO-1" + price = 75 + billing_type = "Stand-Alone" + if customer not in mistaway_data: + mistaway_data[customer] = {} + + if customer == "CrownQuest": + if device == "LimeQuest 6 SR 1-1": + so = "LimeQuest SO" + price = 75 + billing_type = "Stand-Alone" + elif "Wilkinson 39" in device or device in ["Wilkinson 37 WS 1-9B", "Wilkinson 37 WS 1-9B", "Free 40 WS 1-2", "Free 40 WS 1-4", "Free 40 WS 1-1"]: + so = "Wilkinson 39 Field" + price = 0 + billing_type = "AP-bundled" + cellular_cost = 0 + if so not in mistaway_data[customer]: + mistaway_data[customer][so] = {} + if "Wilkinson 39 AP" not in mistaway_data[customer][so]: + mistaway_data[customer][so]["Wilkinson 39 AP"] = { + "Sales Price": 250, + "Platform Cost": 0, + "Platform": "Mistaway", # "thingsboard", "mistaway" + "Cellular Cost": 15, + "Billing Type": "AP" # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + elif "Wilkinson 37" in device or device in ["Wilkinson 33 WS 3-1", "Wilkinson 33 WS 4-1", "Wilkinson 34 WS 2-10", "Wilkinson 34 WS 1-8"]: + so = "Wilkinson 37 Field" + price = 0 + billing_type = "AP-bundled" + cellular_cost = 0 + if so not in mistaway_data[customer]: + mistaway_data[customer][so] = {} + if "Wilkinson 37 AP" not in mistaway_data[customer][so]: + mistaway_data[customer][so]["Wilkinson 37 AP"] = { + "Sales Price": 250, + "Platform Cost": 0, + "Platform": "Mistaway", # "thingsboard", "mistaway" + "Cellular Cost": 15, + "Billing Type": "AP" # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + elif "Wilkinson 33" in device or "Wilkinson 34" in device or "Wilkinson 1" in device or "Wilkinson 4" in device: + so = "Wilkinson 33-34 Field" + price = 0 + billing_type = "AP-bundled" + cellular_cost = 0 + if so not in mistaway_data[customer]: + mistaway_data[customer][so] = {} + if "Wilkinson 33-34 AP" not in mistaway_data[customer][so]: + mistaway_data[customer][so]["Wilkinson 33-34 AP"] = { + "Sales Price": 250, + "Platform Cost": 0, + "Platform": "Mistaway", # "thingsboard", "mistaway" + "Cellular Cost": 15, + "Billing Type": "AP" # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + elif "Free 40" in device or "Free 32" in device: + so = "Free Field" + price = 0 + billing_type = "AP-bundled" + cellular_cost = 0 + if so not in mistaway_data[customer]: + mistaway_data[customer][so] = {} + if "Free AP" not in mistaway_data[customer][so]: + mistaway_data[customer][so]["Free AP"] = { + "Sales Price": 250, + "Platform Cost": 0, + "Platform": "Mistaway", # "thingsboard", "mistaway" + "Cellular Cost": 15, + "Billing Type": "AP" # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + elif "LimeQuest 5" in device or "LimeQuest 10" in device: + so = "LimeQuest Field" + price = 0 + billing_type = "AP-bundled" + cellular_cost = 0 + if so not in mistaway_data[customer]: + mistaway_data[customer][so] = {} + if "LimeQuest AP" not in mistaway_data[customer][so]: + mistaway_data[customer][so]["LimeQuest AP"] = { + "Sales Price": 250, + "Platform Cost": 0, + "Platform": "Mistaway", # "thingsboard", "mistaway" + "Cellular Cost": 15, + "Billing Type": "AP" # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + elif "LimeQuest 5" in device or "LimeQuest 10" in device: + so = "LimeQuest Field" + price = 0 + billing_type = "AP-bundled" + cellular_cost = 0 + if so not in mistaway_data[customer]: + mistaway_data[customer][so] = {} + if "LimeQuest AP" not in mistaway_data[customer][so]: + mistaway_data[customer][so]["LimeQuest AP"] = { + "Sales Price": 250, + "Platform Cost": 0, + "Platform": "Mistaway", # "thingsboard", "mistaway" + "Cellular Cost": 15, + "Billing Type": "AP" # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + elif "Horton 23" in device or "Horton 34" in device: + so = "Horton Field" + price = 0 + billing_type = "AP-bundled" + cellular_cost = 0 + if so not in mistaway_data[customer]: + mistaway_data[customer][so] = {} + if "Horton AP" not in mistaway_data[customer][so]: + mistaway_data[customer][so]["Horton AP"] = { + "Sales Price": 250, + "Platform Cost": 0, + "Platform": "Mistaway", # "thingsboard", "mistaway" + "Cellular Cost": 15, + "Billing Type": "AP" # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + elif type == "advvfdipp" or type == "ipp": + so = "Santa Rosa" + elif type == "rigpump": + so = "Rig Pump" + elif type == "transferlite": + so = "Transfer" + elif customer == "Patriot Resources": + so = "Patriot Resources" + price = 100 + elif customer == "Keagan Faudree Water": + so = "Keagan Faudree Water" + elif customer == "Summit Petroleum": + if location.x >= 31.654963: + so = "Banay" + price = 75 + elif location.within(denali_east): + so = "Denali East" + if type == "dual_flowmeter": + price = 75 + elif type == "plcfreshwater": + price = 55 + cellular_cost = 0 + billing_type = "Networked" + else: #if location.within(jitterbug): + so = "Jitterbug" + if type == "dual_flowmeter": + price = 75 + elif type == "plcfreshwater": + price = 55 + cellular_cost = 0 + billing_type = "Networked" + + + if so not in mistaway_data[customer]: + mistaway_data[customer][so] = {} + + mistaway_data[customer][so][device] = { + "Sales Price": price, + "Platform Cost": 10, + "Platform": "Mistaway", # "thingsboard", "mistaway" + "Cellular Cost": cellular_cost, + "Billing Type": billing_type # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + + + + +# %% +#ThingsBoard data collection +from tb_rest_client.rest_client_ce import * +from tb_rest_client.rest import ApiException + +# %% +# ThingsBoard REST API URL +url = "https://hp.henrypump.cloud" +# Default Tenant Administrator credentials +username = "henry.pump.automation@gmail.com" +password = "Henry Pump @ 2022" + +# %% +def getDevices(rest_client, customers, page=0, pageSize=500): + thingsboard_data = {} + for c in customers.data: + cname = c.name + cid = c.id.id + if cname not in ["Test Company", "Amerus Safety Solutions"]: + #create new company if it doesn't exist + if cname not in thingsboard_data: + thingsboard_data[cname] = {} + #get devices of a company + devices = rest_client.get_customer_devices(customer_id=cid, page_size=pageSize, page=page) + #go through each device and store its data in the dict + for device in devices.data: + cellular_cost = 15 + #fix naming to work with JSON/dict + if '"' in device.name: + deviceName = device.name.replace('"', 'in') + else: + deviceName = device.name + # Sort Device details + if cname == "Chuda Resources": + so = "Water Wells" + price = 75 + billing_type = "Stand-Alone" + elif cname == "Henry Petroleum": + so = "Check Meters" + price = 50 + billing_type = "Stand-Alone" + elif cname == "Faskens": + if device.type == "tankalarms": + so = "Tanks" + billing_type = "Stand-Alone" + price = 50 + elif device.type in ["advvfdipp", "plcfreshwater"]: + so = "Water Wells" + billing_type = "Stand-Alone" + price = 50 + elif device.type == "plcpond": + so = "Ponds" + billing_type = "Stand-Alone" + price = 50 + else: + so = "HPSO-1" + billing_type = "Stand-Alone" + price = 50 + elif cname == "Henry Resources": + if deviceName == "Pearl Central": + so = "Henry Resources" + price = 300 + billing_type = "Stand-Alone-WiFi" + else: + so = "Henry Resources" + price = 275 + billing_type = "Stand-Alone" + elif cname == "ConocoPhillips": + if device.type == "flowmeterskid": + so = "Portable Meter" + price = 50 + billing_type = "Stand-Alone" + elif device.type == "plcfreshwater": + so = "Water Well" + price = 50 + cellular_cost = 0 + billing_type = "Networked" + elif device.type == "advvfdipp": + so = "Santa Rosa" + price = 50 + billing_type = "Stand-Alone" + elif device.type == "Gateway": + so = "AP" + price = 0 + billing_type = "AP-bundled" + elif cname == "Saulsbury Ventures": + so = "Saulsbury Ventures" + price = 50 + billing_type = "Stand-Alone" + else: + so = "HPSO-1" + price = 50 + billing_type = "Stand-Alone" + + #make a new Sales Order if it doesn't exist + if so not in thingsboard_data[cname]: + thingsboard_data[cname][so] = {} + #add device to Sales Order under Company + thingsboard_data[cname][so][deviceName] = { + "Sales Price": price, + "Platform Cost": 0, + "Platform": "ThingsBoard", # "thingsboard", "mistaway" + "Cellular Cost": cellular_cost, + "Billing Type": billing_type # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + return thingsboard_data + +# %% +def getThingsBoardData(url, username, password): + # Creating the REST client object with context manager to get auto token refresh + with RestClientCE(base_url=url) as rest_client: + try: + # Auth with credentials + rest_client.login(username=username, password=password) + # Get customers > get devices under a target customer > get keys for devices > get data for devices + customers = rest_client.get_customers(page_size="100", page="0") + thingsboard_data = getDevices(rest_client=rest_client, customers=customers) + return thingsboard_data + except ApiException as e: + logger.error(e) + return False + +# %% +thingsboard_data = getThingsBoardData(url, username,password) + +# %% +#Mixing data from Mistaway and ThingsBoard +excel_data = {} +excel_data.update(mistaway_data) +for customer in thingsboard_data.keys(): + if customer in excel_data: + for so in thingsboard_data[customer].keys(): + if so in excel_data[customer]: + excel_data[customer][so].update(thingsboard_data[customer][so]) + else: + excel_data[customer].update(thingsboard_data[customer]) + else: + excel_data[customer] = thingsboard_data[customer] + + +# %% +#Build report from data +import xlsxwriter +import pandas as pd + +def highlight_rows(row): + """Function to apply row highlighting for non 'AP-bundled' billing types.""" + return 'background-color: yellow' if row['Billing Type'] != 'AP-bundled' else '' + + +# Create a new Excel writer object +with pd.ExcelWriter(f"Billing-Report-{dt.date(dt.now())}.xlsx", engine="xlsxwriter") as writer: + overview = writer.book.add_worksheet("Overview") + overview_row = 1 + overview.write(0,1, "Revenue") + overview.write(0,2, "Platform Cost") + overview.write(0,3, "Cellular Cost") + overview.write(0,4, "Profit") + # Loop through customers + for customer, orders in excel_data.items(): + + rows = [] + counts = {} + # Loop through each sales order for the customer + for order, items in orders.items(): + for item, details in items.items(): + """ + details_copy = details.copy() + details_copy["item"] = item + details_copy["order"] = order if item.endswith("1") else "" # Display order only once per customer + rows.append(details_copy) + """ + row = { + "Sales Order": order, + "Location": item + } + row.update(details) + rows.append(row) + counts[order] = len(items) + + # Convert the data to a DataFrame + df = pd.DataFrame(rows) + + # Sort by sales order + df = df.sort_values(by="Sales Order") + #df = df.sort_values(by=["order", "item"]) + + + # Apply the highlighting + df_style = df.style.applymap(lambda x: highlight_rows({'Billing Type': x}) if isinstance(x, str) else "", subset=['Billing Type']) + + # Write to a specific sheet in the Excel file + #df.to_excel(writer, sheet_name=customer, index=False) + df_style.to_excel(writer, sheet_name=customer, index=False, header=True) + for column in df: + column_length = max(df[column].astype(str).map(len).max(), len(column)) + col_idx = df.columns.get_loc(column) + writer.sheets[customer].set_column(col_idx, col_idx, column_length) + # Get the dimensions of the dataframe. + (max_row, max_col) = df.shape + #manually adding extra calculated values + sales_formula = f"C2:C{max_row+1}" + platform_formula = f"D2:D{max_row+1}" + cellular_formula = f"F2:F{max_row+1}" + profit_formula = f"=B{max_row+3} - B{max_row+4} - B{max_row+5}" + writer.sheets[customer].write(f'A{max_row+3}', "Revenue") + writer.sheets[customer].write(f'A{max_row+4}', "Platform Cost") + writer.sheets[customer].write(f'A{max_row+5}', "Cellular Cost") + writer.sheets[customer].write(f'A{max_row+6}', "Profit") + writer.sheets[customer].write(f'B{max_row+3}', '=SUM(' + sales_formula + ')', ) + writer.sheets[customer].write(f'B{max_row+4}', '=SUM(' + platform_formula + ')', ) + writer.sheets[customer].write(f'B{max_row+5}', '=SUM(' + cellular_formula + ')', ) + writer.sheets[customer].write_formula(f'B{max_row+6}', profit_formula, ) + for ind,order in enumerate(counts): + writer.sheets[customer].write(f'A{max_row+8+ind}', order) + writer.sheets[customer].write(f'B{max_row+8+ind}', counts[order]) + overview.write(overview_row,0, customer) + overview.write(overview_row,1, f"='{customer}'!B{max_row+3}") + overview.write(overview_row,2, f"='{customer}'!B{max_row+4}") + overview.write(overview_row,3, f"='{customer}'!B{max_row+5}") + overview.write(overview_row,4, f"='{customer}'!B{max_row+6}") + overview_row += 1 + overview.write(overview_row,0, "Total") + overview.write(overview_row,1, f"=SUM(B2:B{overview_row})") + overview.write(overview_row,2, f"=SUM(C2:C{overview_row})+399") + overview.write(overview_row,3, f"=SUM(D2:D{overview_row})") + overview.write(overview_row,4, f"=B{overview_row+1} - C{overview_row+1} - D{overview_row+1}") + + overview.set_column(0,4, 18) + +# %% + + + diff --git a/mistawayData.py b/mistawayData.py new file mode 100644 index 0000000..53cd836 --- /dev/null +++ b/mistawayData.py @@ -0,0 +1,265 @@ +#Mistaway data collection +import lattice, logging +from shapely.geometry import Point, Polygon +from datetime import datetime as dt + +logger = logging.getLogger('billing_reports') +logger.setLevel(logging.INFO) +ch = logging.StreamHandler() +ch.setLevel(logging.INFO) +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +ch.setFormatter(formatter) +logger.addHandler(ch) + +# Find a value for a given key in a given dictionary +def _findItem(obj, key): + if key in obj: return obj[key] + for k, v in obj.items(): + if isinstance(v,dict): + item = _findItem(v, key) + if item is not None: + return item + + +# recursively go through folders to build folder structure +def putFolder(folder, fs): + try: + if not folder["id"] == folder["parentFolderId"]: + parent = _findItem(fs, folder["parentFolderId"]) + parent[folder["id"]] = folder + putFolder(parent,fs) + else: + fs[folder["id"]] = folder + return fs + except Exception as e: + logger.debug(f"Exception in putFolder: {e}") + +def getMistAwayData(): + # Go through every folder and build a proper folder structure + # Output to JSON file + nodes = lattice.getNodes() + folders = lattice.getFolders() + foldermap = {} + for folder in folders: + logger.debug(folder) + putFolder(folder,foldermap) + + # Go through every node and collect unique device id (MAC) + # Output to JSON file + foldersTracker = [] + vanityMap = {} + deviceTypes = {} + for type in lattice.getNodeTypes(): + deviceTypes[type["id"]] = type["name"] + for node in nodes: + if not node["uniqueId"][-6:] in [":00:00", ":00:30"]: + if not node["folderId"] in foldersTracker: + foldersTracker.append(node["folderId"]) + folder = _findItem(foldermap, node["folderId"]) + if folder: + deviceName = folder["name"] + latitude = folder["location"]["lat"] + longitude = folder["location"]["lng"] + pfolder = _findItem(foldermap, folder["parentFolderId"]) + ppfolder = _findItem(foldermap, pfolder["parentFolderId"]) + customer = ppfolder["name"] + vanityMap[node["uniqueId"]] = {"deviceName": deviceName, "deviceType": deviceTypes[node["nodeTypeId"]], "customer": customer, "latitude": latitude, "longitude": longitude} + else: + logger.info("Folder does not exist: " + str(node["folderId"])) + else: + logger.info("Folder already in list: " + str(node["folderId"])) + + """ + Data to be collected: + { + "customer":{ + "sales_order": { + "billable_item_1": { + "sales_price": 75, + "platform_cost": 10, + "platform": "thingsboard", # "thingsboard", "mistaway" + "cellular_cost": 15, + "billing_type": "stand-alone" # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + }, + "billable_item_2:{...}, + ... + }, + "sales_order_2":{...} + }, + "customer_2":{...} + } + """ + + mistaway_data = {} + + denali_east = Polygon([(31.441289, -102.175343),(31.467676, -101.936571), (31.321496, -101.943604),(31.304714, -102.139878) ]) + for _, value in vanityMap.items(): + customer = value["customer"] + device = value["deviceName"] + type = value["deviceType"] + location = Point(value["latitude"], value["longitude"]) + if not device in ["Melinda 252"]: + cellular_cost = 15 + so = "HPSO-1" + price = 75 + billing_type = "Stand-Alone" + if customer not in mistaway_data: + mistaway_data[customer] = {} + + if customer == "CrownQuest": + if device == "LimeQuest 6 SR 1-1": + so = "LimeQuest SO" + price = 75 + billing_type = "Stand-Alone" + elif "Wilkinson 39" in device or device in ["Wilkinson 37 WS 1-9B", "Wilkinson 37 WS 1-9B", "Free 40 WS 1-2", "Free 40 WS 1-4", "Free 40 WS 1-1"]: + so = "Wilkinson 39 Field" + price = 0 + billing_type = "AP-bundled" + cellular_cost = 0 + if so not in mistaway_data[customer]: + mistaway_data[customer][so] = {} + if "Wilkinson 39 AP" not in mistaway_data[customer][so]: + mistaway_data[customer][so]["Wilkinson 39 AP"] = { + "Sales Price": 250, + "Platform Cost": 0, + "Platform": "Mistaway", # "thingsboard", "mistaway" + "Cellular Cost": 15, + "Billing Type": "AP" # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + elif "Wilkinson 37" in device or device in ["Wilkinson 33 WS 3-1", "Wilkinson 33 WS 4-1", "Wilkinson 34 WS 2-10", "Wilkinson 34 WS 1-8"]: + so = "Wilkinson 37 Field" + price = 0 + billing_type = "AP-bundled" + cellular_cost = 0 + if so not in mistaway_data[customer]: + mistaway_data[customer][so] = {} + if "Wilkinson 37 AP" not in mistaway_data[customer][so]: + mistaway_data[customer][so]["Wilkinson 37 AP"] = { + "Sales Price": 250, + "Platform Cost": 0, + "Platform": "Mistaway", # "thingsboard", "mistaway" + "Cellular Cost": 15, + "Billing Type": "AP" # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + elif "Wilkinson 33" in device or "Wilkinson 34" in device or "Wilkinson 1" in device or "Wilkinson 4" in device: + so = "Wilkinson 33-34 Field" + price = 0 + billing_type = "AP-bundled" + cellular_cost = 0 + if so not in mistaway_data[customer]: + mistaway_data[customer][so] = {} + if "Wilkinson 33-34 AP" not in mistaway_data[customer][so]: + mistaway_data[customer][so]["Wilkinson 33-34 AP"] = { + "Sales Price": 250, + "Platform Cost": 0, + "Platform": "Mistaway", # "thingsboard", "mistaway" + "Cellular Cost": 15, + "Billing Type": "AP" # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + elif "Free 40" in device or "Free 32" in device: + so = "Free Field" + price = 0 + billing_type = "AP-bundled" + cellular_cost = 0 + if so not in mistaway_data[customer]: + mistaway_data[customer][so] = {} + if "Free AP" not in mistaway_data[customer][so]: + mistaway_data[customer][so]["Free AP"] = { + "Sales Price": 250, + "Platform Cost": 0, + "Platform": "Mistaway", # "thingsboard", "mistaway" + "Cellular Cost": 15, + "Billing Type": "AP" # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + elif "LimeQuest 5" in device or "LimeQuest 10" in device: + so = "LimeQuest Field" + price = 0 + billing_type = "AP-bundled" + cellular_cost = 0 + if so not in mistaway_data[customer]: + mistaway_data[customer][so] = {} + if "LimeQuest AP" not in mistaway_data[customer][so]: + mistaway_data[customer][so]["LimeQuest AP"] = { + "Sales Price": 250, + "Platform Cost": 0, + "Platform": "Mistaway", # "thingsboard", "mistaway" + "Cellular Cost": 15, + "Billing Type": "AP" # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + elif "LimeQuest 5" in device or "LimeQuest 10" in device: + so = "LimeQuest Field" + price = 0 + billing_type = "AP-bundled" + cellular_cost = 0 + if so not in mistaway_data[customer]: + mistaway_data[customer][so] = {} + if "LimeQuest AP" not in mistaway_data[customer][so]: + mistaway_data[customer][so]["LimeQuest AP"] = { + "Sales Price": 250, + "Platform Cost": 0, + "Platform": "Mistaway", # "thingsboard", "mistaway" + "Cellular Cost": 15, + "Billing Type": "AP" # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + elif "Horton 23" in device or "Horton 34" in device: + so = "Horton Field" + price = 0 + billing_type = "AP-bundled" + cellular_cost = 0 + if so not in mistaway_data[customer]: + mistaway_data[customer][so] = {} + if "Horton AP" not in mistaway_data[customer][so]: + mistaway_data[customer][so]["Horton AP"] = { + "Sales Price": 250, + "Platform Cost": 0, + "Platform": "Mistaway", # "thingsboard", "mistaway" + "Cellular Cost": 15, + "Billing Type": "AP" # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + elif type == "advvfdipp" or type == "ipp": + so = "Santa Rosa" + elif type == "rigpump": + so = "Rig Pump" + elif type == "transferlite": + so = "Transfer" + elif customer == "Patriot Resources": + so = "Patriot Resources" + price = 100 + elif customer == "Keagan Faudree Water": + so = "Keagan Faudree Water" + elif customer == "Summit Petroleum": + if location.x >= 31.654963: + so = "Banay" + price = 75 + elif location.within(denali_east): + so = "Denali East" + if type == "dual_flowmeter": + price = 75 + elif type == "plcfreshwater": + price = 55 + cellular_cost = 0 + billing_type = "Networked" + else: #if location.within(jitterbug): + so = "Jitterbug" + if type == "dual_flowmeter": + price = 75 + elif type == "plcfreshwater": + price = 55 + cellular_cost = 0 + billing_type = "Networked" + + + if so not in mistaway_data[customer]: + mistaway_data[customer][so] = {} + + mistaway_data[customer][so][device] = { + "Sales Price": price, + "Platform Cost": 10, + "Platform": "Mistaway", # "thingsboard", "mistaway" + "Cellular Cost": cellular_cost, + "Billing Type": billing_type # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + return mistaway_data + + + \ No newline at end of file diff --git a/output.xlsx b/output.xlsx deleted file mode 100644 index 2285f6536c81326f0b42b7f22e90bc201d47a18e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27201 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 a&s|qp9_cPL0tW}Wdj{Tlw1p;rz572M-Z_Q< diff --git a/reportBuilder.py b/reportBuilder.py new file mode 100644 index 0000000..8e84477 --- /dev/null +++ b/reportBuilder.py @@ -0,0 +1,155 @@ +#Build report from data +import pandas as pd +from datetime import datetime as dt +import os, boto3 +from thingsBoardData import getThingsBoardData +from mistawayData import getMistAwayData +import logging + +from email.mime.multipart import MIMEMultipart +from email import encoders +from email.mime.base import MIMEBase + +logger = logging.getLogger('billing_reports') +logger.setLevel(logging.INFO) +ch = logging.StreamHandler() +ch.setLevel(logging.INFO) +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +ch.setFormatter(formatter) +logger.addHandler(ch) + +ses = boto3.client('ses') +EMAIL_FROM_ADDRESS = "alerts@henry-pump.com" +email_to = [ + "nmelone@henry-pump.com" + ] + +#Get Mistaway Data +mistaway_data = getMistAwayData() +#Get ThingsBoard Data +thingsboard_data = getThingsBoardData(os.environ["url"], os.environ["username"],os.environ["password"]) +#Mixing data from Mistaway and ThingsBoard +excel_data = {} +excel_data.update(mistaway_data) +for customer in thingsboard_data.keys(): + if customer in excel_data: + for so in thingsboard_data[customer].keys(): + if so in excel_data[customer]: + excel_data[customer][so].update(thingsboard_data[customer][so]) + else: + excel_data[customer].update(thingsboard_data[customer]) + else: + excel_data[customer] = thingsboard_data[customer] + +def reportBuilder(event, context): + # Create a new Excel writer object + with pd.ExcelWriter(f"/tmp/Remote-Monitoring-Report-{dt.date(dt.now())}.xlsx", engine="xlsxwriter") as writer: + # Formats + bold_format = writer.book.add_format({'bold': True}) + header_format = writer.book.add_format({'bold': True, 'center_across': True, 'border': True, 'bottom': True}) + currency_format = writer.book.add_format({'num_format': "[$$-409]#,##0.00"}) + bold_currency_format = writer.book.add_format({'num_format': "[$$-409]#,##0.00", 'bold': True}) + highlight_format = writer.book.add_format({'bg_color': "yellow"}) + # Setting up overview sheet + overview = writer.book.add_worksheet("Overview") + overview_row = 1 + overview.write(0,0, "Customer", header_format) + overview.write(0,1, "Revenue", header_format) + overview.write(0,2, "Platform Cost", header_format) + overview.write(0,3, "Cellular Cost", header_format) + overview.write(0,4, "Profit", header_format) + + + # Loop through customers + for customer, orders in excel_data.items(): + rows = [] + counts = {} + # Loop through each sales order for the customer + for order, items in orders.items(): + for item, details in items.items(): + row = { + "Sales Order": order, + "Location": item + } + row.update(details) + rows.append(row) + counts[order] = len(items) + + # Convert the data to a DataFrame + df = pd.DataFrame(rows) + + # Sort by sales order + df = df.sort_values(by="Sales Order") + + # Write to a specific sheet in the Excel file + df.to_excel(writer, sheet_name=customer, index=False) + for column in df: + column_length = max(df[column].astype(str).map(len).max(), len(column)) + col_idx = df.columns.get_loc(column) + if col_idx in [2,3,5]: + writer.sheets[customer].set_column(col_idx, col_idx, column_length, currency_format) + else: + writer.sheets[customer].set_column(col_idx, col_idx, column_length) + + # Get the dimensions of the dataframe. + (max_row, max_col) = df.shape + #Apply highlighting + writer.sheets[customer].conditional_format(f"G2:G{max_row+1}", {"type": "text", "criteria": "not containing", "value": "AP-bundled", "format": highlight_format}) + + #writer.sheets[customer].set_column(2,3,None,currency_format) + #manually adding extra calculated values + sales_formula = f"C2:C{max_row+1}" + platform_formula = f"D2:D{max_row+1}" + cellular_formula = f"F2:F{max_row+1}" + profit_formula = f"=B{max_row+3} - B{max_row+4} - B{max_row+5}" + writer.sheets[customer].write(f'A{max_row+3}', "Revenue", bold_format) + writer.sheets[customer].write(f'A{max_row+4}', "Platform Cost", bold_format) + writer.sheets[customer].write(f'A{max_row+5}', "Cellular Cost", bold_format) + writer.sheets[customer].write(f'A{max_row+6}', "Profit", bold_format) + writer.sheets[customer].write(f'B{max_row+3}', '=SUM(' + sales_formula + ')', bold_currency_format) + writer.sheets[customer].write(f'B{max_row+4}', '=SUM(' + platform_formula + ')', bold_currency_format) + writer.sheets[customer].write(f'B{max_row+5}', '=SUM(' + cellular_formula + ')', bold_currency_format) + writer.sheets[customer].write_formula(f'B{max_row+6}', profit_formula, bold_currency_format) + for ind,order in enumerate(counts): + writer.sheets[customer].write(f'A{max_row+8+ind}', order) + writer.sheets[customer].write(f'B{max_row+8+ind}', counts[order]) + overview.write(overview_row,0, customer) + overview.write(overview_row,1, f"='{customer}'!B{max_row+3}") + overview.write(overview_row,2, f"='{customer}'!B{max_row+4}") + overview.write(overview_row,3, f"='{customer}'!B{max_row+5}") + overview.write(overview_row,4, f"='{customer}'!B{max_row+6}") + overview_row += 1 + overview.write(overview_row,0, "Total", bold_format) + overview.write(overview_row,1, f"=SUM(B2:B{overview_row})", bold_currency_format) + overview.write(overview_row,2, f"=SUM(C2:C{overview_row})+399", bold_currency_format) + overview.write(overview_row,3, f"=SUM(D2:D{overview_row})", bold_currency_format) + overview.write(overview_row,4, f"=B{overview_row+1} - C{overview_row+1} - D{overview_row+1}", bold_currency_format) + + overview.set_column(0,4, 18) + + send_email() + +def send_email(): + attachment = MIMEBase('application', 'octet-stream') + attachment.set_payload(open(f"/tmp/Remote-Monitoring-Report-{dt.date(dt.now())}.xlsx", "rb").read()) + encoders.encode_base64(attachment) + msg = MIMEMultipart('alternative') + msg['Subject'] = f"Remote Monitoring Report - {dt.date(dt.now())}" + msg['From'] = "alerts@henry-pump.com" + msg['To'] = ", ".join(email_to) + + filename = f"Remote-Monitoring-{dt.date(dt.now())} .xlsx" + attachment.add_header('Content-Disposition', 'attachment', filename=filename) + + msg.attach(attachment) + response = ses.send_raw_email( + Source=EMAIL_FROM_ADDRESS, + Destinations=email_to, + RawMessage={ + 'Data': msg.as_string() + }, + FromArn='', + SourceArn='', + ReturnPathArn='' + ) + return response diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..686da03 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +click==8.1.3 +pandas==1.4.2 +Requests==2.31.0 +Shapely==2.0.1 +tb_rest_client==3.5 +xlsxwriter==3.1.2 diff --git a/thingsBoardData.py b/thingsBoardData.py new file mode 100644 index 0000000..9f489e4 --- /dev/null +++ b/thingsBoardData.py @@ -0,0 +1,130 @@ +#ThingsBoard data collection +from tb_rest_client.rest_client_ce import * +from tb_rest_client.rest import ApiException +import logging + +logger = logging.getLogger('billing_reports') +logger.setLevel(logging.INFO) +ch = logging.StreamHandler() +ch.setLevel(logging.INFO) +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +ch.setFormatter(formatter) +logger.addHandler(ch) + +def getDevices(rest_client, customers, page=0, pageSize=500): + thingsboard_data = {} + for c in customers.data: + cname = c.name + cid = c.id.id + if cname not in ["Test Company", "Amerus Safety Solutions"]: + #create new company if it doesn't exist + if cname not in thingsboard_data: + thingsboard_data[cname] = {} + #get devices of a company + devices = rest_client.get_customer_devices(customer_id=cid, page_size=pageSize, page=page) + #go through each device and store its data in the dict + for device in devices.data: + cellular_cost = 15 + #fix naming to work with JSON/dict + if '"' in device.name: + deviceName = device.name.replace('"', 'in') + else: + deviceName = device.name + # Sort Device details + if cname == "Chuda Resources": + so = "Water Wells" + price = 75 + billing_type = "Stand-Alone" + elif cname == "Henry Petroleum": + so = "Check Meters" + price = 50 + billing_type = "Stand-Alone" + elif cname == "Faskens": + if device.type == "tankalarms": + so = "Tanks" + billing_type = "Stand-Alone" + price = 50 + elif device.type in ["advvfdipp", "plcfreshwater"]: + so = "Water Wells" + billing_type = "Stand-Alone" + price = 50 + elif device.type == "plcpond": + so = "Ponds" + billing_type = "Stand-Alone" + price = 50 + else: + so = "HPSO-1" + billing_type = "Stand-Alone" + price = 50 + elif cname == "Henry Resources": + if deviceName == "Pearl Central": + so = "Henry Resources" + price = 300 + billing_type = "Stand-Alone-WiFi" + else: + so = "Henry Resources" + price = 275 + billing_type = "Stand-Alone" + elif cname == "ConocoPhillips": + if device.type == "flowmeterskid": + so = "Portable Meter" + price = 50 + billing_type = "Stand-Alone" + elif device.type == "plcfreshwater": + so = "Water Well" + price = 50 + cellular_cost = 0 + billing_type = "Networked" + elif device.type == "advvfdipp": + so = "Santa Rosa" + price = 50 + billing_type = "Stand-Alone" + elif device.type == "Gateway": + so = "AP" + price = 0 + billing_type = "AP-bundled" + elif device.type == "cpdualflowmeter": + so = "Pond/Flowmeter" + price = 50 + billing_type = "Networked" + elif cname == "Saulsbury Ventures": + so = "Saulsbury Ventures" + price = 50 + billing_type = "Stand-Alone" + else: + so = "HPSO-1" + price = 50 + billing_type = "Stand-Alone" + + #make a new Sales Order if it doesn't exist + if so not in thingsboard_data[cname]: + thingsboard_data[cname][so] = {} + #add device to Sales Order under Company + thingsboard_data[cname][so][deviceName] = { + "Sales Price": price, + "Platform Cost": 0, + "Platform": "ThingsBoard", # "thingsboard", "mistaway" + "Cellular Cost": cellular_cost, + "Billing Type": billing_type # "stand-alone", "AP", "AP-bundled", "networked", "stand-alone-wifi" + } + return thingsboard_data + + +def getThingsBoardData(url, username, password): + # Creating the REST client object with context manager to get auto token refresh + with RestClientCE(base_url=url) as rest_client: + try: + # Auth with credentials + rest_client.login(username=username, password=password) + # Get customers > get devices under a target customer > get keys for devices > get data for devices + customers = rest_client.get_customers(page_size="100", page="0") + thingsboard_data = getDevices(rest_client=rest_client, customers=customers) + return thingsboard_data + except ApiException as e: + logger.error(e) + return False + + + + +