From 314abe0462fce7b687252bc3e5518ede1794ec34 Mon Sep 17 00:00:00 2001 From: Nedim Date: Fri, 6 Oct 2023 10:47:26 +0200 Subject: [PATCH] Added create contact ednpoint --- NOVA.postman_collection.json | 792 ++++++++++++++++++++++++++++ controllers/contracts_controller.go | 80 +-- controllers/devices_controller.go | 2 +- controllers/invoices_controller.go | 4 +- database/contract/contract.go | 10 +- database/device/device.go | 5 +- database/invoice/invoice.go | 6 +- models/company.go | 27 +- models/contract.go | 179 ++++++- models/device.go | 50 +- models/device_info.go | 61 ++- models/invoice.go | 132 +++-- models/invoice_item.go | 52 +- models/user.go | 21 +- routes/public_routes.go | 3 +- 15 files changed, 1278 insertions(+), 146 deletions(-) create mode 100644 NOVA.postman_collection.json diff --git a/NOVA.postman_collection.json b/NOVA.postman_collection.json new file mode 100644 index 0000000..4f6a834 --- /dev/null +++ b/NOVA.postman_collection.json @@ -0,0 +1,792 @@ +{ + "info": { + "_postman_id": "bce30528-f06b-4c85-9354-89f5e25063a4", + "name": "NOVA", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Get devices", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/dashboard/map/contract/devices?contract_id=1", + "host": [ + "{{URL}}" + ], + "path": [ + "dashboard", + "map", + "contract", + "devices" + ], + "query": [ + { + "key": "contract_id", + "value": "1" + } + ] + } + }, + "response": [ + { + "name": "Get devices", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/dashboard/map/contract/devices?contract_id=1", + "host": [ + "{{URL}}" + ], + "path": [ + "dashboard", + "map", + "contract", + "devices" + ], + "query": [ + { + "key": "contract_id", + "value": "1" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Mon, 09 Oct 2023 06:09:21 GMT" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + } + ], + "cookie": [], + "body": "{\n \"data\": [\n {\n \"id\": 5,\n \"createdAt\": \"2023-09-19T07:59:21.142717+02:00\",\n \"updatedAt\": \"2023-09-19T07:59:21.142717+02:00\",\n \"deviceId\": \"9c51ef10-bf79-4556-8767-1de4bdda0834\",\n \"deviceName\": \"\",\n \"imei\": \"352656107000000\",\n \"imsi\": \"232031721000000\",\n \"deviceConfiguration\": \"{\\n\\\"imei\\\": \\\"352656107000000\\\",\\n\\\"imsi\\\": \\\"232031721000000\\\",\\n\\\"timestamp\\\": 1643200311304,\\n\\\"epoch\\\": 1643200311304,\\n\\\"packetVersion\\\": 1,\\n\\\"hardwareVersion\\\": \\\"2.3\\\",\\n\\\"softwareVersion\\\": \\\"0.9.0\\\",\\n\\\"lat\\\": 34.232237643,\\n\\\"lon\\\": 7.9934428597,\\n\\\"wifiLat\\\": 34.232237643,\\n\\\"wifiLon\\\": 7.9934428597,\\n\\\"cellLat\\\": 34.232237643,\\n\\\"cellLon\\\": 7.9934428597,\\n\\\"provider\\\": \\\"tm_prv_sdq\\\",\\n\\\"mcc\\\": 204,\\n\\\"mnc\\\": 4,\\n\\\"rat\\\": 9,\\n\\\"band\\\": 20,\\n\\\"earfcn\\\": 6254,\\n\\\"tac\\\": 10113,\\n\\\"cellId\\\": 27454823,\\n\\\"physicalId\\\": 389,\\n\\\"rsrp\\\": 24,\\n\\\"rsrq\\\": 25,\\n\\\"snr\\\": 31,\\n\\\"ceLevel\\\": 0,\\n\\\"location\\\": {\\n\\\"type\\\": \\\"Point\\\",\\n\\\"coordinates\\\": [34.232237643, 7.9934428597],\\n\\\"crs\\\": {\\n\\\"type\\\": \\\"name\\\",\\n\\\"properties\\\": {\\n\\\"name\\\": \\\"EPSG:4326\\\"\\n}\\n}\\n},\\n\\\"gpsData\\\": {\\n\\\"timestamp\\\": 1643201553,\\n\\\"timeToFix\\\": 0,\\n\\\"latitude\\\": 34.232237643,\\n\\\"longitude\\\": 7.9934428597,\\n\\\"altitude\\\": 142.8,\\n\\\"numberOfSats\\\": 4,\\n\\\"estimatedAccuracy\\\": 28.68,\\n\\\"pdop\\\": 6.29\\n},\\n\\\"wifiRecords\\\": {\\n\\\"timestamp\\\": 1643200308,\\n\\\"record\\\": [{\\n\\\"macAddress\\\": \\\"00:01:02:03:04:05\\\",\\n\\\"rssi\\\": 54\\n}, {\\n\\\"macAddress\\\": \\\"00:01:02:03:04:05\\\",\\n\\\"rssi\\\": 55\\n}, {\\n\\\"macAddress\\\": \\\"00:01:02:03:04:05\\\",\\n\\\"rssi\\\": 56\\n}, {\\n\\\"macAddress\\\": \\\"00:01:02:03:04:05\\\",\\n\\\"rssi\\\": 57\\n}],\\n\\\"latitude\\\": 72.23184167,\\n\\\"longitude\\\": 7.9847866\\n},\\n\\\"cellInfo\\\": {\\n\\\"timestamp\\\": 1643200305,\\n\\\"mcc\\\": 204,\\n\\\"mnc\\\": 4,\\n\\\"rat\\\": 9,\\n\\\"band\\\": 20,\\n\\\"earfcn\\\": 6254,\\n\\\"cellTac\\\": 10113,\\n\\\"cellId\\\": 27454823,\\n\\\"physicalId\\\": 389,\\n\\\"rsrp\\\": 24,\\n\\\"rsrq\\\": 25,\\n\\\"snr\\\": 31,\\n\\\"ceLevel\\\": 0,\\n\\\"psmXTauInfo\\\": 480,\\n\\\"psmDTauInfo\\\": 3240,\\n\\\"latitude\\\": 34.232237643,\\n\\\"longitude\\\": 7.9934428597\\n},\\n\\\"mode\\\": \\\"Moving\\\",\\n\\\"locationMethod\\\": \\\"w\\\",\\n\\\"ip\\\": \\\"10.196.152.105\\\",\\n\\\"port\\\": 2397,\\n\\\"stateInfo\\\": {\\n\\\"flightMode\\\": true,\\n\\\"motionTrigger\\\": true,\\n\\\"messageDoubling\\\": true,\\n\\\"t2Max\\\": 604800,\\n\\\"backOffTime\\\": 1800,\\n\\\"baseIdleTime\\\": 86400,\\n\\\"fmBackOffTime\\\": 15,\\n\\\"fmIdleTime\\\": 60,\\n\\\"idleSensitivity\\\": 200,\\n\\\"fmIdleSensitivity\\\": 50,\\n\\\"positionTypeActive\\\": 3,\\n\\\"positionTypeIdle\\\": 3\\n},\\n\\\"batteryMv\\\": 3720,\\n\\\"temperatureData\\\": {\\n\\\"timestamp\\\": 1643200305,\\n\\\"temperatureInCelsius\\\": -2\\n},\\n\\\"temperature\\\": -2,\\n\\\"deviceStatus\\\": {},\\n\\\"trigger\\\": 4,\\n\\\"triggerName\\\": \\\"Motion Stop\\\",\\n\\n\\\"cbor\\\":\\\"aa6170a361741a61f13ce761631901ac6172046176a3617001626877820203627377830009006164a461651b000140bd25ff96e461731b0000d3081858e3076163743839343\\\",\\n\\\"statsInfo\\\": {\\n\\\"timestamp\\\": 1643200305,\\n\\\"modemOnTime\\\": 4916,\\n\\\"gpsOnTime\\\": 61388,\\n\\\"deviceUpTime\\\": 8555520,\\n\\\"resetCause\\\": 144\\n},\\n\\\"accelerometerInfo\\\": {\\n\\\"timestamp\\\": 1643200309,\\n\\\"numberOfSamples\\\": 10,\\n\\\"samplingDuration\\\": 3792,\\n\\\"X\\\": -937,\\n\\\"Y\\\": -4,\\n\\\"Z\\\": 0\\n},\\n\\\"counter\\\": 428,\\n\\\"deviceId\\\": \\\"9c51ef10-bf79-4556-8767-1de4bdda0834\\\"\\n}\",\n \"companyId\": 1,\n \"deviceInfos\": []\n },\n {\n \"id\": 6,\n \"createdAt\": \"2023-09-19T17:14:59.401891+02:00\",\n \"updatedAt\": \"2023-09-19T17:14:59.401891+02:00\",\n \"deviceId\": \"9c51ef10-bf79-4556-8767-1de4bdda0835\",\n \"deviceName\": \"\",\n \"imei\": \"352656107000000\",\n \"imsi\": \"232031721000000\",\n \"deviceConfiguration\": \"{\\n\\\"imei\\\": \\\"352656107000000\\\",\\n\\\"imsi\\\": \\\"232031721000000\\\",\\n\\\"timestamp\\\": 1643200311304,\\n\\\"epoch\\\": 1643200311304,\\n\\\"packetVersion\\\": 1,\\n\\\"hardwareVersion\\\": \\\"2.3\\\",\\n\\\"softwareVersion\\\": \\\"0.9.0\\\",\\n\\\"lat\\\": 34.232237643,\\n\\\"lon\\\": 7.9934428597,\\n\\\"wifiLat\\\": 34.232237643,\\n\\\"wifiLon\\\": 7.9934428597,\\n\\\"cellLat\\\": 34.232237643,\\n\\\"cellLon\\\": 7.9934428597,\\n\\\"provider\\\": \\\"tm_prv_sdq\\\",\\n\\\"mcc\\\": 204,\\n\\\"mnc\\\": 4,\\n\\\"rat\\\": 9,\\n\\\"band\\\": 20,\\n\\\"earfcn\\\": 6254,\\n\\\"tac\\\": 10113,\\n\\\"cellId\\\": 27454823,\\n\\\"physicalId\\\": 389,\\n\\\"rsrp\\\": 24,\\n\\\"rsrq\\\": 25,\\n\\\"snr\\\": 31,\\n\\\"ceLevel\\\": 0,\\n\\\"location\\\": {\\n\\\"type\\\": \\\"Point\\\",\\n\\\"coordinates\\\": [34.232237643, 7.9934428597],\\n\\\"crs\\\": {\\n\\\"type\\\": \\\"name\\\",\\n\\\"properties\\\": {\\n\\\"name\\\": \\\"EPSG:4326\\\"\\n}\\n}\\n},\\n\\\"gpsData\\\": {\\n\\\"timestamp\\\": 1643201553,\\n\\\"timeToFix\\\": 0,\\n\\\"latitude\\\": 34.232237643,\\n\\\"longitude\\\": 7.9934428597,\\n\\\"altitude\\\": 142.8,\\n\\\"numberOfSats\\\": 4,\\n\\\"estimatedAccuracy\\\": 28.68,\\n\\\"pdop\\\": 6.29\\n},\\n\\\"wifiRecords\\\": {\\n\\\"timestamp\\\": 1643200308,\\n\\\"record\\\": [{\\n\\\"macAddress\\\": \\\"00:01:02:03:04:05\\\",\\n\\\"rssi\\\": 54\\n}, {\\n\\\"macAddress\\\": \\\"00:01:02:03:04:05\\\",\\n\\\"rssi\\\": 55\\n}, {\\n\\\"macAddress\\\": \\\"00:01:02:03:04:05\\\",\\n\\\"rssi\\\": 56\\n}, {\\n\\\"macAddress\\\": \\\"00:01:02:03:04:05\\\",\\n\\\"rssi\\\": 57\\n}],\\n\\\"latitude\\\": 72.23184167,\\n\\\"longitude\\\": 7.9847866\\n},\\n\\\"cellInfo\\\": {\\n\\\"timestamp\\\": 1643200305,\\n\\\"mcc\\\": 204,\\n\\\"mnc\\\": 4,\\n\\\"rat\\\": 9,\\n\\\"band\\\": 20,\\n\\\"earfcn\\\": 6254,\\n\\\"cellTac\\\": 10113,\\n\\\"cellId\\\": 27454823,\\n\\\"physicalId\\\": 389,\\n\\\"rsrp\\\": 24,\\n\\\"rsrq\\\": 25,\\n\\\"snr\\\": 31,\\n\\\"ceLevel\\\": 0,\\n\\\"psmXTauInfo\\\": 480,\\n\\\"psmDTauInfo\\\": 3240,\\n\\\"latitude\\\": 34.232237643,\\n\\\"longitude\\\": 7.9934428597\\n},\\n\\\"mode\\\": \\\"Moving\\\",\\n\\\"locationMethod\\\": \\\"w\\\",\\n\\\"ip\\\": \\\"10.196.152.105\\\",\\n\\\"port\\\": 2397,\\n\\\"stateInfo\\\": {\\n\\\"flightMode\\\": true,\\n\\\"motionTrigger\\\": true,\\n\\\"messageDoubling\\\": true,\\n\\\"t2Max\\\": 604800,\\n\\\"backOffTime\\\": 1800,\\n\\\"baseIdleTime\\\": 86400,\\n\\\"fmBackOffTime\\\": 15,\\n\\\"fmIdleTime\\\": 60,\\n\\\"idleSensitivity\\\": 200,\\n\\\"fmIdleSensitivity\\\": 50,\\n\\\"positionTypeActive\\\": 3,\\n\\\"positionTypeIdle\\\": 3\\n},\\n\\\"batteryMv\\\": 3720,\\n\\\"temperatureData\\\": {\\n\\\"timestamp\\\": 1643200305,\\n\\\"temperatureInCelsius\\\": -2\\n},\\n\\\"temperature\\\": -2,\\n\\\"deviceStatus\\\": {},\\n\\\"trigger\\\": 4,\\n\\\"triggerName\\\": \\\"Motion Stop\\\",\\n\\n\\\"cbor\\\":\\\"aa6170a361741a61f13ce761631901ac6172046176a3617001626877820203627377830009006164a461651b000140bd25ff96e461731b0000d3081858e3076163743839343\\\",\\n\\\"statsInfo\\\": {\\n\\\"timestamp\\\": 1643200305,\\n\\\"modemOnTime\\\": 4916,\\n\\\"gpsOnTime\\\": 61388,\\n\\\"deviceUpTime\\\": 8555520,\\n\\\"resetCause\\\": 144\\n},\\n\\\"accelerometerInfo\\\": {\\n\\\"timestamp\\\": 1643200309,\\n\\\"numberOfSamples\\\": 10,\\n\\\"samplingDuration\\\": 3792,\\n\\\"X\\\": -937,\\n\\\"Y\\\": -4,\\n\\\"Z\\\": 0\\n},\\n\\\"counter\\\": 428,\\n\\\"deviceId\\\": \\\"9c51ef10-bf79-4556-8767-1de4bdda0835\\\"\\n}\",\n \"companyId\": 1,\n \"deviceInfos\": []\n },\n {\n \"id\": 7,\n \"createdAt\": \"2023-09-19T17:15:04.531334+02:00\",\n \"updatedAt\": \"2023-09-19T17:15:04.531334+02:00\",\n \"deviceId\": \"9c51ef10-bf79-4556-8767-1de4bdda0836\",\n \"deviceName\": \"\",\n \"imei\": \"352656107000000\",\n \"imsi\": \"232031721000000\",\n \"deviceConfiguration\": \"{\\n\\\"imei\\\": \\\"352656107000000\\\",\\n\\\"imsi\\\": \\\"232031721000000\\\",\\n\\\"timestamp\\\": 1643200311304,\\n\\\"epoch\\\": 1643200311304,\\n\\\"packetVersion\\\": 1,\\n\\\"hardwareVersion\\\": \\\"2.3\\\",\\n\\\"softwareVersion\\\": \\\"0.9.0\\\",\\n\\\"lat\\\": 34.232237643,\\n\\\"lon\\\": 7.9934428597,\\n\\\"wifiLat\\\": 34.232237643,\\n\\\"wifiLon\\\": 7.9934428597,\\n\\\"cellLat\\\": 34.232237643,\\n\\\"cellLon\\\": 7.9934428597,\\n\\\"provider\\\": \\\"tm_prv_sdq\\\",\\n\\\"mcc\\\": 204,\\n\\\"mnc\\\": 4,\\n\\\"rat\\\": 9,\\n\\\"band\\\": 20,\\n\\\"earfcn\\\": 6254,\\n\\\"tac\\\": 10113,\\n\\\"cellId\\\": 27454823,\\n\\\"physicalId\\\": 389,\\n\\\"rsrp\\\": 24,\\n\\\"rsrq\\\": 25,\\n\\\"snr\\\": 31,\\n\\\"ceLevel\\\": 0,\\n\\\"location\\\": {\\n\\\"type\\\": \\\"Point\\\",\\n\\\"coordinates\\\": [34.232237643, 7.9934428597],\\n\\\"crs\\\": {\\n\\\"type\\\": \\\"name\\\",\\n\\\"properties\\\": {\\n\\\"name\\\": \\\"EPSG:4326\\\"\\n}\\n}\\n},\\n\\\"gpsData\\\": {\\n\\\"timestamp\\\": 1643201553,\\n\\\"timeToFix\\\": 0,\\n\\\"latitude\\\": 34.232237643,\\n\\\"longitude\\\": 7.9934428597,\\n\\\"altitude\\\": 142.8,\\n\\\"numberOfSats\\\": 4,\\n\\\"estimatedAccuracy\\\": 28.68,\\n\\\"pdop\\\": 6.29\\n},\\n\\\"wifiRecords\\\": {\\n\\\"timestamp\\\": 1643200308,\\n\\\"record\\\": [{\\n\\\"macAddress\\\": \\\"00:01:02:03:04:05\\\",\\n\\\"rssi\\\": 54\\n}, {\\n\\\"macAddress\\\": \\\"00:01:02:03:04:05\\\",\\n\\\"rssi\\\": 55\\n}, {\\n\\\"macAddress\\\": \\\"00:01:02:03:04:05\\\",\\n\\\"rssi\\\": 56\\n}, {\\n\\\"macAddress\\\": \\\"00:01:02:03:04:05\\\",\\n\\\"rssi\\\": 57\\n}],\\n\\\"latitude\\\": 72.23184167,\\n\\\"longitude\\\": 7.9847866\\n},\\n\\\"cellInfo\\\": {\\n\\\"timestamp\\\": 1643200305,\\n\\\"mcc\\\": 204,\\n\\\"mnc\\\": 4,\\n\\\"rat\\\": 9,\\n\\\"band\\\": 20,\\n\\\"earfcn\\\": 6254,\\n\\\"cellTac\\\": 10113,\\n\\\"cellId\\\": 27454823,\\n\\\"physicalId\\\": 389,\\n\\\"rsrp\\\": 24,\\n\\\"rsrq\\\": 25,\\n\\\"snr\\\": 31,\\n\\\"ceLevel\\\": 0,\\n\\\"psmXTauInfo\\\": 480,\\n\\\"psmDTauInfo\\\": 3240,\\n\\\"latitude\\\": 34.232237643,\\n\\\"longitude\\\": 7.9934428597\\n},\\n\\\"mode\\\": \\\"Moving\\\",\\n\\\"locationMethod\\\": \\\"w\\\",\\n\\\"ip\\\": \\\"10.196.152.105\\\",\\n\\\"port\\\": 2397,\\n\\\"stateInfo\\\": {\\n\\\"flightMode\\\": true,\\n\\\"motionTrigger\\\": true,\\n\\\"messageDoubling\\\": true,\\n\\\"t2Max\\\": 604800,\\n\\\"backOffTime\\\": 1800,\\n\\\"baseIdleTime\\\": 86400,\\n\\\"fmBackOffTime\\\": 15,\\n\\\"fmIdleTime\\\": 60,\\n\\\"idleSensitivity\\\": 200,\\n\\\"fmIdleSensitivity\\\": 50,\\n\\\"positionTypeActive\\\": 3,\\n\\\"positionTypeIdle\\\": 3\\n},\\n\\\"batteryMv\\\": 3720,\\n\\\"temperatureData\\\": {\\n\\\"timestamp\\\": 1643200305,\\n\\\"temperatureInCelsius\\\": -2\\n},\\n\\\"temperature\\\": -2,\\n\\\"deviceStatus\\\": {},\\n\\\"trigger\\\": 4,\\n\\\"triggerName\\\": \\\"Motion Stop\\\",\\n\\n\\\"cbor\\\":\\\"aa6170a361741a61f13ce761631901ac6172046176a3617001626877820203627377830009006164a461651b000140bd25ff96e461731b0000d3081858e3076163743839343\\\",\\n\\\"statsInfo\\\": {\\n\\\"timestamp\\\": 1643200305,\\n\\\"modemOnTime\\\": 4916,\\n\\\"gpsOnTime\\\": 61388,\\n\\\"deviceUpTime\\\": 8555520,\\n\\\"resetCause\\\": 144\\n},\\n\\\"accelerometerInfo\\\": {\\n\\\"timestamp\\\": 1643200309,\\n\\\"numberOfSamples\\\": 10,\\n\\\"samplingDuration\\\": 3792,\\n\\\"X\\\": -937,\\n\\\"Y\\\": -4,\\n\\\"Z\\\": 0\\n},\\n\\\"counter\\\": 428,\\n\\\"deviceId\\\": \\\"9c51ef10-bf79-4556-8767-1de4bdda0836\\\"\\n}\",\n \"companyId\": 1,\n \"deviceInfos\": []\n }\n ]\n}" + } + ] + }, + { + "name": "Get Dashboar Map Contracts", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/dashboard/map/contracts?offset=0&limit=20&status=active", + "host": [ + "{{URL}}" + ], + "path": [ + "dashboard", + "map", + "contracts" + ], + "query": [ + { + "key": "offset", + "value": "0" + }, + { + "key": "limit", + "value": "20" + }, + { + "key": "status", + "value": "active" + } + ] + } + }, + "response": [ + { + "name": "Get Dashboar Map Contracts", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/dashboard/map/contracts?offset=0&limit=20&status=active", + "host": [ + "{{URL}}" + ], + "path": [ + "dashboard", + "map", + "contracts" + ], + "query": [ + { + "key": "offset", + "value": "0" + }, + { + "key": "limit", + "value": "20" + }, + { + "key": "status", + "value": "active" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Fri, 06 Oct 2023 08:27:27 GMT" + }, + { + "key": "Content-Length", + "value": "1691" + } + ], + "cookie": [], + "body": "{\n \"data\": [\n {\n \"id\": 1,\n \"createdAt\": \"2023-09-13T08:36:41.742294+02:00\",\n \"updatedAt\": \"2023-09-13T08:36:41.742294+02:00\",\n \"name\": \"Contract1\",\n \"deviceIds\": [\n 5,\n 6,\n 7\n ],\n \"buyerId\": 1,\n \"sellerId\": 0,\n \"description\": \"\",\n \"startLat\": 0,\n \"startLon\": 0,\n \"endLat\": 0,\n \"endLon\": 0,\n \"startTime\": \"2023-09-13T08:36:41.742294+02:00\",\n \"endTime\": \"2023-09-20T08:36:41.742294+02:00\",\n \"status\": \"active\",\n \"blockchainId\": \"12\",\n \"contractInfos\": null,\n \"productId\": 0,\n \"maxTemp\": 0,\n \"minTemp\": 0,\n \"arrivalDate\": \"0001-01-01T00:00:00Z\",\n \"penaltyType\": \"\",\n \"penaltyValue\": 0,\n \"penaltyRec\": \"\",\n \"buyerName\": \"Nova kompanija\",\n \"numberOfDevices\": 3\n },\n {\n \"id\": 3,\n \"createdAt\": \"2023-09-13T08:36:41.742294+02:00\",\n \"updatedAt\": \"2023-09-13T08:36:41.742294+02:00\",\n \"name\": \"Contract2\",\n \"deviceIds\": [\n 1,\n 2,\n 3,\n 4\n ],\n \"buyerId\": 1,\n \"sellerId\": 0,\n \"description\": \"\",\n \"startLat\": 0,\n \"startLon\": 0,\n \"endLat\": 0,\n \"endLon\": 0,\n \"startTime\": \"2023-09-13T08:36:41.742294+02:00\",\n \"endTime\": \"2023-11-20T07:36:41.742294+01:00\",\n \"status\": \"active\",\n \"blockchainId\": \"\",\n \"contractInfos\": null,\n \"productId\": 0,\n \"maxTemp\": 0,\n \"minTemp\": 0,\n \"arrivalDate\": \"0001-01-01T00:00:00Z\",\n \"penaltyType\": \"\",\n \"penaltyValue\": 0,\n \"penaltyRec\": \"\",\n \"buyerName\": \"Nova kompanija\",\n \"numberOfDevices\": 4\n },\n {\n \"id\": 4,\n \"createdAt\": \"2023-09-13T08:36:41.742294+02:00\",\n \"updatedAt\": \"2023-09-13T08:36:41.742294+02:00\",\n \"name\": \"Contract2\",\n \"deviceIds\": [\n 1,\n 2,\n 3,\n 4\n ],\n \"buyerId\": 1,\n \"sellerId\": 0,\n \"description\": \"\",\n \"startLat\": 0,\n \"startLon\": 0,\n \"endLat\": 0,\n \"endLon\": 0,\n \"startTime\": \"2023-09-13T08:36:41.742294+02:00\",\n \"endTime\": \"2023-11-20T07:36:41.742294+01:00\",\n \"status\": \"active\",\n \"blockchainId\": \"\",\n \"contractInfos\": null,\n \"productId\": 0,\n \"maxTemp\": 0,\n \"minTemp\": 0,\n \"arrivalDate\": \"0001-01-01T00:00:00Z\",\n \"penaltyType\": \"\",\n \"penaltyValue\": 0,\n \"penaltyRec\": \"\",\n \"buyerName\": \"Nova kompanija\",\n \"numberOfDevices\": 4\n }\n ],\n \"total\": 3\n}" + } + ] + }, + { + "name": "Get Contracts for Buyers", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/contracts", + "host": [ + "{{URL}}" + ], + "path": [ + "contracts" + ] + } + }, + "response": [ + { + "name": "Get Contracts for Buyers", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/contracts", + "host": [ + "{{URL}}" + ], + "path": [ + "contracts" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Fri, 06 Oct 2023 08:27:52 GMT" + }, + { + "key": "Content-Length", + "value": "1056" + } + ], + "cookie": [], + "body": "{\n \"data\": [\n {\n \"status\": {\n \"key\": \"Unknown\",\n \"value\": \"unknown\"\n },\n \"buyer\": {\n \"id\": 2,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 7,\n \"numberOfDevices\": 0,\n \"dateCreated\": \"2023-10-06T08:36:23.752245+02:00\"\n },\n {\n \"status\": {\n \"key\": \"Unknown\",\n \"value\": \"unknown\"\n },\n \"buyer\": {\n \"id\": 2,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 6,\n \"numberOfDevices\": 0,\n \"dateCreated\": \"2023-10-06T08:25:40.488392+02:00\"\n },\n {\n \"status\": {\n \"key\": \"Active\",\n \"value\": \"active\"\n },\n \"buyer\": {\n \"id\": 1,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 1,\n \"numberOfDevices\": 3,\n \"dateCreated\": \"2023-09-13T08:36:41.742294+02:00\"\n },\n {\n \"status\": {\n \"key\": \"Pending signature\",\n \"value\": \"pending\"\n },\n \"buyer\": {\n \"id\": 1,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 2,\n \"numberOfDevices\": 1,\n \"dateCreated\": \"2023-09-13T08:36:41.742294+02:00\"\n },\n {\n \"status\": {\n \"key\": \"Active\",\n \"value\": \"active\"\n },\n \"buyer\": {\n \"id\": 1,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 3,\n \"numberOfDevices\": 4,\n \"dateCreated\": \"2023-09-13T08:36:41.742294+02:00\"\n },\n {\n \"status\": {\n \"key\": \"Active\",\n \"value\": \"active\"\n },\n \"buyer\": {\n \"id\": 1,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 4,\n \"numberOfDevices\": 4,\n \"dateCreated\": \"2023-09-13T08:36:41.742294+02:00\"\n }\n ],\n \"total\": 6\n}" + } + ] + }, + { + "name": "GetContractStatuses", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/contracts/statuses", + "host": [ + "{{URL}}" + ], + "path": [ + "contracts", + "statuses" + ] + } + }, + "response": [ + { + "name": "GetContractStatuses", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/contracts/statuses", + "host": [ + "{{URL}}" + ], + "path": [ + "contracts", + "statuses" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Fri, 06 Oct 2023 08:28:42 GMT" + }, + { + "key": "Content-Length", + "value": "292" + } + ], + "cookie": [], + "body": "{\n \"data\": [\n {\n \"key\": \"active\",\n \"value\": \"Active\"\n },\n {\n \"key\": \"pending\",\n \"value\": \"Pending signature\"\n },\n {\n \"key\": \"draft\",\n \"value\": \"Draft\"\n },\n {\n \"key\": \"signed\",\n \"value\": \"Signed\"\n },\n {\n \"key\": \"ready_for_activation\",\n \"value\": \"Ready for Activation\"\n },\n {\n \"key\": \"executed\",\n \"value\": \"Executed\"\n },\n {\n \"key\": \"revoked\",\n \"value\": \"Revoked\"\n }\n ]\n}" + } + ] + }, + { + "name": "Get device info", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/dashboard/map/device_data?device_id=5&contract_id=1", + "host": [ + "{{URL}}" + ], + "path": [ + "dashboard", + "map", + "device_data" + ], + "query": [ + { + "key": "device_id", + "value": "5" + }, + { + "key": "contract_id", + "value": "1" + } + ] + } + }, + "response": [ + { + "name": "Get device info", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/dashboard/map/device_data?device_id=5&contract_id=1", + "host": [ + "{{URL}}" + ], + "path": [ + "dashboard", + "map", + "device_data" + ], + "query": [ + { + "key": "device_id", + "value": "5" + }, + { + "key": "contract_id", + "value": "1" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Fri, 06 Oct 2023 08:39:46 GMT" + }, + { + "key": "Content-Length", + "value": "1745" + } + ], + "cookie": [], + "body": "{\n \"data\": {\n \"type\": \"FeatureCollection\",\n \"features\": [\n {\n \"type\": \"Feature\",\n \"geometry\": {\n \"type\": \"Point\",\n \"coordinates\": [\n 7.9934428597,\n 34.232237643\n ]\n },\n \"deviceInfo\": {\n \"id\": 51,\n \"createdAt\": \"2023-09-19T08:19:01.689368+02:00\",\n \"updatedAt\": \"2023-09-19T08:19:01.689368+02:00\",\n \"rawJson\": \"\",\n \"imei\": \"352656107000000\",\n \"imsi\": \"232031721000000\",\n \"timestamp\": 1643200311304,\n \"lat\": 34.232237643,\n \"lon\": 7.9934428597,\n \"wifiLocation\": {\n \"lat\": 0,\n \"lon\": 0\n },\n \"cellLocation\": {\n \"lat\": 0,\n \"lon\": 0\n },\n \"temperature\": -2,\n \"accelerometerInfo\": {\n \"x\": 0,\n \"y\": 0,\n \"z\": 0\n },\n \"x\": -937,\n \"y\": -4,\n \"z\": 0,\n \"deviceId\": 5,\n \"externalDeviceId\": \"9c51ef10-bf79-4556-8767-1de4bdda0834\"\n },\n \"properties\": {}\n },\n {\n \"type\": \"Feature\",\n \"geometry\": {\n \"type\": \"Point\",\n \"coordinates\": [\n 7.9934428597,\n 34.232237643\n ]\n },\n \"deviceInfo\": {\n \"id\": 51,\n \"createdAt\": \"2023-09-19T08:19:01.689368+02:00\",\n \"updatedAt\": \"2023-09-19T08:19:01.689368+02:00\",\n \"rawJson\": \"\",\n \"imei\": \"352656107000000\",\n \"imsi\": \"232031721000000\",\n \"timestamp\": 1643200311304,\n \"lat\": 34.232237643,\n \"lon\": 7.9934428597,\n \"wifiLocation\": {\n \"lat\": 0,\n \"lon\": 0\n },\n \"cellLocation\": {\n \"lat\": 0,\n \"lon\": 0\n },\n \"temperature\": -2,\n \"accelerometerInfo\": {\n \"x\": 0,\n \"y\": 0,\n \"z\": 0\n },\n \"x\": -937,\n \"y\": -4,\n \"z\": 0,\n \"deviceId\": 5,\n \"externalDeviceId\": \"9c51ef10-bf79-4556-8767-1de4bdda0834\"\n },\n \"properties\": {}\n },\n {\n \"type\": \"Feature\",\n \"geometry\": {\n \"type\": \"Point\",\n \"coordinates\": [\n 7.9934428597,\n 34.232237643\n ]\n },\n \"deviceInfo\": {\n \"id\": 51,\n \"createdAt\": \"2023-09-19T08:19:01.689368+02:00\",\n \"updatedAt\": \"2023-09-19T08:19:01.689368+02:00\",\n \"rawJson\": \"\",\n \"imei\": \"352656107000000\",\n \"imsi\": \"232031721000000\",\n \"timestamp\": 1643200311304,\n \"lat\": 34.232237643,\n \"lon\": 7.9934428597,\n \"wifiLocation\": {\n \"lat\": 0,\n \"lon\": 0\n },\n \"cellLocation\": {\n \"lat\": 0,\n \"lon\": 0\n },\n \"temperature\": -2,\n \"accelerometerInfo\": {\n \"x\": 0,\n \"y\": 0,\n \"z\": 0\n },\n \"x\": -937,\n \"y\": -4,\n \"z\": 0,\n \"deviceId\": 5,\n \"externalDeviceId\": \"9c51ef10-bf79-4556-8767-1de4bdda0834\"\n },\n \"properties\": {}\n }\n ]\n }\n}" + } + ] + }, + { + "name": "Get Invoices", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/invoices?limit=5&offset=0&sort_by=invoice_date&sort_order=desc&buyer_name=Some", + "host": [ + "{{URL}}" + ], + "path": [ + "invoices" + ], + "query": [ + { + "key": "limit", + "value": "5" + }, + { + "key": "offset", + "value": "0" + }, + { + "key": "sort_by", + "value": "invoice_date" + }, + { + "key": "sort_order", + "value": "desc" + }, + { + "key": "buyer_name", + "value": "Some" + } + ] + } + }, + "response": [ + { + "name": "Get Invoices", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/invoices?limit=5&offset=0&sort_by=invoice_date&sort_order=desc&buyer_name=Some", + "host": [ + "{{URL}}" + ], + "path": [ + "invoices" + ], + "query": [ + { + "key": "limit", + "value": "5" + }, + { + "key": "offset", + "value": "0" + }, + { + "key": "sort_by", + "value": "invoice_date" + }, + { + "key": "sort_order", + "value": "desc" + }, + { + "key": "buyer_name", + "value": "Some" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Fri, 06 Oct 2023 08:39:58 GMT" + }, + { + "key": "Content-Length", + "value": "446" + } + ], + "cookie": [], + "body": "{\n \"data\": [\n {\n \"status\": {\n \"key\": \"Invoice issued\",\n \"value\": \"invoice_issued\"\n },\n \"buyer\": {\n \"id\": 1,\n \"name\": \"Some Buyer\"\n },\n \"contractId\": 1,\n \"dateCreated\": \"2023-09-13T08:36:41.742294+02:00\",\n \"dueDate\": \"2023-09-13T08:36:41.742294+02:00\",\n \"amount\": \"0\"\n },\n {\n \"status\": {\n \"key\": \"Unknown\",\n \"value\": \"unknown\"\n },\n \"buyer\": {\n \"id\": 1,\n \"name\": \"Some Buyer\"\n },\n \"contractId\": 3,\n \"dateCreated\": \"2023-09-13T08:36:41.742294+02:00\",\n \"dueDate\": \"2023-09-13T08:36:41.742294+02:00\",\n \"amount\": \"0\"\n }\n ],\n \"total\": 2\n}" + } + ] + }, + { + "name": "Get Invoice details", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/invoice/1", + "host": [ + "{{URL}}" + ], + "path": [ + "invoice", + "1" + ] + } + }, + "response": [ + { + "name": "Get Invoice details", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/invoice/1", + "host": [ + "{{URL}}" + ], + "path": [ + "invoice", + "1" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Fri, 06 Oct 2023 08:40:02 GMT" + }, + { + "key": "Content-Length", + "value": "589" + } + ], + "cookie": [], + "body": "{\n \"data\": {\n \"id\": 0,\n \"createdAt\": \"0001-01-01T00:00:00Z\",\n \"updatedAt\": \"0001-01-01T00:00:00Z\",\n \"deletedAt\": {\n \"Time\": \"0001-01-01T00:00:00Z\",\n \"Valid\": false\n },\n \"buyerId\": 1,\n \"buyerName\": \"Some Buyer\",\n \"buyerAddress\": \"\",\n \"buyerEmail\": \"\",\n \"buyerPhone\": \"\",\n \"sellerId\": 1,\n \"sellerName\": \"This name\",\n \"sellerAddress\": \"addre\",\n \"sellerEmail\": \"ds@fdf\",\n \"sellerPhone\": \"3434\",\n \"priceCents\": 0,\n \"discount\": 19,\n \"tax\": 12,\n \"termsAndConditions\": \"Ter\",\n \"invoiceName\": \"New invo\",\n \"invoiceDate\": \"2023-09-13T08:36:41.742294+02:00\",\n \"invoiceDueDate\": \"2023-09-13T08:36:41.742294+02:00\",\n \"contractId\": 1,\n \"invoiceItem\": null,\n \"status\": \"invoice_issued\"\n }\n}" + } + ] + }, + { + "name": "Save device info", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\"imei\": \"352656107000000\",\n\"imsi\": \"232031721000000\",\n\"timestamp\": 1643200311304,\n\"epoch\": 1643200311304,\n\"packetVersion\": 1,\n\"hardwareVersion\": \"2.3\",\n\"softwareVersion\": \"0.9.0\",\n\"lat\": 34.232237643,\n\"lon\": 8.1074428597,\n\"wifiLat\": 34.232237643,\n\"wifiLon\": 7.9934428597,\n\"cellLat\": 34.232237643,\n\"cellLon\": 7.9934428597,\n\"provider\": \"tm_prv_sdq\",\n\"mcc\": 204,\n\"mnc\": 4,\n\"rat\": 9,\n\"band\": 20,\n\"earfcn\": 6254,\n\"tac\": 10113,\n\"cellId\": 27454823,\n\"physicalId\": 389,\n\"rsrp\": 24,\n\"rsrq\": 25,\n\"snr\": 31,\n\"ceLevel\": 0,\n\"location\": {\n\"type\": \"Point\",\n\"coordinates\": [34.232237643, 8.1074428597],\n\"crs\": {\n\"type\": \"name\",\n\"properties\": {\n\"name\": \"EPSG:4326\"\n}\n}\n},\n\"gpsData\": {\n\"timestamp\": 1643201553,\n\"timeToFix\": 0,\n\"latitude\": 34.232237643,\n\"longitude\": 8.1074428597,\n\"altitude\": 142.8,\n\"numberOfSats\": 4,\n\"estimatedAccuracy\": 28.68,\n\"pdop\": 6.29\n},\n\"wifiRecords\": {\n\"timestamp\": 1643200308,\n\"record\": [{\n\"macAddress\": \"00:01:02:03:04:05\",\n\"rssi\": 54\n}, {\n\"macAddress\": \"00:01:02:03:04:05\",\n\"rssi\": 55\n}, {\n\"macAddress\": \"00:01:02:03:04:05\",\n\"rssi\": 56\n}, {\n\"macAddress\": \"00:01:02:03:04:05\",\n\"rssi\": 57\n}],\n\"latitude\": 72.23184167,\n\"longitude\": 8.1064428597\n},\n\"cellInfo\": {\n\"timestamp\": 1643200305,\n\"mcc\": 204,\n\"mnc\": 4,\n\"rat\": 9,\n\"band\": 20,\n\"earfcn\": 6254,\n\"cellTac\": 10113,\n\"cellId\": 27454823,\n\"physicalId\": 389,\n\"rsrp\": 24,\n\"rsrq\": 25,\n\"snr\": 31,\n\"ceLevel\": 0,\n\"psmXTauInfo\": 480,\n\"psmDTauInfo\": 3240,\n\"latitude\": 34.232237643,\n\"longitude\": 8.1074428597\n},\n\"mode\": \"Moving\",\n\"locationMethod\": \"w\",\n\"ip\": \"10.196.152.105\",\n\"port\": 2397,\n\"stateInfo\": {\n\"flightMode\": true,\n\"motionTrigger\": true,\n\"messageDoubling\": true,\n\"t2Max\": 604800,\n\"backOffTime\": 1800,\n\"baseIdleTime\": 86400,\n\"fmBackOffTime\": 15,\n\"fmIdleTime\": 60,\n\"idleSensitivity\": 200,\n\"fmIdleSensitivity\": 50,\n\"positionTypeActive\": 3,\n\"positionTypeIdle\": 3\n},\n\"batteryMv\": 3720,\n\"temperatureData\": {\n\"timestamp\": 1643200305,\n\"temperatureInCelsius\": -2\n},\n\"temperature\": -2,\n\"deviceStatus\": {},\n\"trigger\": 4,\n\"triggerName\": \"Motion Stop\",\n\n\"cbor\":\"aa6170a361741a61f13ce761631901ac6172046176a3617001626877820203627377830009006164a461651b000140bd25ff96e461731b0000d3081858e3076163743839343\",\n\"statsInfo\": {\n\"timestamp\": 1643200305,\n\"modemOnTime\": 4916,\n\"gpsOnTime\": 61388,\n\"deviceUpTime\": 8555520,\n\"resetCause\": 144\n},\n\"accelerometerInfo\": {\n\"timestamp\": 1643200309,\n\"numberOfSamples\": 10,\n\"samplingDuration\": 3792,\n\"X\": -937,\n\"Y\": -4,\n\"Z\": 0\n},\n\"counter\": 428,\n\"deviceId\": \"9c51ef10-bf79-4556-8767-1de4bdda0836\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/device_data/save", + "host": [ + "{{URL}}" + ], + "path": [ + "device_data", + "save" + ] + } + }, + "response": [ + { + "name": "Save device info", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\"imei\": \"352656107000000\",\n\"imsi\": \"232031721000000\",\n\"timestamp\": 1643200311304,\n\"epoch\": 1643200311304,\n\"packetVersion\": 1,\n\"hardwareVersion\": \"2.3\",\n\"softwareVersion\": \"0.9.0\",\n\"lat\": 34.232237643,\n\"lon\": 8.1074428597,\n\"wifiLat\": 34.232237643,\n\"wifiLon\": 7.9934428597,\n\"cellLat\": 34.232237643,\n\"cellLon\": 7.9934428597,\n\"provider\": \"tm_prv_sdq\",\n\"mcc\": 204,\n\"mnc\": 4,\n\"rat\": 9,\n\"band\": 20,\n\"earfcn\": 6254,\n\"tac\": 10113,\n\"cellId\": 27454823,\n\"physicalId\": 389,\n\"rsrp\": 24,\n\"rsrq\": 25,\n\"snr\": 31,\n\"ceLevel\": 0,\n\"location\": {\n\"type\": \"Point\",\n\"coordinates\": [34.232237643, 8.1074428597],\n\"crs\": {\n\"type\": \"name\",\n\"properties\": {\n\"name\": \"EPSG:4326\"\n}\n}\n},\n\"gpsData\": {\n\"timestamp\": 1643201553,\n\"timeToFix\": 0,\n\"latitude\": 34.232237643,\n\"longitude\": 8.1074428597,\n\"altitude\": 142.8,\n\"numberOfSats\": 4,\n\"estimatedAccuracy\": 28.68,\n\"pdop\": 6.29\n},\n\"wifiRecords\": {\n\"timestamp\": 1643200308,\n\"record\": [{\n\"macAddress\": \"00:01:02:03:04:05\",\n\"rssi\": 54\n}, {\n\"macAddress\": \"00:01:02:03:04:05\",\n\"rssi\": 55\n}, {\n\"macAddress\": \"00:01:02:03:04:05\",\n\"rssi\": 56\n}, {\n\"macAddress\": \"00:01:02:03:04:05\",\n\"rssi\": 57\n}],\n\"latitude\": 72.23184167,\n\"longitude\": 8.1064428597\n},\n\"cellInfo\": {\n\"timestamp\": 1643200305,\n\"mcc\": 204,\n\"mnc\": 4,\n\"rat\": 9,\n\"band\": 20,\n\"earfcn\": 6254,\n\"cellTac\": 10113,\n\"cellId\": 27454823,\n\"physicalId\": 389,\n\"rsrp\": 24,\n\"rsrq\": 25,\n\"snr\": 31,\n\"ceLevel\": 0,\n\"psmXTauInfo\": 480,\n\"psmDTauInfo\": 3240,\n\"latitude\": 34.232237643,\n\"longitude\": 8.1074428597\n},\n\"mode\": \"Moving\",\n\"locationMethod\": \"w\",\n\"ip\": \"10.196.152.105\",\n\"port\": 2397,\n\"stateInfo\": {\n\"flightMode\": true,\n\"motionTrigger\": true,\n\"messageDoubling\": true,\n\"t2Max\": 604800,\n\"backOffTime\": 1800,\n\"baseIdleTime\": 86400,\n\"fmBackOffTime\": 15,\n\"fmIdleTime\": 60,\n\"idleSensitivity\": 200,\n\"fmIdleSensitivity\": 50,\n\"positionTypeActive\": 3,\n\"positionTypeIdle\": 3\n},\n\"batteryMv\": 3720,\n\"temperatureData\": {\n\"timestamp\": 1643200305,\n\"temperatureInCelsius\": -2\n},\n\"temperature\": -2,\n\"deviceStatus\": {},\n\"trigger\": 4,\n\"triggerName\": \"Motion Stop\",\n\n\"cbor\":\"aa6170a361741a61f13ce761631901ac6172046176a3617001626877820203627377830009006164a461651b000140bd25ff96e461731b0000d3081858e3076163743839343\",\n\"statsInfo\": {\n\"timestamp\": 1643200305,\n\"modemOnTime\": 4916,\n\"gpsOnTime\": 61388,\n\"deviceUpTime\": 8555520,\n\"resetCause\": 144\n},\n\"accelerometerInfo\": {\n\"timestamp\": 1643200309,\n\"numberOfSamples\": 10,\n\"samplingDuration\": 3792,\n\"X\": -937,\n\"Y\": -4,\n\"Z\": 0\n},\n\"counter\": 428,\n\"deviceId\": \"9c51ef10-bf79-4556-8767-1de4bdda0836\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/device_data/save", + "host": [ + "{{URL}}" + ], + "path": [ + "device_data", + "save" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Fri, 06 Oct 2023 08:39:05 GMT" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + } + ], + "cookie": [], + "body": "{\n \"data\": {\n \"ID\": 58,\n \"CreatedAt\": \"2023-10-06T10:39:05.696554685+02:00\",\n \"UpdatedAt\": \"2023-10-06T10:39:05.696554685+02:00\",\n \"DeletedAt\": null,\n \"raw_json\": \"{\\n\\\"imei\\\": \\\"352656107000000\\\",\\n\\\"imsi\\\": \\\"232031721000000\\\",\\n\\\"timestamp\\\": 1643200311304,\\n\\\"epoch\\\": 1643200311304,\\n\\\"packetVersion\\\": 1,\\n\\\"hardwareVersion\\\": \\\"2.3\\\",\\n\\\"softwareVersion\\\": \\\"0.9.0\\\",\\n\\\"lat\\\": 34.232237643,\\n\\\"lon\\\": 8.1074428597,\\n\\\"wifiLat\\\": 34.232237643,\\n\\\"wifiLon\\\": 7.9934428597,\\n\\\"cellLat\\\": 34.232237643,\\n\\\"cellLon\\\": 7.9934428597,\\n\\\"provider\\\": \\\"tm_prv_sdq\\\",\\n\\\"mcc\\\": 204,\\n\\\"mnc\\\": 4,\\n\\\"rat\\\": 9,\\n\\\"band\\\": 20,\\n\\\"earfcn\\\": 6254,\\n\\\"tac\\\": 10113,\\n\\\"cellId\\\": 27454823,\\n\\\"physicalId\\\": 389,\\n\\\"rsrp\\\": 24,\\n\\\"rsrq\\\": 25,\\n\\\"snr\\\": 31,\\n\\\"ceLevel\\\": 0,\\n\\\"location\\\": {\\n\\\"type\\\": \\\"Point\\\",\\n\\\"coordinates\\\": [34.232237643, 8.1074428597],\\n\\\"crs\\\": {\\n\\\"type\\\": \\\"name\\\",\\n\\\"properties\\\": {\\n\\\"name\\\": \\\"EPSG:4326\\\"\\n}\\n}\\n},\\n\\\"gpsData\\\": {\\n\\\"timestamp\\\": 1643201553,\\n\\\"timeToFix\\\": 0,\\n\\\"latitude\\\": 34.232237643,\\n\\\"longitude\\\": 8.1074428597,\\n\\\"altitude\\\": 142.8,\\n\\\"numberOfSats\\\": 4,\\n\\\"estimatedAccuracy\\\": 28.68,\\n\\\"pdop\\\": 6.29\\n},\\n\\\"wifiRecords\\\": {\\n\\\"timestamp\\\": 1643200308,\\n\\\"record\\\": [{\\n\\\"macAddress\\\": \\\"00:01:02:03:04:05\\\",\\n\\\"rssi\\\": 54\\n}, {\\n\\\"macAddress\\\": \\\"00:01:02:03:04:05\\\",\\n\\\"rssi\\\": 55\\n}, {\\n\\\"macAddress\\\": \\\"00:01:02:03:04:05\\\",\\n\\\"rssi\\\": 56\\n}, {\\n\\\"macAddress\\\": \\\"00:01:02:03:04:05\\\",\\n\\\"rssi\\\": 57\\n}],\\n\\\"latitude\\\": 72.23184167,\\n\\\"longitude\\\": 8.1064428597\\n},\\n\\\"cellInfo\\\": {\\n\\\"timestamp\\\": 1643200305,\\n\\\"mcc\\\": 204,\\n\\\"mnc\\\": 4,\\n\\\"rat\\\": 9,\\n\\\"band\\\": 20,\\n\\\"earfcn\\\": 6254,\\n\\\"cellTac\\\": 10113,\\n\\\"cellId\\\": 27454823,\\n\\\"physicalId\\\": 389,\\n\\\"rsrp\\\": 24,\\n\\\"rsrq\\\": 25,\\n\\\"snr\\\": 31,\\n\\\"ceLevel\\\": 0,\\n\\\"psmXTauInfo\\\": 480,\\n\\\"psmDTauInfo\\\": 3240,\\n\\\"latitude\\\": 34.232237643,\\n\\\"longitude\\\": 8.1074428597\\n},\\n\\\"mode\\\": \\\"Moving\\\",\\n\\\"locationMethod\\\": \\\"w\\\",\\n\\\"ip\\\": \\\"10.196.152.105\\\",\\n\\\"port\\\": 2397,\\n\\\"stateInfo\\\": {\\n\\\"flightMode\\\": true,\\n\\\"motionTrigger\\\": true,\\n\\\"messageDoubling\\\": true,\\n\\\"t2Max\\\": 604800,\\n\\\"backOffTime\\\": 1800,\\n\\\"baseIdleTime\\\": 86400,\\n\\\"fmBackOffTime\\\": 15,\\n\\\"fmIdleTime\\\": 60,\\n\\\"idleSensitivity\\\": 200,\\n\\\"fmIdleSensitivity\\\": 50,\\n\\\"positionTypeActive\\\": 3,\\n\\\"positionTypeIdle\\\": 3\\n},\\n\\\"batteryMv\\\": 3720,\\n\\\"temperatureData\\\": {\\n\\\"timestamp\\\": 1643200305,\\n\\\"temperatureInCelsius\\\": -2\\n},\\n\\\"temperature\\\": -2,\\n\\\"deviceStatus\\\": {},\\n\\\"trigger\\\": 4,\\n\\\"triggerName\\\": \\\"Motion Stop\\\",\\n\\n\\\"cbor\\\":\\\"aa6170a361741a61f13ce761631901ac6172046176a3617001626877820203627377830009006164a461651b000140bd25ff96e461731b0000d3081858e3076163743839343\\\",\\n\\\"statsInfo\\\": {\\n\\\"timestamp\\\": 1643200305,\\n\\\"modemOnTime\\\": 4916,\\n\\\"gpsOnTime\\\": 61388,\\n\\\"deviceUpTime\\\": 8555520,\\n\\\"resetCause\\\": 144\\n},\\n\\\"accelerometerInfo\\\": {\\n\\\"timestamp\\\": 1643200309,\\n\\\"numberOfSamples\\\": 10,\\n\\\"samplingDuration\\\": 3792,\\n\\\"X\\\": -937,\\n\\\"Y\\\": -4,\\n\\\"Z\\\": 0\\n},\\n\\\"counter\\\": 428,\\n\\\"deviceId\\\": \\\"9c51ef10-bf79-4556-8767-1de4bdda0836\\\"\\n}\",\n \"imei\": \"352656107000000\",\n \"imsi\": \"232031721000000\",\n \"timestamp\": 1643200311304,\n \"lat\": 34.232237643,\n \"lon\": 8.1074428597,\n \"wifiLocation\": {\n \"lat\": 0,\n \"lon\": 0\n },\n \"cellLocation\": {\n \"lat\": 0,\n \"lon\": 0\n },\n \"temperature\": -2,\n \"accelerometerInfo\": {\n \"x\": -937,\n \"y\": -4,\n \"z\": 0\n },\n \"x\": -937,\n \"y\": -4,\n \"z\": 0,\n \"DeviceID\": 7,\n \"deviceId\": \"9c51ef10-bf79-4556-8767-1de4bdda0836\"\n },\n \"message\": \"Successfully received and saved device info\"\n}" + } + ] + }, + { + "name": "Create Contracts", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"sellerId\": 1,\n \"buyerId\": 2,\n \"description\": \"This is a sample contract.\",\n \"productId\": 3,\n \"minTemp\": -20.0,\n \"maxTemp\": 40.0,\n \"arrivalDate\": 1674019200,\n \"penaltyType\": \"AMOUNT\",\n \"penaltyValue\": 100,\n \"penaltyRec\": \"DAILY\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/contracts/create", + "host": [ + "{{URL}}" + ], + "path": [ + "contracts", + "create" + ] + } + }, + "response": [ + { + "name": "Create Contracts", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"sellerId\": 1,\n \"buyerId\": 2,\n \"description\": \"This is a sample contract.\",\n \"productId\": 3,\n \"minTemp\": -20.0,\n \"maxTemp\": 40.0,\n \"arrivalDate\": 1674019200,\n \"penaltyType\": \"AMOUNT\",\n \"penaltyValue\": 100,\n \"penaltyRec\": \"DAILY\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/contracts/create", + "host": [ + "{{URL}}" + ], + "path": [ + "contracts", + "create" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Fri, 06 Oct 2023 08:40:15 GMT" + }, + { + "key": "Content-Length", + "value": "61" + } + ], + "cookie": [], + "body": "{\n \"id\": 9,\n \"message\": \"Successfully received and saved contract\"\n}" + } + ] + } + ] +} \ No newline at end of file diff --git a/controllers/contracts_controller.go b/controllers/contracts_controller.go index 3512b76..8d56c97 100644 --- a/controllers/contracts_controller.go +++ b/controllers/contracts_controller.go @@ -1,20 +1,23 @@ package controllers import ( + "log" "net/http" "strconv" + "strings" "time" "github.com/gin-gonic/gin" "gitlab.com/pactual1/backend/database/contract" "gitlab.com/pactual1/backend/models" + "gitlab.com/pactual1/backend/shared" ) func GetLatestContracts(c *gin.Context) { // Existing parameters limitStr := c.DefaultQuery("limit", "50") offsetStr := c.DefaultQuery("offset", "0") - status := c.DefaultQuery("status", models.ContractStatusActive) + status := strings.Split(c.DefaultQuery("status", models.ContractStatusActive), ",") // New/Updated optional parameters companyName := c.Query("company_name") @@ -81,7 +84,7 @@ func GetLatestContracts(c *gin.Context) { } // Respond with the contracts and the total count - c.JSON(http.StatusOK, gin.H{"total": total, "data": contracts}) + c.JSON(http.StatusOK, gin.H{"total": total, "data": models.ConvertContractToResponse(contracts)}) } @@ -89,7 +92,7 @@ func GetBuyerContracts(c *gin.Context) { // Existing parameters limitStr := c.DefaultQuery("limit", "50") offsetStr := c.DefaultQuery("offset", "0") - status := c.Query("status") + status := strings.Split(c.DefaultQuery("status", models.ContractStatusActive), ",") contractIDStr := c.DefaultQuery("contract_id","0") dateCreatedStr := c.Query("date_created") @@ -137,44 +140,51 @@ func GetBuyerContracts(c *gin.Context) { } // Respond with the contracts and the total count - c.JSON(http.StatusOK, gin.H{"total": total, "data": convertContractToResponseModel(contracts)}) + c.JSON(http.StatusOK, gin.H{"total": total, "data": models.ConvertContractToResponseModel(contracts)}) } func GetContractStatuses(c *gin.Context) { // Respond with the contract statuses - c.JSON(http.StatusOK, gin.H{"statuses": models.GetContractStatuses()}) -} - - -func convertContractToResponseModel(contracts []models.Contract) []models.ListContractResponse { - var listInvoiceResponses []models.ListContractResponse - - // Get all statuses - statuses := models.GetContractStatuses() - statusMap := make(map[string]models.Status) - for _, s := range statuses { - statusMap[s.Value] = s - } - - for _, contract := range contracts { - // Get the status based on Value in the DB - status, ok := statusMap[contract.Status] - if !ok { - status = models.Status{Key: "Unknown", Value: "unknown"} - } - - listInvoiceResponse := models.ListContractResponse{ - Status: models.KeyValue{Key: status.Key, Value: status.Value}, - Buyer: models.CompanyShortResponse{ID: int(contract.BuyerID), Name: contract.BuyerName}, - ContractID: int(contract.ID), - DateCreated: contract.CreatedAt, - NumberOfDevices: contract.NumberOfDevices, - } - listInvoiceResponses = append(listInvoiceResponses, listInvoiceResponse) - } - return listInvoiceResponses + c.JSON(http.StatusOK, gin.H{"data": models.GetContractStatuses()}) } + +func CreateContract(c *gin.Context) { + + var payload models.CreateContractRequestPayload + + if err := c.ShouldBindJSON(&payload); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid JSON payload"}) + log.Printf("Invalid JSON payload: %v", err) + return + } + + db := shared.GetDb() + + newContract := models.Contract{ + BuyerID: payload.BuyerID, + SellerID: payload.SellerID, + Description: payload.Description, + ProductID: payload.ProductID, + MinTemp: payload.MinTemp, + MaxTemp: payload.MaxTemp, + ArrivalDate: time.Unix(payload.ArrivalDate, 0), + PenaltyType: payload.PenaltyRec, + PenaltyValue : payload.PenaltyValue, + PenaltyRec : payload.PenaltyRec, + } + + if err := db.Create(&newContract).Error; err != nil { + log.Printf("SaveContractInfo CREATE - Contract DB Error: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not create new contract"}) + return + } + + log.Printf("Successfully received and saved contract: %v", newContract) + c.JSON(http.StatusOK, gin.H{"message": "Successfully received and saved contract", "id": newContract.ID}) +} + + diff --git a/controllers/devices_controller.go b/controllers/devices_controller.go index 6205738..cb6237c 100644 --- a/controllers/devices_controller.go +++ b/controllers/devices_controller.go @@ -161,5 +161,5 @@ func GetDevicesByContract(c *gin.Context) { return } // Respond with the devices - c.JSON(http.StatusOK,gin.H{"data" : devices}) + c.JSON(http.StatusOK,gin.H{"data" : models.ConvertDeviceToResponse(devices)}) } diff --git a/controllers/invoices_controller.go b/controllers/invoices_controller.go index 766330a..9ae8f1c 100644 --- a/controllers/invoices_controller.go +++ b/controllers/invoices_controller.go @@ -53,8 +53,10 @@ func GetInvoiceByID(c *gin.Context) { return } + invoiceResponses := models.ConvertInvoiceToResponse(invoices) + if len(invoices) > 0 { - c.JSON(http.StatusOK, gin.H{"data": invoices[0]}) + c.JSON(http.StatusOK, gin.H{"data": invoiceResponses[0]}) } else { c.JSON(http.StatusNotFound, gin.H{"error": "Invoice not found"}) } diff --git a/database/contract/contract.go b/database/contract/contract.go index 90bc826..294f7ac 100644 --- a/database/contract/contract.go +++ b/database/contract/contract.go @@ -13,7 +13,7 @@ import ( ) -func GetContracts(status string, companyName string, companyAddress string, +func GetContracts(status []string, companyName string, companyAddress string, companyEmail string, companyPhone string, startTime *time.Time, endTime *time.Time, contractName string, deviceIDs []int64, contractID int, dateCreated *time.Time, limit, offset int) ([]models.Contract, int64, int, error) { @@ -24,10 +24,10 @@ func GetContracts(status string, companyName string, companyAddress string, // Define custom fields to be selected, varies based on joined tables customFields := "contracts.*, array_length(contracts.device_ids, 1) as number_of_devices" - // Search by Status - if status != "" { - db = db.Where("contracts.status = ?", status) - countDb = countDb.Where("contracts.status = ?", status) + // Search by Statuses + if len(status) > 0 { + db = db.Where("contracts.status IN (?)", status) + countDb = countDb.Where("contracts.status IN (?)", status) } // Search by Company Fields diff --git a/database/device/device.go b/database/device/device.go index f6dd07d..e0d250b 100644 --- a/database/device/device.go +++ b/database/device/device.go @@ -79,13 +79,14 @@ func GetDeviceInfoForContract (deviceID uint64, contract models.Contract) (model } } + deviceInfosResponse := models.ConvertDeviceInfoToResponse(deviceInfos) // Loop through each deviceInfo to create GeoJSON features - for _, info := range deviceInfos { + for _, info := range deviceInfosResponse { info.RawJSON = "" feature := models.GeoJSONFeature{ Type: "Feature", - DeviceInfo: &info, + DeviceInfoResponse: &info, Geometry: models.GeoJSONGeometry{ Type: "Point", Coordinates: []float64{info.Lon, info.Lat}, diff --git a/database/invoice/invoice.go b/database/invoice/invoice.go index 1add62f..6183b31 100644 --- a/database/invoice/invoice.go +++ b/database/invoice/invoice.go @@ -47,13 +47,15 @@ func GetInvoices(buyerName string, sortBy string, limit int, offset int, id uint Find(&invoices).Error; err != nil { return nil, 0, err } - + for i := range invoices { var sum int64 - for _, item := range invoices[i].InvoiceItem { + if invoices[i].InvoiceItem != nil { + for _, item := range *invoices[i].InvoiceItem { sum += item.PriceCents * item.Quantity } invoices[i].PriceCents = sum + } } return invoices, total, nil diff --git a/models/company.go b/models/company.go index 9f9c8ab..4127862 100644 --- a/models/company.go +++ b/models/company.go @@ -1,20 +1,29 @@ package models -import "github.com/jinzhu/gorm" +import ( + "time" + "github.com/jinzhu/gorm" +) + +type BaseModel struct { + ID uint `json:"id" gorm:"primaryKey"` + CreatedAt time.Time `json:"createdAt" gorm:"autoCreateTime"` + UpdatedAt time.Time `json:"updatedAt" gorm:"autoUpdateTime"` +} type Company struct { gorm.Model - Name string - Address string - Email string - Phone string - Users []User - Devices []Device + Name string `json:"name"` + Address string `json:"address"` + Email string `json:"email"` + Phone string `json:"phone"` + Users []User `json:"users"` + Devices []Device `json:"devices"` } type CompanyShortResponse struct { - ID int - Name string + ID int `json:"id"` + Name string `json:"name"` } diff --git a/models/contract.go b/models/contract.go index da8cdab..c59e0fc 100644 --- a/models/contract.go +++ b/models/contract.go @@ -9,22 +9,127 @@ import ( type Contract struct { gorm.Model - Name string - DeviceIDs pq.Int64Array `gorm:"type:integer[]"` - BuyerID uint - StartLat float64 - StartLon float64 - EndLat float64 - EndLon float64 - StartTime time.Time - EndTime time.Time - Status string - BlockchainID string - ContractInfos []ContractInfo - BuyerName string `gorm:"-"` - NumberOfDevices int `gorm:"-"` + Name string `json:"name"` + DeviceIDs pq.Int64Array `json:"deviceIds" gorm:"type:integer[]"` + BuyerID uint `json:"buyerId"` + SellerID uint `json:"sellerId"` + Description string `json:"description"` + StartLat float64 `json:"startLat"` + StartLon float64 `json:"startLon"` + EndLat float64 `json:"endLat"` + EndLon float64 `json:"endLon"` + StartTime time.Time `json:"startTime"` + EndTime time.Time `json:"endTime"` + Status string `json:"status"` + BlockchainID string `json:"blockchainId"` + ContractInfos []ContractInfo `json:"contractInfos"` + ProductID uint `json:"productId"` + MaxTemp float64 `json:"maxTemp"` + MinTemp float64 `json:"minTemp"` + ArrivalDate time.Time `json:"arrivalDate"` + PenaltyType string `json:"penaltyType"` + PenaltyValue int `json:"penaltyValue"` + PenaltyRec string `json:"penaltyRec"` + BuyerName string `json:"buyerName" gorm:"-"` + NumberOfDevices int `json:"numberOfDevices" gorm:"-"` } +type ContractResponse struct { + BaseModel + Name string `json:"name"` + DeviceIDs pq.Int64Array `json:"deviceIds" gorm:"type:integer[]"` + BuyerID uint `json:"buyerId"` + SellerID uint `json:"sellerId"` + Description string `json:"description"` + StartLat float64 `json:"startLat"` + StartLon float64 `json:"startLon"` + EndLat float64 `json:"endLat"` + EndLon float64 `json:"endLon"` + StartTime time.Time `json:"startTime"` + EndTime time.Time `json:"endTime"` + Status string `json:"status"` + BlockchainID string `json:"blockchainId"` + ContractInfos []ContractInfo `json:"contractInfos"` + ProductID uint `json:"productId"` + MaxTemp float64 `json:"maxTemp"` + MinTemp float64 `json:"minTemp"` + ArrivalDate time.Time `json:"arrivalDate"` + PenaltyType string `json:"penaltyType"` + PenaltyValue int `json:"penaltyValue"` + PenaltyRec string `json:"penaltyRec"` + BuyerName string `json:"buyerName" gorm:"-"` + NumberOfDevices int `json:"numberOfDevices" gorm:"-"` +} + + + +func ConvertContractToResponse(contracts []Contract) []ContractResponse { + var contractResponses []ContractResponse + for _, contract := range contracts { + contractResponse := ContractResponse{ + BaseModel: BaseModel{ + ID: contract.ID, + CreatedAt: contract.CreatedAt, + UpdatedAt: contract.UpdatedAt, + }, + Name: contract.Name, + DeviceIDs: contract.DeviceIDs, + BuyerID: contract.BuyerID, + SellerID: contract.SellerID, + Description: contract.Description, + StartLat: contract.StartLat, + StartLon: contract.StartLon, + EndLat: contract.EndLat, + EndLon: contract.EndLon, + StartTime: contract.StartTime, + EndTime: contract.EndTime, + Status: contract.Status, + BlockchainID: contract.BlockchainID, + ContractInfos: contract.ContractInfos, + ProductID: contract.ProductID, + MaxTemp: contract.MaxTemp, + MinTemp: contract.MinTemp, + ArrivalDate: contract.ArrivalDate, + PenaltyType: contract.PenaltyType, + PenaltyValue: contract.PenaltyValue, + PenaltyRec: contract.PenaltyRec, + BuyerName: contract.BuyerName, + NumberOfDevices: contract.NumberOfDevices, + } + contractResponses = append(contractResponses, contractResponse) + } + return contractResponses +} + +func ConvertContractToResponseModel(contracts []Contract) []ListContractResponse { + var listInvoiceResponses []ListContractResponse + + // Get all statuses + statuses := GetContractStatuses() + statusMap := make(map[string]Status) + for _, s := range statuses { + statusMap[s.Value] = s + } + + for _, contract := range contracts { + // Get the status based on Value in the DB + status, ok := statusMap[contract.Status] + if !ok { + status = Status{Key: "", Value: ""} + } + + listInvoiceResponse := ListContractResponse{ + Status: KeyValue{Key: status.Key, Value: status.Value}, + Buyer: CompanyShortResponse{ID: int(contract.BuyerID), Name: contract.BuyerName}, + ContractID: int(contract.ID), + DateCreated: contract.CreatedAt, + NumberOfDevices: contract.NumberOfDevices, + } + listInvoiceResponses = append(listInvoiceResponses, listInvoiceResponse) + } + return listInvoiceResponses + +} const ContractStatusActive = "active" const ContractStatusPending = "pending" const ContractStatusDraft = "draft" @@ -34,6 +139,13 @@ const ContractStatusExecuted = "executed" const ContractStatusRevoked = "revoked" +const PenaltyTypeAmount = "amount" +const PenaltyTypePercentage = "percentage" + +const PenaltyRecDaily = "daily" +const PenaltyRecMonthly = "monthly" + + type Status struct { Key string `json:"key"` Value string `json:"value"` @@ -41,25 +153,38 @@ type Status struct { func GetContractStatuses() []Status { return []Status{ - {Key: "Active", Value: "active"}, - {Key: "Pending signature", Value: "pending"}, - {Key: "Draft", Value: "draft"}, - {Key: "Signed", Value: "signed"}, - {Key: "Ready for Activation", Value: "ready_for_activation"}, - {Key: "Executed", Value: "executed"}, - {Key: "Revoked", Value: "revoked"}, + {Value: "Active", Key: "active"}, + {Value: "Pending signature", Key: "pending"}, + {Value: "Draft", Key: "draft"}, + {Value: "Signed", Key: "signed"}, + {Value: "Ready for Activation", Key: "ready_for_activation"}, + {Value: "Executed", Key: "executed"}, + {Value: "Revoked", Key: "revoked"}, } } type ListContractResponse struct { - Status KeyValue `json:"Status"` - Buyer CompanyShortResponse `json:"Buyer"` - ContractID int - NumberOfDevices int - DateCreated time.Time + Status KeyValue `json:"status"` + Buyer CompanyShortResponse `json:"buyer"` + ContractID int `json:"contractID"` + NumberOfDevices int `json:"numberOfDevices"` + DateCreated time.Time `json:"dateCreated"` } +type CreateContractRequestPayload struct { + SellerID uint `json:"sellerId" binding:"required"` + BuyerID uint `json:"buyerId" binding:"required"` + Description string `json:"description"` + ProductID uint `json:"productId"` + MinTemp float64 `json:"minTemp" binding:"required"` + MaxTemp float64 `json:"maxTemp" binding:"required"` + ArrivalDate int64 `json:"arrivalDate"` + PenaltyType string `json:"penaltyType"` + PenaltyValue int `json:"penaltyValue"` + PenaltyRec string `json:"penaltyRec"` +} + func (Contract) Update() (bool, error) { return false, nil } @@ -69,3 +194,5 @@ func (Contract) Create() (bool, error) { func (Contract) Delete() (bool, error) { return false, nil } + + diff --git a/models/device.go b/models/device.go index 498eac6..ba25a37 100644 --- a/models/device.go +++ b/models/device.go @@ -4,15 +4,54 @@ import ( "github.com/jinzhu/gorm" ) + type Device struct { gorm.Model - DeviceID string `json:"deviceId"` - DeviceName string + DeviceID string `json:"deviceId"` + DeviceName string `json:"deviceName"` IMEI string `json:"imei"` IMSI string `json:"imsi"` - DeviceConfiguration string `gorm:"type:json"` - CompanyID uint - DeviceInfos []DeviceInfo + DeviceConfiguration string `json:"deviceConfiguration" gorm:"type:json"` + CompanyID uint `json:"companyId"` + DeviceInfos *[]DeviceInfo `json:"deviceInfos"` +} + +type DeviceResponse struct { + BaseModel + DeviceID string `json:"deviceId"` + DeviceName string `json:"deviceName"` + IMEI string `json:"imei"` + IMSI string `json:"imsi"` + DeviceConfiguration string `json:"deviceConfiguration" gorm:"type:json"` + CompanyID uint `json:"companyId"` + DeviceInfos *[]DeviceInfo `json:"deviceInfos"` +} + +func ConvertDeviceToResponse(devices []Device) []DeviceResponse { + var deviceResponses []DeviceResponse + for _, device := range devices { + if device.DeviceInfos == nil { + emptySlice := make([]DeviceInfo, 0) + device.DeviceInfos = &emptySlice + } + + deviceResponse := DeviceResponse{ + BaseModel: BaseModel{ + ID: device.ID, + CreatedAt: device.CreatedAt, + UpdatedAt: device.UpdatedAt, + }, + DeviceID: device.DeviceID, + DeviceName: device.DeviceName, + IMEI: device.IMEI, + IMSI: device.IMSI, + DeviceConfiguration: device.DeviceConfiguration, + CompanyID: device.CompanyID, + DeviceInfos: device.DeviceInfos, + } + deviceResponses = append(deviceResponses, deviceResponse) + } + return deviceResponses } func (Device) Update() (bool, error) { @@ -30,3 +69,4 @@ func (d *Device) Delete(db *gorm.DB) (bool, error) { return true, nil } + diff --git a/models/device_info.go b/models/device_info.go index 72edafb..e4a0fcc 100644 --- a/models/device_info.go +++ b/models/device_info.go @@ -1,6 +1,8 @@ package models -import "github.com/jinzhu/gorm" +import ( + "github.com/jinzhu/gorm" +) // Location holds latitude and longitude. type Location struct { @@ -10,17 +12,15 @@ type Location struct { // ImportantInfo holds fields that are important for quick access. type SensorData struct { - IMEI string `json:"imei"` - IMSI string `json:"imsi"` - Timestamp int64 `json:"timestamp"` - Lat float64 `json:"lat"` - Lon float64 `json:"lon"` - WifiLoc Location `json:"wifi_location"` - CellLoc Location `json:"cell_location"` - Temperature float64 `json:"temperature"` - // Used to parse incoming json data - AccInfo AccelerometerInfo `json:"accelerometerInfo"` - // Used to store coordinates of accelerometer to DB + IMEI string `json:"imei"` + IMSI string `json:"imsi"` + Timestamp int64 `json:"timestamp"` + Lat float64 `json:"lat"` + Lon float64 `json:"lon"` + WifiLoc Location `json:"wifiLocation"` + CellLoc Location `json:"cellLocation"` + Temperature float64 `json:"temperature"` + AccInfo AccelerometerInfo `json:"accelerometerInfo"` AccelerometerInfo } @@ -33,12 +33,38 @@ type DeviceInfo struct { } -type AccelerometerInfo struct { - X int64 - Y int64 - Z int64 +type DeviceInfoResponse struct { + BaseModel + RawJSON string `json:"rawJson" gorm:"type:json"` + SensorData + DeviceID uint `json:"deviceId"` + ExternalDeviceID string `json:"externalDeviceId"` } +func ConvertDeviceInfoToResponse(deviceInfos []DeviceInfo) []DeviceInfoResponse { + var deviceInfoResponses []DeviceInfoResponse + for _, deviceInfo := range deviceInfos { + deviceInfoResponse := DeviceInfoResponse{ + BaseModel: BaseModel{ + ID: deviceInfo.ID, + CreatedAt: deviceInfo.CreatedAt, + UpdatedAt: deviceInfo.UpdatedAt, + }, + RawJSON: deviceInfo.RawJSON, + SensorData: deviceInfo.SensorData, + DeviceID: deviceInfo.DeviceID, + ExternalDeviceID: deviceInfo.ExternalDeviceID, + } + deviceInfoResponses = append(deviceInfoResponses, deviceInfoResponse) + } + return deviceInfoResponses +} + +type AccelerometerInfo struct { + X int64 `json:"x"` + Y int64 `json:"y"` + Z int64 `json:"z"` +} type GeoJSONFeatureCollection struct { Type string `json:"type"` Features []GeoJSONFeature `json:"features"` @@ -47,7 +73,7 @@ type GeoJSONFeatureCollection struct { type GeoJSONFeature struct { Type string `json:"type"` Geometry GeoJSONGeometry `json:"geometry"` - DeviceInfo *DeviceInfo `json:",omitempty"` + DeviceInfoResponse *DeviceInfoResponse `json:"deviceInfo,omitempty"` Properties map[string]interface{} `json:"properties"` } @@ -56,7 +82,6 @@ type GeoJSONGeometry struct { Coordinates []float64 `json:"coordinates"` } - func (DeviceInfo) Update() (bool, error) { return false, nil } diff --git a/models/invoice.go b/models/invoice.go index 4c082f8..ba7f7f4 100644 --- a/models/invoice.go +++ b/models/invoice.go @@ -1,6 +1,7 @@ package models import ( + "database/sql" "time" "github.com/jinzhu/gorm" @@ -8,42 +9,113 @@ import ( type Invoice struct { gorm.Model - BuyerID uint - BuyerName string - BuyerAddress string - BuyerEmail string - BuyerPhone string - SellerID uint - SellerName string - SellerAddress string - SellerEmail string - SellerPhone string - PriceCents int64 `gorm:"column:price_cents"` - Discount int64 - Tax int64 - TermsAndConditions string - InvoiceName string - InvoiceDate time.Time - InvoiceDueDate time.Time - ContractID uint - InvoiceItem [] InvoiceItem - Status string + ID uint `json:"id" gorm:"primaryKey"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + DeletedAt sql.NullTime `json:"deletedAt" gorm:"index"` + BuyerID uint `json:"buyerId"` + BuyerName string `json:"buyerName"` + BuyerAddress string `json:"buyerAddress"` + BuyerEmail string `json:"buyerEmail"` + BuyerPhone string `json:"buyerPhone"` + SellerID uint `json:"sellerId"` + SellerName string `json:"sellerName"` + SellerAddress string `json:"sellerAddress"` + SellerEmail string `json:"sellerEmail"` + SellerPhone string `json:"sellerPhone"` + PriceCents int64 `json:"priceCents" gorm:"column:price_cents"` + Discount int64 `json:"discount"` + Tax int64 `json:"tax"` + TermsAndConditions string `json:"termsAndConditions"` + InvoiceName string `json:"invoiceName"` + InvoiceDate time.Time `json:"invoiceDate"` + InvoiceDueDate time.Time `json:"invoiceDueDate"` + ContractID uint `json:"contractId"` + InvoiceItem *[]InvoiceItem `json:"invoiceItem"` + Status string `json:"status"` } +type InvoiceResponse struct { + BaseModel + ID uint `json:"id" gorm:"primaryKey"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + DeletedAt sql.NullTime `json:"deletedAt" gorm:"index"` + BuyerID uint `json:"buyerId"` + BuyerName string `json:"buyerName"` + BuyerAddress string `json:"buyerAddress"` + BuyerEmail string `json:"buyerEmail"` + BuyerPhone string `json:"buyerPhone"` + SellerID uint `json:"sellerId"` + SellerName string `json:"sellerName"` + SellerAddress string `json:"sellerAddress"` + SellerEmail string `json:"sellerEmail"` + SellerPhone string `json:"sellerPhone"` + PriceCents int64 `json:"priceCents" gorm:"column:price_cents"` + Discount int64 `json:"discount"` + Tax int64 `json:"tax"` + TermsAndConditions string `json:"termsAndConditions"` + InvoiceName string `json:"invoiceName"` + InvoiceDate time.Time `json:"invoiceDate"` + InvoiceDueDate time.Time `json:"invoiceDueDate"` + ContractID uint `json:"contractId"` + InvoiceItem *[]InvoiceItem `json:"invoiceItem"` + Status string `json:"status"` +} + +func ConvertInvoiceToResponse(invoices []Invoice) []InvoiceResponse { + var invoiceResponses []InvoiceResponse + for _, invoice := range invoices { + if invoice.InvoiceItem == nil { + emptySlice := make([]InvoiceItem, 0) + invoice.InvoiceItem = &emptySlice + } + + invoiceResponse := InvoiceResponse{ + BaseModel: BaseModel{ + ID: invoice.ID, + CreatedAt: invoice.CreatedAt, + UpdatedAt: invoice.UpdatedAt, + }, + BuyerID: invoice.BuyerID, + BuyerName: invoice.BuyerName, + BuyerAddress: invoice.BuyerAddress, + BuyerEmail: invoice.BuyerEmail, + BuyerPhone: invoice.BuyerPhone, + SellerID: invoice.SellerID, + SellerName: invoice.SellerName, + SellerAddress: invoice.SellerAddress, + SellerEmail: invoice.SellerEmail, + SellerPhone: invoice.SellerPhone, + PriceCents: invoice.PriceCents, + Discount: invoice.Discount, + Tax: invoice.Tax, + TermsAndConditions: invoice.TermsAndConditions, + InvoiceName: invoice.InvoiceName, + InvoiceDate: invoice.InvoiceDate, + InvoiceDueDate: invoice.InvoiceDueDate, + ContractID: invoice.ContractID, + InvoiceItem: invoice.InvoiceItem, + Status: invoice.Status, + } + invoiceResponses = append(invoiceResponses, invoiceResponse) + } + return invoiceResponses +} + + type ListInvoiceResponse struct { - Status KeyValue `json:"Status"` - Buyer CompanyShortResponse `json:"Buyer"` - ContractID int - DateCreated time.Time - DueDate time.Time - Amount string - + Status KeyValue `json:"status"` + Buyer CompanyShortResponse `json:"buyer"` + ContractID int `json:"contractId"` + DateCreated time.Time `json:"dateCreated"` + DueDate time.Time `json:"dueDate"` + Amount string `json:"amount"` } - type KeyValue struct { - Key string - Value string + Key string `json:"key"` + Value string `json:"value"` } diff --git a/models/invoice_item.go b/models/invoice_item.go index eaa14dc..76079ae 100644 --- a/models/invoice_item.go +++ b/models/invoice_item.go @@ -1,18 +1,60 @@ package models import ( + "database/sql" + "time" + "github.com/jinzhu/gorm" ) type InvoiceItem struct { gorm.Model - Description string - Quantity int64 - Unit string - PriceCents int64 `gorm:"column:price_cents"` - InvoiceID uint + ID uint `json:"id" gorm:"primaryKey"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + DeletedAt sql.NullTime `json:"deletedAt" gorm:"index"` + Description string `json:"description"` + Quantity int64 `json:"quantity"` + Unit string `json:"unit"` + PriceCents int64 `json:"priceCents" gorm:"column:price_cents"` + InvoiceID uint `json:"invoiceId"` } +type InvoiceItemResponse struct { + BaseModel + ID uint `json:"id" gorm:"primaryKey"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + DeletedAt sql.NullTime `json:"deletedAt" gorm:"index"` + Description string `json:"description"` + Quantity int64 `json:"quantity"` + Unit string `json:"unit"` + PriceCents int64 `json:"priceCents" gorm:"column:price_cents"` + InvoiceID uint `json:"invoiceId"` +} + +// ConvertSliceOfInvoiceItemToResponse converts a slice of InvoiceItem models to a slice of InvoiceItemResponse models +func ConvertInvoiceItemToResponse(items []InvoiceItem) []InvoiceItemResponse { + var itemResponses []InvoiceItemResponse + for _, item := range items { + itemResponse := InvoiceItemResponse{ + BaseModel: BaseModel{ + ID: item.ID, + CreatedAt: item.CreatedAt, + UpdatedAt: item.UpdatedAt, + }, + Description: item.Description, + Quantity: item.Quantity, + Unit: item.Unit, + PriceCents: item.PriceCents, + InvoiceID: item.InvoiceID, + } + itemResponses = append(itemResponses, itemResponse) + } + return itemResponses +} + + func (InvoiceItem) Update() (bool, error) { diff --git a/models/user.go b/models/user.go index 6159378..2375d5a 100644 --- a/models/user.go +++ b/models/user.go @@ -1,14 +1,23 @@ package models -import "github.com/jinzhu/gorm" +import ( + "database/sql" + "time" + + "github.com/jinzhu/gorm" +) type User struct { gorm.Model - Username string - Password string - Email string - Avatar string - CompanyID uint + ID uint `json:"id" gorm:"primaryKey"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + DeletedAt sql.NullTime `json:"deletedAt" gorm:"index"` + Username string `json:"username"` + Password string `json:"password"` + Email string `json:"email"` + Avatar string `json:"avatar"` + CompanyID uint `json:"companyId"` } func (User) Update() (bool, error) { diff --git a/routes/public_routes.go b/routes/public_routes.go index 780d96a..82822bc 100644 --- a/routes/public_routes.go +++ b/routes/public_routes.go @@ -26,6 +26,7 @@ func RegisterPublicRoutes(r *gin.Engine) { // Contracts r.GET("/contracts/statuses", controllers.GetContractStatuses) - r.GET("/contracts/list", controllers.GetBuyerContracts) + r.GET("/contracts", controllers.GetBuyerContracts) + r.POST("/contracts/create", controllers.CreateContract) }