my_tank_info 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/main.yml +17 -0
  3. data/.gitignore +9 -0
  4. data/CHANGELOG.md +5 -0
  5. data/CODE_OF_CONDUCT.md +84 -0
  6. data/Gemfile +10 -0
  7. data/Gemfile.lock +74 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +253 -0
  10. data/Rakefile +12 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/lib/my_tank_info/client.rb +106 -0
  14. data/lib/my_tank_info/collection.rb +33 -0
  15. data/lib/my_tank_info/error.rb +6 -0
  16. data/lib/my_tank_info/errors/missing_required_attribute_error.rb +6 -0
  17. data/lib/my_tank_info/object.rb +18 -0
  18. data/lib/my_tank_info/objects/alarm.rb +6 -0
  19. data/lib/my_tank_info/objects/alarm_note.rb +6 -0
  20. data/lib/my_tank_info/objects/csld_result.rb +6 -0
  21. data/lib/my_tank_info/objects/environmental_sitegroup.rb +9 -0
  22. data/lib/my_tank_info/objects/inventory_sitegroup.rb +9 -0
  23. data/lib/my_tank_info/objects/line_leak_result.rb +6 -0
  24. data/lib/my_tank_info/objects/notification_code.rb +6 -0
  25. data/lib/my_tank_info/objects/notification_contact.rb +6 -0
  26. data/lib/my_tank_info/objects/notification_rule.rb +9 -0
  27. data/lib/my_tank_info/objects/notification_rule_contact.rb +6 -0
  28. data/lib/my_tank_info/objects/notification_site.rb +6 -0
  29. data/lib/my_tank_info/objects/sensor_status_result.rb +6 -0
  30. data/lib/my_tank_info/objects/site.rb +6 -0
  31. data/lib/my_tank_info/objects/sitegroup_inventory_dashboard.rb +9 -0
  32. data/lib/my_tank_info/objects/tank.rb +6 -0
  33. data/lib/my_tank_info/objects/tank_daily_usage_record.rb +6 -0
  34. data/lib/my_tank_info/objects/tank_delivery_record.rb +6 -0
  35. data/lib/my_tank_info/objects/tank_inventory_record.rb +6 -0
  36. data/lib/my_tank_info/objects/tank_leak_result.rb +6 -0
  37. data/lib/my_tank_info/objects/tank_reconciliation_record.rb +30 -0
  38. data/lib/my_tank_info/objects/tank_rule.rb +6 -0
  39. data/lib/my_tank_info/objects/tank_runout_record.rb +6 -0
  40. data/lib/my_tank_info/resource.rb +75 -0
  41. data/lib/my_tank_info/resources/active_alarms.rb +29 -0
  42. data/lib/my_tank_info/resources/alarm_history.rb +25 -0
  43. data/lib/my_tank_info/resources/alarm_notes.rb +13 -0
  44. data/lib/my_tank_info/resources/csld_results.rb +10 -0
  45. data/lib/my_tank_info/resources/environmental_sitegroups.rb +9 -0
  46. data/lib/my_tank_info/resources/inventory_sitegroups.rb +9 -0
  47. data/lib/my_tank_info/resources/line_leak_results.rb +10 -0
  48. data/lib/my_tank_info/resources/notification_contacts.rb +32 -0
  49. data/lib/my_tank_info/resources/notification_rules.rb +28 -0
  50. data/lib/my_tank_info/resources/sensor_status_results.rb +10 -0
  51. data/lib/my_tank_info/resources/sitegroup_inventory_dashboards.rb +12 -0
  52. data/lib/my_tank_info/resources/tank_daily_usage.rb +10 -0
  53. data/lib/my_tank_info/resources/tank_deliveries.rb +27 -0
  54. data/lib/my_tank_info/resources/tank_inventory.rb +10 -0
  55. data/lib/my_tank_info/resources/tank_leak_results.rb +10 -0
  56. data/lib/my_tank_info/resources/tank_reconciliation_records.rb +34 -0
  57. data/lib/my_tank_info/resources/tank_rules.rb +15 -0
  58. data/lib/my_tank_info/resources/tank_runout.rb +10 -0
  59. data/lib/my_tank_info/resources/tanks.rb +24 -0
  60. data/lib/my_tank_info/resources/tokens.rb +10 -0
  61. data/lib/my_tank_info/tank_reconciliation_record_collection.rb +51 -0
  62. data/lib/my_tank_info/tank_reconciliation_record_summary.rb +113 -0
  63. data/lib/my_tank_info/version.rb +5 -0
  64. data/lib/my_tank_info.rb +68 -0
  65. data/my_tank_info.gemspec +34 -0
  66. metadata +138 -0
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class Object
5
+ def initialize(attributes)
6
+ @attributes = OpenStruct.new(attributes)
7
+ end
8
+
9
+ def method_missing(method, *args, &block)
10
+ attribute = @attributes.send(method, *args, &block)
11
+ attribute.is_a?(Hash) ? Object.new(attribute) : attribute
12
+ end
13
+
14
+ def respond_to_missing?(method, include_private = false)
15
+ true
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class Alarm < Object
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class AlarmNote < Object
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class CsldResult < Object
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class EnvironmentalSitegroup < Object
5
+ def sites
6
+ @attributes.sites.map { |site| Site.new(site) }
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class InventorySitegroup < Object
5
+ def sites
6
+ @attributes.sites.map { |site| Site.new(site) }
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class LineLeakResult < Object
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class NotificationCode < Object
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class NotificationContact < Object
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class NotificationRule < Object
5
+ def contacts
6
+ @attributes.contacts.map { |contact| NotificationContact.new(contact) }
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class NotificationRuleContact < Object
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class NotificationSite < Object
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class SensorStatusResult < Object
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class Site < Object
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class SitegroupInventoryDashboard < Object
5
+ def sites
6
+ @attributes.sites.map { |site| Site.new(site) }
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class Tank < Object
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class TankDailyUsageRecord < Object
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class TankDeliveryRecord < Object
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class TankInventoryRecord < Object
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class TankLeakResult < Object
5
+ end
6
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class TankReconciliationRecord < Object
5
+ def name
6
+ [tank_number, product_name].join(" - ")
7
+ end
8
+
9
+ def tank_number
10
+ tank_numbers.join(", ")
11
+ end
12
+
13
+ def started_at
14
+ DateTime.parse(start_date_time)
15
+ end
16
+
17
+ def is_missing?
18
+ is_missing
19
+ end
20
+
21
+ def book_inventory
22
+ (start_volume + deliveries_volume) - sales_volume
23
+ end
24
+
25
+ # Used for Weekly reconciliation
26
+ def removed_from_ust
27
+ (start_volume + deliveries_volume) - end_volume
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class TankRule < Object
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class TankRunoutRecord < Object
5
+ end
6
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class Resource
5
+ attr_reader :client
6
+
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def get_request(url, params: {}, headers: {})
12
+ handle_response client.connection.get(url, params, default_headers.merge(headers))
13
+ end
14
+
15
+ def post_request(url, body:, headers: {})
16
+ handle_response client.connection.post(url, body, default_headers.merge(headers))
17
+ end
18
+
19
+ def patch_request(url, body:, headers: {})
20
+ handle_response client.connection.patch(url, body, default_headers.merge(headers))
21
+ end
22
+
23
+ def put_request(url, body:, headers: {})
24
+ handle_response client.connection.put(url, body, default_headers.merge(headers))
25
+ end
26
+
27
+ def delete_request(url, params: {}, headers: {})
28
+ handle_response client.connection.delete(url, params, default_headers.merge(headers))
29
+ end
30
+
31
+ private
32
+
33
+ def enforce_required_attributes(required_attrs:, attrs:)
34
+ attr_keys = attrs.keys
35
+ required_attrs_present = required_attrs.all? { |req_attr| attr_keys.include?(req_attr) }
36
+
37
+ unless required_attrs_present
38
+ missing_attrs = required_attrs - attr_keys
39
+ error_message = "You must provide values for all required attributes: #{missing_attrs.join(", ")}"
40
+ raise MissingRequiredAttributeError, error_message
41
+ end
42
+ end
43
+
44
+ def default_headers
45
+ {Authorization: "Bearer #{client.api_key}"}
46
+ end
47
+
48
+ def handle_response(response)
49
+ message = response.body
50
+
51
+ case response.status
52
+ when 400
53
+ raise Error, "Your request was malformed - #{message}"
54
+ when 401
55
+ raise Error, "You did not supply valid authentication credentials - #{message}"
56
+ when 403
57
+ raise RequestForbiddenError, "You are not allowed to perform that action - #{message}"
58
+ when 404
59
+ raise Error, "This resource could not be found"
60
+ when 429
61
+ raise Error, "Your request exceeded the API rate limit - #{message}"
62
+ when 500
63
+ raise InternalServerError, "We were unable to perform the request due to server-side problems - #{message}"
64
+ end
65
+
66
+ response
67
+ end
68
+ end
69
+
70
+ class MissingRequiredAttributeError < Error; end
71
+
72
+ class RequestForbiddenError < Error; end
73
+
74
+ class InternalServerError < Error; end
75
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class ActiveAlarmsResource < Resource
5
+ def list(site_id: nil, **params)
6
+ response = get_request("api/alarms", params: params)
7
+
8
+ if site_id.nil?
9
+ Collection.from_response(response, type: Alarm)
10
+ else
11
+ Collection.from_response(
12
+ response,
13
+ type: Alarm,
14
+ filter_attribute: :site_id,
15
+ filter_value: site_id
16
+ )
17
+ end
18
+ end
19
+
20
+ def list_notes(alarm_id:)
21
+ response = get_request("api/alarms/#{alarm_id}/notes")
22
+ Collection.from_response(response, type: AlarmNote)
23
+ end
24
+
25
+ def retrieve(alarm_id:)
26
+ Alarm.new get_request("api/alarms/#{alarm_id}").body
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class AlarmHistoryResource < Resource
5
+ def list(site_id: nil, **params)
6
+ response =
7
+ if site_id.nil?
8
+ get_request("api/alarmhistory", params: params)
9
+ else
10
+ get_request("api/sites/#{site_id}/alarmhistory", params: params)
11
+ end
12
+
13
+ Collection.from_response(response, type: Alarm)
14
+ end
15
+
16
+ def list_notes(alarm_id:)
17
+ response = get_request("api/alarmhistory/#{alarm_id}/notes")
18
+ Collection.from_response(response, type: AlarmNote)
19
+ end
20
+
21
+ def retrieve(alarm_id:)
22
+ Alarm.new get_request("api/alarmhistory/#{alarm_id}").body
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class AlarmNotesResource < Resource
5
+ def create(alarm_id:, **attributes)
6
+ AlarmNote.new post_request("api/alarmhistory/#{alarm_id}/notes", body: attributes).body
7
+ end
8
+
9
+ def delete(alarm_id:, note_id:)
10
+ delete_request("api/alarmhistory/#{alarm_id}/notes/#{note_id}")
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class CsldResultsResource < Resource
5
+ def list(site_id:, **params)
6
+ response = get_request("api/environmental/sites/#{site_id}/csldstatuses", params: params)
7
+ Collection.from_response(response, type: CsldResult)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class EnvironmentalSitegroupsResource < Resource
5
+ def list(environmental: true)
6
+ Collection.from_response(get_request("api/environmental/sitegroups"), type: EnvironmentalSitegroup)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class InventorySitegroupsResource < Resource
5
+ def list(environmental: true)
6
+ Collection.from_response(get_request("api/sitegroups"), type: InventorySitegroup)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class LineLeakResultsResource < Resource
5
+ def list(site_id:, **params)
6
+ response = get_request("api/environmental/sites/#{site_id}/lineleaks", params: params)
7
+ Collection.from_response(response, type: LineLeakResult)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class NotificationContactsResource < Resource
5
+ def list
6
+ response = get_request("api/admin/notificationcontacts")
7
+ Collection.from_response(response, type: NotificationContact)
8
+ end
9
+
10
+ def list_sites(contact_id:)
11
+ response = get_request("api/admin/notificationcontacts/#{contact_id}/sites")
12
+ Collection.from_response(response, type: NotificationSite)
13
+ end
14
+
15
+ def retrieve(contact_id:)
16
+ NotificationContact.new get_request("api/admin/notificationcontacts/#{contact_id}").body
17
+ end
18
+
19
+ def update(contact_id:, **attributes)
20
+ request = put_request("api/admin/notificationcontacts/#{contact_id}", body: attributes)
21
+ NotificationContact.new request.body
22
+ end
23
+
24
+ def create(**attributes)
25
+ NotificationContact.new post_request("api/admin/notificationcontacts", body: attributes).body
26
+ end
27
+
28
+ def delete(contact_id:)
29
+ NotificationContact.new delete_request("api/admin/notificationcontacts/#{contact_id}").body
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class NotificationRulesResource < Resource
5
+ def list_codes
6
+ response = get_request("api/admin/notificationrules/codes")
7
+ Collection.from_response(response, type: NotificationCode)
8
+ end
9
+
10
+ def list_contacts(rule_id:)
11
+ response = get_request("api/admin/notificationrules/#{rule_id}/contacts")
12
+ Collection.from_response(response, type: NotificationRuleContact)
13
+ end
14
+
15
+ def list(code_id:)
16
+ response = get_request("api/admin/notificationrules?codeId=#{code_id}")
17
+ Collection.from_response(response, type: NotificationRule)
18
+ end
19
+
20
+ def update(rule_id:, **attributes)
21
+ put_request("api/admin/notificationrules/#{rule_id}", body: attributes)
22
+ end
23
+
24
+ def delete(rule_id:)
25
+ delete_request("api/admin/notificationrules/#{rule_id}")
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class SensorStatusResultsResource < Resource
5
+ def list(site_id:, **params)
6
+ response = get_request("api/environmental/sites/#{site_id}/sensorstatuses", params: params)
7
+ Collection.from_response(response, type: SensorStatusResult)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class SitegroupInventoryDashboardsResource < Resource
5
+ def list(sitegroup_id:)
6
+ Collection.from_response(
7
+ get_request("api/sitegroups/#{sitegroup_id}/inventory/dashboard"),
8
+ type: SitegroupInventoryDashboard
9
+ )
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class TankDailyUsageResource < Resource
5
+ def list(tank_id:)
6
+ response = get_request("api/tanks/#{tank_id}/dailyusage")
7
+ Collection.from_response(response, type: TankDailyUsageRecord)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class TankDeliveriesResource < Resource
5
+ def list(tank_id:, **params)
6
+ response = get_request("api/tanks/#{tank_id}/deliveries", params: params)
7
+ Collection.from_response(response, type: TankDeliveryRecord)
8
+ end
9
+
10
+ def update(tank_id:, delivery_id:, **attributes)
11
+ required_attributes = [
12
+ :start_date_and_time,
13
+ :start_gross,
14
+ :stop_date_and_time,
15
+ :stop_gross,
16
+ :delivery_net,
17
+ :delivery_gross,
18
+ :bol_number
19
+ ]
20
+
21
+ enforce_required_attributes(required_attrs: required_attributes, attrs: attributes)
22
+
23
+ request = put_request("api/tanks/#{tank_id}/deliveries/#{delivery_id}", body: attributes)
24
+ TankDeliveryRecord.new request.body
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class TankInventoryResource < Resource
5
+ def list(tank_id:, **params)
6
+ response = get_request("api/tanks/#{tank_id}/inventory", params: params)
7
+ Collection.from_response(response, type: TankInventoryRecord)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class TankLeakResultsResource < Resource
5
+ def list(site_id:, **params)
6
+ response = get_request("api/environmental/sites/#{site_id}/tankleaks", params: params)
7
+ Collection.from_response(response, type: TankLeakResult)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class TankReconciliationRecordsResource < Resource
5
+ def list(site_id:, reconciliation_period:, **params)
6
+ response = get_request("api/recon/sites/#{site_id}", params: params)
7
+ TankReconciliationRecordCollection.from_response(
8
+ response,
9
+ reconciliation_period: reconciliation_period
10
+ )
11
+ end
12
+
13
+ def retrieve(site_id:, reconciliation_period:, started_at:)
14
+ date =
15
+ if started_at.instance_of?(DateTime) ||
16
+ started_at.instance_of?(Date) ||
17
+ started_at.instance_of?(Time)
18
+ started_at.strftime(MYTI_DATE_TIME_FORMAT)
19
+ else
20
+ started_at
21
+ end
22
+
23
+ response = get_request("api/recon/sites/#{site_id}/#{date}")
24
+ TankReconciliationRecordCollection.from_response(
25
+ response,
26
+ reconciliation_period: reconciliation_period
27
+ )
28
+ end
29
+
30
+ def update(site_id:, started_at:, **attributes)
31
+ put("api/recon/sites/#{site_id}/#{date}", body: attributes)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class TankRulesResource < Resource
5
+ def list(tank_id:)
6
+ response = get_request("/api/tanks/#{tank_id}/rules")
7
+ Collection.from_response(response, type: TankRule)
8
+ end
9
+
10
+ def update(tank_id:, attributes:)
11
+ response = put_request("api/tanks/#{tank_id}/rules", body: attributes)
12
+ Collection.from_response(response, type: TankRule)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class TankRunoutResource < Resource
5
+ def list(tank_id:)
6
+ response = get_request("api/tanks/#{tank_id}/runout")
7
+ Collection.from_response(response, type: TankRunoutRecord)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyTankInfo
4
+ class TanksResource < Resource
5
+ def list(site_id: nil)
6
+ response = get_request("api/tanks")
7
+
8
+ if site_id.nil?
9
+ Collection.from_response(response, type: Tank)
10
+ else
11
+ Collection.from_response(
12
+ response,
13
+ type: Tank,
14
+ filter_attribute: :site_id,
15
+ filter_value: site_id
16
+ )
17
+ end
18
+ end
19
+
20
+ def retrieve(tank_id:)
21
+ Tank.new get_request("api/tanks/#{tank_id}").body
22
+ end
23
+ end
24
+ end