speedy-bg 0.1.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 (148) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +3 -0
  3. data/CODE_OF_CONDUCT.md +134 -0
  4. data/CONTRIBUTING.md +67 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +150 -0
  7. data/SECURITY.md +29 -0
  8. data/docs/API.md +740 -0
  9. data/docs/RESPONSE_CONTRACTS.md +55 -0
  10. data/docs/VCR.md +161 -0
  11. data/docs/schema-notes.md +38 -0
  12. data/lib/speedy/camel_case_middleware.rb +71 -0
  13. data/lib/speedy/client.rb +100 -0
  14. data/lib/speedy/client_resources.rb +776 -0
  15. data/lib/speedy/collection.rb +58 -0
  16. data/lib/speedy/error.rb +29 -0
  17. data/lib/speedy/model.rb +92 -0
  18. data/lib/speedy/models/calculation/address_location.rb +16 -0
  19. data/lib/speedy/models/calculation/calculation_content.rb +15 -0
  20. data/lib/speedy/models/calculation/calculation_recipient.rb +15 -0
  21. data/lib/speedy/models/calculation/calculation_result.rb +19 -0
  22. data/lib/speedy/models/calculation/calculation_sender.rb +16 -0
  23. data/lib/speedy/models/calculation/calculation_service.rb +16 -0
  24. data/lib/speedy/models/clients/client.rb +21 -0
  25. data/lib/speedy/models/clients/cod_contract_info.rb +16 -0
  26. data/lib/speedy/models/clients/cod_international_annex.rb +12 -0
  27. data/lib/speedy/models/clients/contract_info.rb +16 -0
  28. data/lib/speedy/models/clients/requirement.rb +12 -0
  29. data/lib/speedy/models/clients/special_delivery_requirements.rb +12 -0
  30. data/lib/speedy/models/common/address.rb +36 -0
  31. data/lib/speedy/models/error.rb +37 -0
  32. data/lib/speedy/models/location/address_nomenclature_type.rb +12 -0
  33. data/lib/speedy/models/location/block.rb +15 -0
  34. data/lib/speedy/models/location/complex.rb +23 -0
  35. data/lib/speedy/models/location/country.rb +25 -0
  36. data/lib/speedy/models/location/find_office_response.rb +12 -0
  37. data/lib/speedy/models/location/find_site_response.rb +12 -0
  38. data/lib/speedy/models/location/get_office_response.rb +12 -0
  39. data/lib/speedy/models/location/get_site_response.rb +12 -0
  40. data/lib/speedy/models/location/office.rb +41 -0
  41. data/lib/speedy/models/location/office_result.rb +13 -0
  42. data/lib/speedy/models/location/office_working_time_schedule.rb +15 -0
  43. data/lib/speedy/models/location/point_of_interest.rb +22 -0
  44. data/lib/speedy/models/location/postcode.rb +12 -0
  45. data/lib/speedy/models/location/routing_information.rb +14 -0
  46. data/lib/speedy/models/location/site.rb +30 -0
  47. data/lib/speedy/models/location/state.rb +17 -0
  48. data/lib/speedy/models/location/street.rb +23 -0
  49. data/lib/speedy/models/location/tour.rb +14 -0
  50. data/lib/speedy/models/payments/payout.rb +20 -0
  51. data/lib/speedy/models/payments/payout_details.rb +23 -0
  52. data/lib/speedy/models/pickup/pickup_order.rb +16 -0
  53. data/lib/speedy/models/pickup/terms_response.rb +12 -0
  54. data/lib/speedy/models/print/extended_print_response.rb +13 -0
  55. data/lib/speedy/models/print/label_info.rb +19 -0
  56. data/lib/speedy/models/print/label_info_response.rb +12 -0
  57. data/lib/speedy/models/print/parcel_to_print_additional_barcode.rb +14 -0
  58. data/lib/speedy/models/print/print_response.rb +12 -0
  59. data/lib/speedy/models/response.rb +13 -0
  60. data/lib/speedy/models/services/additional_courier_service.rb +11 -0
  61. data/lib/speedy/models/services/additional_courier_services.rb +21 -0
  62. data/lib/speedy/models/services/courier_service.rb +19 -0
  63. data/lib/speedy/models/services/extended_courier_service.rb +13 -0
  64. data/lib/speedy/models/shipments/bank_account.rb +12 -0
  65. data/lib/speedy/models/shipments/barcode_information.rb +20 -0
  66. data/lib/speedy/models/shipments/cod_payment.rb +12 -0
  67. data/lib/speedy/models/shipments/content.rb +20 -0
  68. data/lib/speedy/models/shipments/create_shipment_response.rb +16 -0
  69. data/lib/speedy/models/shipments/created_shipment_parcel.rb +14 -0
  70. data/lib/speedy/models/shipments/external_carrier_parcel_number.rb +12 -0
  71. data/lib/speedy/models/shipments/goods_item.rb +16 -0
  72. data/lib/speedy/models/shipments/money_transfer_premium.rb +13 -0
  73. data/lib/speedy/models/shipments/parcel.rb +22 -0
  74. data/lib/speedy/models/shipments/payment.rb +16 -0
  75. data/lib/speedy/models/shipments/primary_shipment.rb +12 -0
  76. data/lib/speedy/models/shipments/recipient.rb +21 -0
  77. data/lib/speedy/models/shipments/return_amounts.rb +11 -0
  78. data/lib/speedy/models/shipments/secondary_shipment.rb +18 -0
  79. data/lib/speedy/models/shipments/sender.rb +21 -0
  80. data/lib/speedy/models/shipments/shipment.rb +28 -0
  81. data/lib/speedy/models/shipments/shipment_additional_services.rb +17 -0
  82. data/lib/speedy/models/shipments/shipment_address.rb +10 -0
  83. data/lib/speedy/models/shipments/shipment_cod_additional_service.rb +20 -0
  84. data/lib/speedy/models/shipments/shipment_cod_fiscal_receipt_item.rb +14 -0
  85. data/lib/speedy/models/shipments/shipment_content.rb +24 -0
  86. data/lib/speedy/models/shipments/shipment_declared_value_additional_service.rb +13 -0
  87. data/lib/speedy/models/shipments/shipment_delivery.rb +14 -0
  88. data/lib/speedy/models/shipments/shipment_discount_card_id.rb +12 -0
  89. data/lib/speedy/models/shipments/shipment_electronic_return_receipt_additional_service.rb +14 -0
  90. data/lib/speedy/models/shipments/shipment_obpd.rb +13 -0
  91. data/lib/speedy/models/shipments/shipment_parcel.rb +23 -0
  92. data/lib/speedy/models/shipments/shipment_parcel_number.rb +12 -0
  93. data/lib/speedy/models/shipments/shipment_parcel_ref.rb +13 -0
  94. data/lib/speedy/models/shipments/shipment_parcel_size.rb +13 -0
  95. data/lib/speedy/models/shipments/shipment_payment.rb +17 -0
  96. data/lib/speedy/models/shipments/shipment_phone_number.rb +12 -0
  97. data/lib/speedy/models/shipments/shipment_price.rb +23 -0
  98. data/lib/speedy/models/shipments/shipment_price_amount.rb +13 -0
  99. data/lib/speedy/models/shipments/shipment_recipient.rb +14 -0
  100. data/lib/speedy/models/shipments/shipment_return_additional_services.rb +20 -0
  101. data/lib/speedy/models/shipments/shipment_return_receipt_additional_service.rb +14 -0
  102. data/lib/speedy/models/shipments/shipment_return_voucher_additional_service.rb +14 -0
  103. data/lib/speedy/models/shipments/shipment_rod_additional_service.rb +15 -0
  104. data/lib/speedy/models/shipments/shipment_rop_additional_service.rb +12 -0
  105. data/lib/speedy/models/shipments/shipment_rop_additional_service_line.rb +12 -0
  106. data/lib/speedy/models/shipments/shipment_sender.rb +23 -0
  107. data/lib/speedy/models/shipments/shipment_service.rb +17 -0
  108. data/lib/speedy/models/shipments/shipment_swap_additional_service.rb +17 -0
  109. data/lib/speedy/models/shipments/update_shipment_response.rb +10 -0
  110. data/lib/speedy/models/tracking/bulk_tracking_data_file.rb +14 -0
  111. data/lib/speedy/models/tracking/external_carrier_parcel_number_details.rb +13 -0
  112. data/lib/speedy/models/tracking/tracked_parcel.rb +21 -0
  113. data/lib/speedy/models/tracking/tracked_parcel_operation.rb +22 -0
  114. data/lib/speedy/models/tracking/tracked_parcel_operation_additional_info.rb +17 -0
  115. data/lib/speedy/models/tracking/tracked_parcel_operation_additional_info_predict.rb +14 -0
  116. data/lib/speedy/models/tracking/tracked_parcel_operation_additional_info_recipient.rb +14 -0
  117. data/lib/speedy/models/validation/validation_response.rb +14 -0
  118. data/lib/speedy/resource_attributes.rb +87 -0
  119. data/lib/speedy/service_resource.rb +94 -0
  120. data/lib/speedy/services/calculation.rb +22 -0
  121. data/lib/speedy/services/clients.rb +40 -0
  122. data/lib/speedy/services/courier_services.rb +25 -0
  123. data/lib/speedy/services/location/block.rb +32 -0
  124. data/lib/speedy/services/location/complex.rb +39 -0
  125. data/lib/speedy/services/location/country.rb +70 -0
  126. data/lib/speedy/services/location/office.rb +50 -0
  127. data/lib/speedy/services/location/point_of_interest.rb +39 -0
  128. data/lib/speedy/services/location/postcode.rb +25 -0
  129. data/lib/speedy/services/location/site.rb +77 -0
  130. data/lib/speedy/services/location/state.rb +46 -0
  131. data/lib/speedy/services/location/street.rb +39 -0
  132. data/lib/speedy/services/location.rb +11 -0
  133. data/lib/speedy/services/payments.rb +19 -0
  134. data/lib/speedy/services/pickup.rb +38 -0
  135. data/lib/speedy/services/print.rb +58 -0
  136. data/lib/speedy/services/shipments/shipment.rb +120 -0
  137. data/lib/speedy/services/shipments.rb +11 -0
  138. data/lib/speedy/services/tracking.rb +26 -0
  139. data/lib/speedy/services/validation/address.rb +26 -0
  140. data/lib/speedy/services/validation/general.rb +37 -0
  141. data/lib/speedy/services/validation.rb +11 -0
  142. data/lib/speedy/transport_error.rb +17 -0
  143. data/lib/speedy/util.rb +67 -0
  144. data/lib/speedy/version.rb +5 -0
  145. data/lib/speedy-bg.rb +6 -0
  146. data/lib/speedy.rb +203 -0
  147. data/sig/speedy.rbs +374 -0
  148. metadata +227 -0
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module Speedy
6
+ module ResourceAttributes
7
+ TYPE_CASTERS = {
8
+ integer: ->(value) { blank?(value) ? nil : value.to_i },
9
+ string: ->(value) { value&.to_s },
10
+ boolean: lambda do |value|
11
+ next nil if blank?(value)
12
+ next false if value == false || %w[false 0 no off].include?(value.to_s.downcase)
13
+
14
+ true
15
+ end,
16
+ float: ->(value) { blank?(value) ? nil : value.to_f }
17
+ }.freeze
18
+
19
+ def self.blank?(value)
20
+ value.nil? || (value.is_a?(String) && value.strip.empty?)
21
+ end
22
+
23
+ def self.included(base)
24
+ base.extend(ClassMethods)
25
+ end
26
+
27
+ module ClassMethods
28
+ def fields
29
+ @fields ||= {}
30
+ end
31
+
32
+ def field(name, opts = {})
33
+ fields[name] = opts
34
+
35
+ define_method(name) do
36
+ cast_attribute(@attributes[name], opts[:type], opts[:of])
37
+ end
38
+
39
+ define_method("#{name}=") do |value|
40
+ @attributes[name] = cast_attribute(value, opts[:type], opts[:of])
41
+ end
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def cast_attribute(value, type, collection_type = nil)
48
+ return cast_primitive(value, type) if TYPE_CASTERS.key?(type)
49
+ return cast_date(value) if type == :date
50
+ return cast_array(value, collection_type) if type == :array
51
+ return cast_hash(value, collection_type) if type == :hash
52
+
53
+ return cast_model(value, type) if type.is_a?(Class)
54
+
55
+ value
56
+ end
57
+
58
+ def cast_primitive(value, type)
59
+ TYPE_CASTERS.fetch(type).call(value)
60
+ end
61
+
62
+ def cast_model(value, type)
63
+ value.nil? || value.is_a?(type) ? value : type.new(value)
64
+ end
65
+
66
+ def cast_date(value)
67
+ return value if value.nil? || value.is_a?(Date)
68
+
69
+ Date.parse(value.to_s)
70
+ rescue StandardError
71
+ value
72
+ end
73
+
74
+ def cast_array(value, collection_type)
75
+ values = Array(value)
76
+ return values unless collection_type.is_a?(Class)
77
+
78
+ values.map { |item| item.is_a?(collection_type) ? item : collection_type.new(item) }
79
+ end
80
+
81
+ def cast_hash(value, value_type)
82
+ return value unless value.is_a?(Hash) && value_type.is_a?(Class)
83
+
84
+ value.transform_values { |item| item.is_a?(value_type) ? item : value_type.new(item) }
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Speedy
4
+ class ServiceResource
5
+ attr_reader :client
6
+
7
+ class << self
8
+ def resource_path(value = nil)
9
+ return @resource_path unless value
10
+
11
+ @resource_path = value
12
+ end
13
+ end
14
+
15
+ ERROR_MESSAGES = {
16
+ 400 => 'Your request was malformed.',
17
+ 401 => 'You did not supply valid authentication credentials.',
18
+ 403 => 'You are not allowed to perform that action.',
19
+ 404 => 'No results were found for your request.',
20
+ 429 => 'Your request exceeded the API rate limit.',
21
+ 500 => 'We were unable to perform the request due to server-side problems.',
22
+ 503 => 'The Speedy API is currently unavailable.'
23
+ }.freeze
24
+
25
+ def initialize(client: Speedy::Client.instance)
26
+ message = 'Speedy::Client is not configured. Call `Speedy::Client.configure` first.'
27
+
28
+ @client = client || raise(message)
29
+ end
30
+
31
+ def resource_url
32
+ self.class.resource_path
33
+ end
34
+
35
+ private
36
+
37
+ def get(url = nil, params: {}, headers: {})
38
+ response_for(with_transport_errors { client.connection.get(url_for(url), params, headers) })
39
+ end
40
+
41
+ def post(url = nil, body: nil, headers: {})
42
+ response_for(with_transport_errors { client.connection.post(url_for(url), request_body(body), headers) })
43
+ end
44
+
45
+ def delete(url = nil, params: {}, headers: {})
46
+ response_for(with_transport_errors { client.connection.delete(url_for(url), params, headers) })
47
+ end
48
+
49
+ def with_transport_errors
50
+ yield
51
+ rescue Faraday::TimeoutError => e
52
+ raise TimeoutError, 'Speedy API request timed out.', cause: e
53
+ rescue Faraday::ConnectionFailed => e
54
+ raise ConnectionError, 'Could not connect to the Speedy API.', cause: e
55
+ rescue Faraday::SSLError => e
56
+ raise SSLError, 'Speedy API TLS connection failed.', cause: e
57
+ end
58
+
59
+ def url_for(url)
60
+ [resource_url, url].compact.reject(&:empty?).join('/')
61
+ end
62
+
63
+ def request_body(body)
64
+ client.credentials.merge(body || {})
65
+ end
66
+
67
+ def response_for(response)
68
+ error = error_from(response.body)
69
+ raise Error.new(error: error, status: response.status) if error && !successful_response?(response)
70
+
71
+ error_message = ERROR_MESSAGES[response.status]
72
+ raise Error.new(error_message, status: response.status) if error_message
73
+ raise Error.new(status: response.status) unless successful_response?(response)
74
+
75
+ response
76
+ end
77
+
78
+ def collection(response, model)
79
+ model.collection(response.body)
80
+ end
81
+
82
+ def resource(response, model, key: nil)
83
+ model.build(response.body, key: key)
84
+ end
85
+
86
+ def error_from(body)
87
+ Speedy::Models::Error.build_from(body)
88
+ end
89
+
90
+ def successful_response?(response)
91
+ response.status.to_i.between?(200, 299)
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Speedy
4
+ module Services
5
+ class Calculation < Speedy::ServiceResource
6
+ resource_path 'calculate'
7
+
8
+ # POST `/calculate`
9
+ def calculate(recipient:, service:, content:, payment:, sender: nil, **options)
10
+ response = post(body: {
11
+ sender: sender,
12
+ recipient: recipient,
13
+ service: service,
14
+ content: content,
15
+ payment: payment
16
+ }.merge(options).compact)
17
+
18
+ collection(response, Speedy::Models::Calculation::CalculationResult)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Speedy
4
+ module Services
5
+ class Clients < Speedy::ServiceResource
6
+ resource_path 'client'
7
+
8
+ def get(id)
9
+ response = post(id.to_s)
10
+ resource(response, Speedy::Models::Clients::Client, key: :client)
11
+ end
12
+
13
+ def own_id
14
+ response = post
15
+ response.body[:client_id] || response.body['client_id'] || response.body['clientId']
16
+ end
17
+
18
+ def contract_clients
19
+ response = post('contract')
20
+ collection(response, Speedy::Models::Clients::Client)
21
+ end
22
+
23
+ def create_contact(**attributes)
24
+ response = post('contact', body: attributes.compact)
25
+
26
+ response.body[:client_id] || response.body['client_id'] || response.body['clientId']
27
+ end
28
+
29
+ def contact_by_external_id(id:, secret_key:)
30
+ response = post("contact/external/#{id}", body: { secret_key: secret_key })
31
+ resource(response, Speedy::Models::Clients::Client, key: :client)
32
+ end
33
+
34
+ def contract_info
35
+ response = post('contract/info')
36
+ resource(response, Speedy::Models::Clients::ContractInfo)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Speedy
4
+ module Services
5
+ class CourierServices < Speedy::ServiceResource
6
+ resource_path 'services'
7
+
8
+ # POST `/services`
9
+ def all(date: nil)
10
+ response = post(body: { date: date }.compact)
11
+
12
+ collection(response, Speedy::Models::Services::CourierService)
13
+ end
14
+
15
+ # POST `/services/destination`
16
+ def for_destination(sender:, recipient:, date: nil)
17
+ response = post('destination', body: {
18
+ date: date, sender: sender, recipient: recipient
19
+ }.compact)
20
+
21
+ collection(response, Speedy::Models::Services::ExtendedCourierService)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+
5
+ module Speedy
6
+ module Services
7
+ module Location
8
+ class Block < Speedy::ServiceResource
9
+ resource_path 'location/block'
10
+
11
+ # POST `/location/block`
12
+ def find(site_id:, name: nil)
13
+ response = post(body: { site_id: site_id, name: name }.compact)
14
+
15
+ collection(response, Speedy::Models::Location::Block)
16
+ end
17
+
18
+ # POST `/location/block/csv/{countryId}`
19
+ def all(country_id:)
20
+ response = post("csv/#{country_id}")
21
+ rows = CSV.parse(response.body.to_s).filter_map do |row|
22
+ next if row.compact.empty? || row.first.to_s == 'siteId'
23
+
24
+ %i[site_id name name_en].zip(row).to_h
25
+ end
26
+
27
+ Speedy::Models::Location::Block.collection(rows)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+
5
+ module Speedy
6
+ module Services
7
+ module Location
8
+ class Complex < Speedy::ServiceResource
9
+ resource_path 'location/complex'
10
+
11
+ # POST `/location/complex/{id}`
12
+ def get(id)
13
+ response = post(id.to_s)
14
+
15
+ resource(response, Speedy::Models::Location::Complex, key: :complex)
16
+ end
17
+
18
+ # POST `/location/complex`
19
+ def find(site_id:, name: nil, type: nil)
20
+ response = post(body: { site_id: site_id, name: name, type: type }.compact)
21
+
22
+ collection(response, Speedy::Models::Location::Complex)
23
+ end
24
+
25
+ # POST `/location/complex/csv/{countryId}`
26
+ def all(country_id:)
27
+ response = post("csv/#{country_id}")
28
+ rows = CSV.parse(response.body.to_s).filter_map do |row|
29
+ next if row.compact.empty? || row.first.to_s == 'id'
30
+
31
+ %i[id site_id type type_en name name_en actual_id].zip(row).to_h
32
+ end
33
+
34
+ Speedy::Models::Location::Complex.collection(rows)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+
5
+ module Speedy
6
+ module Services
7
+ module Location
8
+ class Country < Speedy::ServiceResource
9
+ resource_path 'location/country'
10
+
11
+ # POST `/location/country`
12
+ def find(name: nil, iso_alpha2: nil, iso_alpha3: nil)
13
+ response = post(body: {
14
+ name: name, iso_alpha2: iso_alpha2, iso_alpha3: iso_alpha3
15
+ }.compact)
16
+
17
+ collection(response, Speedy::Models::Location::Country)
18
+ end
19
+
20
+ # POST `/location/country/{id}`
21
+ def get(id)
22
+ response = post(id.to_s)
23
+
24
+ resource(response, Speedy::Models::Location::Country, key: :country)
25
+ end
26
+
27
+ # POST `/location/country/csv`
28
+ def all
29
+ response = post('csv')
30
+ Speedy::Models::Location::Country.collection(csv_countries(response.body))
31
+ end
32
+
33
+ CSV_FIELDS = %i[
34
+ id name name_en iso_alpha2 iso_alpha3 post_code_formats require_state address_type
35
+ currency_code default_office_id street_types street_types_en complex_types
36
+ complex_types_en site_nomen
37
+ ].freeze
38
+
39
+ private
40
+
41
+ def csv_countries(body)
42
+ CSV.parse(body.to_s).filter_map do |row|
43
+ next if row.compact.empty? || row.first.to_s == 'id'
44
+
45
+ country_attributes(row)
46
+ end
47
+ end
48
+
49
+ def country_attributes(row)
50
+ attributes = CSV_FIELDS.zip(row).to_h
51
+ attributes[:post_code_formats] = csv_list(attributes[:post_code_formats])
52
+ %i[street complex].each do |kind|
53
+ attributes[:"#{kind}_types"] = nomenclature(
54
+ attributes.delete(:"#{kind}_types"), attributes.delete(:"#{kind}_types_en")
55
+ )
56
+ end
57
+ attributes
58
+ end
59
+
60
+ def csv_list(value)
61
+ value.to_s.split(',').map(&:strip).reject(&:empty?)
62
+ end
63
+
64
+ def nomenclature(names, english_names)
65
+ csv_list(names).zip(csv_list(english_names)).map { |name, name_en| { name: name, name_en: name_en } }
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Speedy
4
+ module Services
5
+ module Location
6
+ class Office < Speedy::ServiceResource
7
+ include Speedy::Services::Location
8
+
9
+ resource_path 'location/office'
10
+
11
+ # POST `/location/office`
12
+ def find(country_id: nil, site_id: nil, site_name: nil, name: nil, limit: nil)
13
+ response = post(body: {
14
+ country_id: country_id,
15
+ site_id: site_id,
16
+ site_name: site_name,
17
+ name: name,
18
+ limit: limit
19
+ }.compact)
20
+
21
+ collection(response, Speedy::Models::Location::Office)
22
+ end
23
+
24
+ # POST `/location/office/{id}`
25
+ def get(id)
26
+ response = post(id.to_s)
27
+
28
+ resource(response, Speedy::Models::Location::GetOfficeResponse)
29
+ end
30
+
31
+ # POST `/location/office/nearest-offices`
32
+ def nearest(address:, distance: nil, limit: nil, office_type: nil, office_features: nil)
33
+ response = post('nearest-offices', body: {
34
+ address: address,
35
+ distance: distance,
36
+ limit: limit,
37
+ office_type: office_type,
38
+ office_features: office_features
39
+ }.compact)
40
+
41
+ collection(response, Speedy::Models::Location::OfficeResult)
42
+ end
43
+
44
+ alias find_offices find
45
+ alias get_office get
46
+ alias nearest_offices nearest
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+
5
+ module Speedy
6
+ module Services
7
+ module Location
8
+ class PointOfInterest < Speedy::ServiceResource
9
+ resource_path 'location/poi'
10
+
11
+ # POST `/location/poi/{id}`
12
+ def get(id)
13
+ response = post(id.to_s)
14
+
15
+ resource(response, Speedy::Models::Location::PointOfInterest, key: :poi)
16
+ end
17
+
18
+ # POST `/location/poi`
19
+ def find(site_id:, name: nil)
20
+ response = post(body: { site_id: site_id, name: name }.compact)
21
+
22
+ collection(response, Speedy::Models::Location::PointOfInterest)
23
+ end
24
+
25
+ # POST `/location/poi/csv/{countryId}`
26
+ def all(country_id:)
27
+ response = post("csv/#{country_id}")
28
+ rows = CSV.parse(response.body.to_s).filter_map do |row|
29
+ next if row.compact.empty? || row.first.to_s == 'id'
30
+
31
+ %i[id site_id name name_en address address_en x y type type_en].zip(row).to_h
32
+ end
33
+
34
+ Speedy::Models::Location::PointOfInterest.collection(rows)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+
5
+ module Speedy
6
+ module Services
7
+ module Location
8
+ class Postcode < Speedy::ServiceResource
9
+ resource_path 'location/postcode'
10
+
11
+ # POST `/location/postcode/csv/{countryId}`
12
+ def all(country_id:)
13
+ response = post("csv/#{country_id}")
14
+ rows = CSV.parse(response.body.to_s).filter_map do |row|
15
+ next if row.compact.empty? || row.first.to_s == 'postcode'
16
+
17
+ %i[postcode site_id].zip(row).to_h
18
+ end
19
+
20
+ Speedy::Models::Location::Postcode.collection(rows)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+
5
+ module Speedy
6
+ module Services
7
+ module Location
8
+ class Site < Speedy::ServiceResource
9
+ include Speedy::Services::Location
10
+
11
+ resource_path 'location/site'
12
+
13
+ # POST `/location/site`
14
+ def find(country_id: nil, name: nil, post_code: nil, type: nil, municipality: nil, region: nil)
15
+ response = post(body: {
16
+ country_id: country_id,
17
+ name: name,
18
+ post_code: post_code,
19
+ type: type,
20
+ municipality: municipality,
21
+ region: region
22
+ }.compact)
23
+
24
+ collection(response, Speedy::Models::Location::Site)
25
+ end
26
+
27
+ # POST `/location/site/{id}`
28
+ def get(id)
29
+ response = post(id.to_s)
30
+
31
+ resource(response, Speedy::Models::Location::GetSiteResponse)
32
+ end
33
+
34
+ # POST `/location/site/csv/{countryId}`
35
+ def all(country_id:)
36
+ response = post("csv/#{country_id}")
37
+
38
+ Speedy::Models::Location::Site.collection(csv_sites(response.body))
39
+ end
40
+
41
+ alias find_sites find
42
+ alias get_site get
43
+
44
+ CSV_FIELDS = %i[
45
+ id
46
+ country_id
47
+ main_site_id
48
+ type
49
+ type_en
50
+ name
51
+ name_en
52
+ municipality
53
+ municipality_en
54
+ region
55
+ region_en
56
+ post_code
57
+ address_nomenclature
58
+ x
59
+ y
60
+ serving_days
61
+ serving_office_id
62
+ serving_hub_office_id
63
+ ].freeze
64
+
65
+ private
66
+
67
+ def csv_sites(body)
68
+ CSV.parse(body.to_s).filter_map do |row|
69
+ next if row.compact.empty? || row.first.to_s == 'id'
70
+
71
+ CSV_FIELDS.zip(row).to_h
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+
5
+ module Speedy
6
+ module Services
7
+ module Location
8
+ class State < Speedy::ServiceResource
9
+ include Speedy::Services::Location
10
+
11
+ resource_path 'location/state'
12
+
13
+ # POST `/location/state/{id}`
14
+ def get(id)
15
+ response = post(id.to_s)
16
+
17
+ resource(response, Speedy::Models::Location::State, key: :state)
18
+ end
19
+
20
+ # POST `/location/state`
21
+ def find(country_id: nil, name: nil)
22
+ response = post(body: {
23
+ country_id: country_id,
24
+ name: name
25
+ }.compact)
26
+
27
+ collection(response, Speedy::Models::Location::State)
28
+ end
29
+
30
+ # POST `/location/state/csv/{countryId}`
31
+ def all(country_id:)
32
+ response = post("csv/#{country_id}")
33
+ rows = CSV.parse(response.body.to_s).filter_map do |row|
34
+ next if row.compact.empty? || row.first.to_s == 'id'
35
+
36
+ %i[id name name_en state_alpha country_id].zip(row).to_h
37
+ end
38
+
39
+ Speedy::Models::Location::State.collection(rows)
40
+ end
41
+
42
+ alias get_all_states all
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+
5
+ module Speedy
6
+ module Services
7
+ module Location
8
+ class Street < Speedy::ServiceResource
9
+ resource_path 'location/street'
10
+
11
+ # POST `/location/street`
12
+ def find(site_id:, name: nil, type: nil)
13
+ response = post(body: { site_id: site_id, name: name, type: type }.compact)
14
+
15
+ collection(response, Speedy::Models::Location::Street)
16
+ end
17
+
18
+ # POST `/location/street/{id}`
19
+ def get(id)
20
+ response = post(id.to_s)
21
+
22
+ resource(response, Speedy::Models::Location::Street, key: :street)
23
+ end
24
+
25
+ # POST `/location/street/csv/{countryId}`
26
+ def all(country_id:)
27
+ response = post("csv/#{country_id}")
28
+ rows = CSV.parse(response.body.to_s).filter_map do |row|
29
+ next if row.compact.empty? || row.first.to_s == 'id'
30
+
31
+ %i[id site_id type type_en name name_en actual_id].zip(row).to_h
32
+ end
33
+
34
+ Speedy::Models::Location::Street.collection(rows)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end