econt 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 (87) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +3 -0
  3. data/CODE_OF_CONDUCT.md +17 -0
  4. data/CONTRIBUTING.md +37 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +171 -0
  7. data/SECURITY.md +33 -0
  8. data/docs/API.md +571 -0
  9. data/docs/ENDPOINTS.md +42 -0
  10. data/docs/PUBLIC_API.md +81 -0
  11. data/docs/RELEASING.md +35 -0
  12. data/docs/RESPONSE_TESTS.md +46 -0
  13. data/docs/VCR.md +144 -0
  14. data/lib/econt/camel_case_middleware.rb +88 -0
  15. data/lib/econt/client.rb +99 -0
  16. data/lib/econt/collection.rb +59 -0
  17. data/lib/econt/error.rb +42 -0
  18. data/lib/econt/meta_resource.rb +6 -0
  19. data/lib/econt/model.rb +95 -0
  20. data/lib/econt/models/error.rb +53 -0
  21. data/lib/econt/models/hosted_file.rb +13 -0
  22. data/lib/econt/models/nomenclatures/address.rb +35 -0
  23. data/lib/econt/models/nomenclatures/address_service_info.rb +16 -0
  24. data/lib/econt/models/nomenclatures/address_service_times_response.rb +19 -0
  25. data/lib/econt/models/nomenclatures/address_validation_response.rb +19 -0
  26. data/lib/econt/models/nomenclatures/city.rb +32 -0
  27. data/lib/econt/models/nomenclatures/country.rb +16 -0
  28. data/lib/econt/models/nomenclatures/geo_location.rb +13 -0
  29. data/lib/econt/models/nomenclatures/office.rb +32 -0
  30. data/lib/econt/models/nomenclatures/quarter.rb +14 -0
  31. data/lib/econt/models/nomenclatures/serving_office_element.rb +12 -0
  32. data/lib/econt/models/nomenclatures/street.rb +14 -0
  33. data/lib/econt/models/nomenclatures/working_date_time.rb +16 -0
  34. data/lib/econt/models/nomenclatures/working_time.rb +12 -0
  35. data/lib/econt/models/payment_report/payment_report_row.rb +17 -0
  36. data/lib/econt/models/profile/cd_pay_options.rb +24 -0
  37. data/lib/econt/models/profile/client_profile.rb +29 -0
  38. data/lib/econt/models/profile/profiles_response_element.rb +16 -0
  39. data/lib/econt/models/shipments/cargo_vehicle_options.rb +16 -0
  40. data/lib/econt/models/shipments/check_possible_shipment_editions_result_element.rb +14 -0
  41. data/lib/econt/models/shipments/create_label_result_element.rb +19 -0
  42. data/lib/econt/models/shipments/customs_list_element.rb +14 -0
  43. data/lib/econt/models/shipments/delete_labels_result_element.rb +14 -0
  44. data/lib/econt/models/shipments/get_my_awb_response.rb +15 -0
  45. data/lib/econt/models/shipments/get_my_awb_result_element.rb +23 -0
  46. data/lib/econt/models/shipments/instruction.rb +20 -0
  47. data/lib/econt/models/shipments/next_shipment_element.rb +13 -0
  48. data/lib/econt/models/shipments/pack_element.rb +14 -0
  49. data/lib/econt/models/shipments/packing_list_element.rb +17 -0
  50. data/lib/econt/models/shipments/payment_addition_price.rb +14 -0
  51. data/lib/econt/models/shipments/payment_instruction.rb +11 -0
  52. data/lib/econt/models/shipments/previous_shipment.rb +14 -0
  53. data/lib/econt/models/shipments/request_courier_response.rb +13 -0
  54. data/lib/econt/models/shipments/request_courier_status.rb +14 -0
  55. data/lib/econt/models/shipments/request_courier_status_result_element.rb +14 -0
  56. data/lib/econt/models/shipments/return_instruction_params.rb +48 -0
  57. data/lib/econt/models/shipments/shipment_edition_response_element.rb +16 -0
  58. data/lib/econt/models/shipments/shipment_status.rb +64 -0
  59. data/lib/econt/models/shipments/shipment_status_result_element.rb +14 -0
  60. data/lib/econt/models/shipments/shipment_status_service.rb +16 -0
  61. data/lib/econt/models/shipments/shipment_tracking_event.rb +21 -0
  62. data/lib/econt/models/shipments/shipping_label.rb +59 -0
  63. data/lib/econt/models/shipments/shipping_label_services.rb +37 -0
  64. data/lib/econt/models/shipments/status_response.rb +11 -0
  65. data/lib/econt/models/shipments/update_label_response.rb +11 -0
  66. data/lib/econt/models/shipments/update_labels_result_element.rb +14 -0
  67. data/lib/econt/models/three_way_logistics/three_way_logistics.rb +50 -0
  68. data/lib/econt/models/three_way_logistics/three_way_logistics_response.rb +11 -0
  69. data/lib/econt/resource_attributes.rb +69 -0
  70. data/lib/econt/service_resource.rb +105 -0
  71. data/lib/econt/services/nomenclatures/address.rb +87 -0
  72. data/lib/econt/services/nomenclatures/nomenclatures.rb +122 -0
  73. data/lib/econt/services/nomenclatures.rb +11 -0
  74. data/lib/econt/services/payment_report/payment_report.rb +35 -0
  75. data/lib/econt/services/payment_report.rb +11 -0
  76. data/lib/econt/services/profile/profile.rb +45 -0
  77. data/lib/econt/services/profile.rb +11 -0
  78. data/lib/econt/services/shipments/label.rb +174 -0
  79. data/lib/econt/services/shipments/shipment.rb +109 -0
  80. data/lib/econt/services/shipments.rb +11 -0
  81. data/lib/econt/services/three_way_logistics/three_way_logistics.rb +30 -0
  82. data/lib/econt/services/three_way_logistics.rb +11 -0
  83. data/lib/econt/util.rb +63 -0
  84. data/lib/econt/version.rb +5 -0
  85. data/lib/econt.rb +118 -0
  86. data/sig/econt.rbs +465 -0
  87. metadata +166 -0
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Econt
4
+ module Models
5
+ module Shipments
6
+ class ReturnInstructionParams < Econt::Model
7
+ field :return_parcel_destination, type: :string
8
+ field :return_parcel_is_document, type: :boolean
9
+ field :return_parcel_is_empty_pallet, type: :boolean
10
+ field :empty_pallet_euro, type: :integer
11
+ field :empty_pallet80, type: :integer
12
+ field :empty_pallet100, type: :integer
13
+ field :empty_pallet120, type: :integer
14
+
15
+ alias empty_pallet_80 empty_pallet80
16
+ alias empty_pallet_80= empty_pallet80=
17
+ alias empty_pallet_100 empty_pallet100
18
+ alias empty_pallet_100= empty_pallet100=
19
+ alias empty_pallet_120 empty_pallet120
20
+ alias empty_pallet_120= empty_pallet120=
21
+ field :days_until_return, type: :integer
22
+ field :return_parcel_payment_side, type: :string
23
+ field :return_parcel_receiver_client, type: Econt::Models::Profile::ClientProfile
24
+ field :return_parcel_receiver_agent, type: Econt::Models::Profile::ClientProfile
25
+ field :return_parcel_receiver_office_code, type: :string
26
+ field :return_parcel_receiver_address, type: Econt::Models::Nomenclatures::Address
27
+ field :print_return_parcel, type: :boolean
28
+ field :reject_action, type: :string
29
+ field :reject_instruction, type: :string
30
+ field :reject_contact, type: :string
31
+ field :reject_return_client, type: Econt::Models::Profile::ClientProfile
32
+ field :reject_return_agent, type: Econt::Models::Profile::ClientProfile
33
+ field :reject_return_office_code, type: :string
34
+ field :reject_return_address, type: Econt::Models::Nomenclatures::Address
35
+ field :reject_original_parcel_pay_side, type: :string
36
+ field :reject_return_parcel_pay_side, type: :string
37
+ field :signature_documents, type: :boolean
38
+ field :signature_pen_color, type: :string
39
+ field :signature_count, type: :integer
40
+ field :signature_page_numbers, type: :string
41
+ field :signature_other_instructions, type: :string
42
+ field :execute_if_rejected_without_review, type: :boolean
43
+ field :use_return_address_for_instruction, type: :boolean
44
+ field :execute_if_not_taken, type: :integer
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Econt
4
+ module Models
5
+ module Shipments
6
+ class ShipmentEditionResponseElement < Econt::Model
7
+ field :shipment_num, type: :integer
8
+ field :edition_num, type: :integer
9
+ field :edition_type, type: :string
10
+ field :edition_error, type: :string
11
+ field :price, type: :string
12
+ field :currency, type: :string
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Econt
4
+ module Models
5
+ module Shipments
6
+ class ShipmentStatus < Econt::Model
7
+ field :shipment_number, type: :string
8
+ field :storage_office_name, type: :string
9
+ field :storage_person_name, type: :string
10
+ field :created_time, type: :datetime
11
+ field :send_time, type: :datetime
12
+ field :delivery_time, type: :datetime
13
+ field :shipment_type, type: :string
14
+ field :pack_count, type: :integer
15
+ field :shipment_description, type: :string
16
+ field :weight, type: :float
17
+ field :sender_delivery_type, type: :string
18
+ field :sender_client, type: Econt::Models::Profile::ClientProfile
19
+ field :sender_agent, type: Econt::Models::Profile::ClientProfile
20
+ field :sender_office_code, type: :string
21
+ field :sender_address, type: Econt::Models::Nomenclatures::Address
22
+ field :receiver_delivery_type, type: :string
23
+ field :receiver_client, type: Econt::Models::Profile::ClientProfile
24
+ field :receiver_agent, type: Econt::Models::Profile::ClientProfile
25
+ field :receiver_office_code, type: :string
26
+ field :receiver_address, type: Econt::Models::Nomenclatures::Address
27
+ field :hub_code, type: :string
28
+ field :hub_name, type: :string
29
+ field :hub_name_en, type: :string
30
+ field :cd_collected_amount, type: :float
31
+ field :cd_collected_currency, type: :string
32
+ field :cd_collected_time, type: :datetime
33
+ field :cd_paid_amount, type: :float
34
+ field :cd_paid_currency, type: :string
35
+ field :cd_paid_time, type: :datetime
36
+ field :total_price, type: :float
37
+ field :currency, type: :string
38
+ field :discount_percent, type: :float
39
+ field :discount_amount, type: :float
40
+ field :discount_description, type: :string
41
+ field :sender_due_amount, type: :float
42
+ field :receiver_due_amount, type: :float
43
+ field :other_due_amount, type: :float
44
+ field :delivery_attempt_count, type: :integer
45
+ field :previous_shipment_number, type: :string
46
+ field :services, type: :array, of: Econt::Models::Shipments::ShipmentStatusService
47
+ field :last_processed_instruction, type: :string
48
+ field :next_shipments, type: :array, of: Econt::Models::Shipments::NextShipmentElement
49
+ field :tracking_events, type: :array, of: Econt::Models::Shipments::ShipmentTrackingEvent
50
+ field :pdf_url, type: :string
51
+ field :expected_delivery_date, type: :date
52
+ field :return_shipment_url, type: :string
53
+ field :reject_original_parcel_pay_side, type: :string
54
+ field :reject_return_parcel_pay_side, type: :string
55
+ field :shipment_edition, type: Econt::Models::Shipments::ShipmentEditionResponseElement
56
+ field :previous_shipment, type: Econt::Models::Shipments::PreviousShipment
57
+ field :warnings, type: :string
58
+ field :short_delivery_status, type: :string
59
+ field :short_delivery_status_en, type: :string
60
+ field :routing_code, type: :string
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Econt
4
+ module Models
5
+ module Shipments
6
+ class ShipmentStatusResultElement < Econt::Model
7
+ collection_key :shipment_statuses
8
+
9
+ field :status, type: Econt::Models::Shipments::ShipmentStatus
10
+ field :error, type: Econt::Models::Error
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Econt
4
+ module Models
5
+ module Shipments
6
+ class ShipmentStatusService < Econt::Model
7
+ field :type, type: :string
8
+ field :description, type: :string
9
+ field :count, type: :float
10
+ field :payment_side, type: :string
11
+ field :price, type: :float
12
+ field :currency, type: :string
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Econt
4
+ module Models
5
+ module Shipments
6
+ class ShipmentTrackingEvent < Econt::Model
7
+ field :is_receipt, type: :boolean
8
+ field :destination_type, type: :string
9
+ field :destination_details, type: :string
10
+ field :destination_details_en, type: :string
11
+ field :office_name, type: :string
12
+ field :office_name_en, type: :string
13
+ field :city_name, type: :string
14
+ field :city_name_en, type: :string
15
+ field :country_code, type: :string
16
+ field :office_code, type: :string
17
+ field :time, type: :datetime
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Econt
4
+ module Models
5
+ module Shipments
6
+ class ShippingLabel < Econt::Model
7
+ field :shipment_number, type: :string
8
+ field :previous_shipment_number, type: :string
9
+ field :previous_shipment_receiver_phone, type: :string
10
+ field :sender_client, type: Econt::Models::Profile::ClientProfile
11
+ field :sender_agent, type: Econt::Models::Profile::ClientProfile
12
+ field :sender_address, type: Econt::Models::Nomenclatures::Address
13
+ field :sender_office_code, type: :string
14
+ field :email_on_delivery, type: :string
15
+ field :sms_on_delivery, type: :string
16
+ field :receiver_client, type: Econt::Models::Profile::ClientProfile
17
+ field :receiver_agent, type: Econt::Models::Profile::ClientProfile
18
+ field :receiver_address, type: Econt::Models::Nomenclatures::Address
19
+ field :receiver_office_code, type: :string
20
+ field :receiver_provider_id, type: :integer
21
+ field :receiver_bic, type: :string
22
+ field :receiver_iban, type: :string
23
+ field :envelope_numbers, type: :array, of: :string
24
+ field :pack_count, type: :integer
25
+ field :packs, type: :array, of: Econt::Models::Shipments::PackElement
26
+ field :shipment_type, type: :string
27
+ field :weight, type: :float
28
+ field :size_under_60cm, type: :boolean
29
+ field :shipment_dimensions_l, type: :float
30
+ field :shipment_dimensions_w, type: :float
31
+ field :shipment_dimensions_h, type: :float
32
+ field :shipment_description, type: :string
33
+ field :order_number, type: :string
34
+ field :send_date, type: :date
35
+ field :holiday_delivery_day, type: :string
36
+ field :keep_upright, type: :boolean
37
+ field :services, type: Econt::Models::Shipments::ShippingLabelServices
38
+ field :instructions, type: :array, of: Econt::Models::Shipments::Instruction
39
+ field :pay_after_accept, type: :boolean
40
+ field :pay_after_test, type: :boolean
41
+ field :packing_list_type, type: :string
42
+ field :packing_list, type: :array, of: Econt::Models::Shipments::PackingListElement
43
+ field :partial_delivery, type: :boolean
44
+ field :payment_sender_method, type: :string
45
+ field :payment_receiver_method, type: :string
46
+ field :payment_receiver_amount, type: :float
47
+ field :payment_receiver_amount_is_percent, type: :boolean
48
+ field :payment_other_client_number, type: :string
49
+ field :payment_other_amount, type: :float
50
+ field :payment_other_amount_is_percent, type: :boolean
51
+ field :mediator, type: :string
52
+ field :payment_token, type: :string
53
+ field :customs_list, type: :array, of: Econt::Models::Shipments::CustomsListElement
54
+ field :customs_invoice, type: :string
55
+ field :cargo_vehicle_options, type: Econt::Models::Shipments::CargoVehicleOptions
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Econt
4
+ module Models
5
+ module Shipments
6
+ class ShippingLabelServices < Econt::Model
7
+ field :priority_time_from, type: :string
8
+ field :priority_time_to, type: :string
9
+ field :delivery_receipt, type: :boolean
10
+ field :digital_receipt, type: :boolean
11
+ field :goods_receipt, type: :boolean
12
+ field :two_way_shipment, type: :boolean
13
+ field :delivery_to_floor, type: :boolean
14
+ field :pack5, type: :integer
15
+ field :pack6, type: :integer
16
+ field :pack8, type: :integer
17
+ field :pack9, type: :integer
18
+ field :pack10, type: :integer
19
+ field :pack12, type: :integer
20
+ field :refrigerated_pack, type: :integer
21
+ field :declared_value_amount, type: :float
22
+ field :declared_value_currency, type: :string
23
+ field :money_transfer_amount, type: :float
24
+ field :express_money_transfer, type: :boolean
25
+ field :cd_amount, type: :float
26
+ field :cd_type, type: :string
27
+ field :cd_currency, type: :string
28
+ field :cd_pay_options_template, type: :string
29
+ field :cd_pay_options, type: Econt::Models::Profile::CDPayOptions
30
+ field :invoice_before_pay_cd, type: :boolean
31
+ field :sms_notification, type: :boolean
32
+ field :invoice_num, type: :string
33
+ field :money_transfer_currency, type: :string
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Econt
4
+ module Models
5
+ module Shipments
6
+ class StatusResponse < Econt::Model
7
+ field :status, type: :string
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Econt
4
+ module Models
5
+ module Shipments
6
+ class UpdateLabelResponse < Econt::Model
7
+ field :label, type: Econt::Models::Shipments::ShipmentStatus
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Econt
4
+ module Models
5
+ module Shipments
6
+ class UpdateLabelsResultElement < Econt::Model
7
+ collection_key :results
8
+
9
+ field :error, type: Econt::Models::Error
10
+ field :labels, type: Econt::Models::Shipments::UpdateLabelResponse
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Econt
4
+ module Models
5
+ module ThreeWayLogistics
6
+ # Request fields use the API's legacy snake_case names.
7
+ class ThreeWayLogisticsRequest < Econt::Model
8
+ field :requester_name, type: :string
9
+ field :requester_phone, type: :string
10
+ field :requester_email, type: :string
11
+ field :requester_company_name, type: :string
12
+ field :requester_username, type: :string
13
+ field :supplier_company_name, type: :string
14
+ field :supplier_contact_person, type: :string
15
+ field :supplier_phone, type: :string
16
+ field :supplier_city, type: :string
17
+ field :supplier_address, type: :string
18
+ field :supplier_date_for_visit, type: :string
19
+ field :supplier_time_for_visit, type: :string
20
+ field :receiver_name, type: :string
21
+ field :receiver_company_name, type: :string
22
+ field :receiver_phone, type: :string
23
+ field :receiver_email, type: :string
24
+ field :description_shipment_description, type: :string
25
+ field :description_shipment_count, type: :string
26
+ field :description_shipment_weight, type: :string
27
+ field :description_additional_instructions, type: :string
28
+ field :description_payment_sum_to_supplier, type: :string
29
+ field :delivery_details_city, type: :string
30
+ field :delivery_details_address, type: :string
31
+ field :delivery_details_office, type: :string
32
+ field :dc, type: :string
33
+ field :dccp, type: :string
34
+ field :email_on_delivery, type: :string
35
+ field :invoice_before_pay, type: :string
36
+ field :preview, type: :string
37
+ field :test, type: :string
38
+ field :payment_delivery_and_return_by_me, type: :string
39
+ field :payment_return_by_me, type: :string
40
+ field :payment_delivery_by_requester, type: :string
41
+ field :payment_delivery_by_receiver, type: :string
42
+ field :oc_sum, type: :string
43
+ field :cd_sum, type: :string
44
+ field :priority_delivery_time_before, type: :string
45
+ field :priority_delivery_time_after, type: :string
46
+ field :priority_delivery_time_in, type: :string
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Econt
4
+ module Models
5
+ module ThreeWayLogistics
6
+ # Econt documents a successful response as an object without properties.
7
+ class ThreeWayLogisticsResponse < Econt::Model
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module Econt
6
+ module ResourceAttributes
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ end
10
+
11
+ module ClassMethods
12
+ def fields
13
+ @fields ||= {}
14
+ end
15
+
16
+ def field(name, opts = {})
17
+ fields[name] = opts
18
+
19
+ define_method(name) do
20
+ coerce_field_value(@attributes[name], opts)
21
+ end
22
+
23
+ define_method("#{name}=") do |value|
24
+ @attributes[name] = coerce_field_value(value, opts)
25
+ end
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def coerce_field_value(value, options)
32
+ return nil if value.nil?
33
+
34
+ case options[:type]
35
+ when :integer then value.to_i
36
+ when :string then value.to_s
37
+ when :boolean then value == true || value.to_s.casecmp('true').zero?
38
+ when :float, :double then value.to_f
39
+ when :date then parse_temporal(value, Date)
40
+ when :datetime then parse_temporal(value, DateTime)
41
+ when :array then coerce_array(value, options[:of])
42
+ when Class then value.is_a?(options[:type]) ? value : options[:type].new(value)
43
+ else value
44
+ end
45
+ end
46
+
47
+ def coerce_array(value, item_type)
48
+ values = Array(value)
49
+ return values if item_type.nil?
50
+
51
+ values.map { |item| coerce_array_item(item, item_type) }
52
+ end
53
+
54
+ def coerce_array_item(value, type)
55
+ return value if type.is_a?(Class) && value.is_a?(type)
56
+ return type.new(value) if type.is_a?(Class)
57
+
58
+ coerce_field_value(value, type: type)
59
+ end
60
+
61
+ def parse_temporal(value, type)
62
+ return value if value.is_a?(type)
63
+
64
+ type.parse(value.to_s)
65
+ rescue ArgumentError
66
+ value
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Econt
4
+ class ServiceResource
5
+ attr_reader :client
6
+
7
+ class << self
8
+ def resource_type(value = name.split('::').last)
9
+ @resource_type = value
10
+ end
11
+ end
12
+
13
+ def initialize(client: Econt::Client.instance)
14
+ @client = client || raise('Econt::Client is not configured. Call `Econt::Client.configure` first.')
15
+ end
16
+
17
+ def resource_url
18
+ "#{service_url}/#{self.class.resource_type}Service"
19
+ end
20
+
21
+ ERROR_MESSAGES = {
22
+ 400 => 'Your request was malformed.',
23
+ 401 => 'You did not supply valid authentication credentials.',
24
+ 403 => 'You are not allowed to perform that action.',
25
+ 404 => 'No results were found for your request.',
26
+ 429 => 'Your request exceeded the API rate limit.',
27
+ 500 => 'We were unable to perform the request due to server-side problems.',
28
+ 503 => 'You have been rate-limited for sending more than 20 requests per second.'
29
+ }.freeze
30
+
31
+ private
32
+
33
+ def get(url, params: {}, headers: {})
34
+ response_for(execute_request { client.connection.get(url_for(url), params, headers) })
35
+ end
36
+
37
+ def post(url, body: {}, headers: {})
38
+ response_for(execute_request { client.connection.post(url_for(url), body, headers) })
39
+ end
40
+
41
+ def post_raw(url, body:, headers: {})
42
+ json_headers = { 'Content-Type' => 'application/json' }.merge(headers)
43
+ json_body = JSON.generate(body)
44
+ response_for(execute_request { client.connection.post(url_for(url), json_body, json_headers) })
45
+ end
46
+
47
+ def patch(url, body:, headers: {})
48
+ response_for(execute_request { client.connection.patch(url_for(url), body, headers) })
49
+ end
50
+
51
+ def put(url, body:, headers: {})
52
+ response_for(execute_request { client.connection.put(url_for(url), body, headers) })
53
+ end
54
+
55
+ def delete(url, params: {}, headers: {})
56
+ response_for(execute_request { client.connection.delete(url_for(url), params, headers) })
57
+ end
58
+
59
+ def execute_request
60
+ yield
61
+ rescue Faraday::ConnectionFailed => e
62
+ raise Econt::ConnectionError.new('Econt API connection failed.'), cause: e
63
+ rescue Faraday::TimeoutError => e
64
+ raise Econt::TimeoutError.new('Econt API request timed out.'), cause: e
65
+ rescue Faraday::SSLError => e
66
+ raise Econt::SSLError.new('Econt API TLS connection failed.'), cause: e
67
+ end
68
+
69
+ def url_for(url, format = 'json')
70
+ "#{resource_url}.#{url}.#{format}"
71
+ end
72
+
73
+ def response_for(response)
74
+ error = error_from(response.body)
75
+ raise Error.new(error: error, status: response.status) if error && server_error?(response)
76
+ return response if error
77
+
78
+ error_message = ERROR_MESSAGES[response.status]
79
+ raise Error.new(error_message, status: response.status) if error_message
80
+ raise Error.new(status: response.status) unless successful_response?(response)
81
+
82
+ response
83
+ end
84
+
85
+ def collection(response, model)
86
+ model.collection(response.body)
87
+ end
88
+
89
+ def resource(response, model, key: nil)
90
+ model.build(response.body, key: key)
91
+ end
92
+
93
+ def error_from(body)
94
+ Econt::Models::Error.build_from(body)
95
+ end
96
+
97
+ def successful_response?(response)
98
+ response.status.to_i.between?(200, 299)
99
+ end
100
+
101
+ def server_error?(response)
102
+ response.status.to_i.between?(500, 599)
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Econt
4
+ module Services
5
+ module Nomenclatures
6
+ class Address < Econt::ServiceResource
7
+ include Econt::Services::Nomenclatures
8
+
9
+ resource_type 'Address'
10
+
11
+ # POST /services/Nomenclatures/AddressService.validateAddress.json(.soap?wsdl)
12
+ # Validate and normalize an address.
13
+ # @note Read. Does not change shipment state.
14
+ # @param address [Hash, Econt::Models::Nomenclatures::Address] Address fields; the argument is positional.
15
+ # @return [Econt::Models::Nomenclatures::AddressValidationResponse]
16
+ # Check #error? before using data.
17
+ # @raise [Econt::Error] On HTTP failure.
18
+ # @raise [Econt::TransportError] On connection, timeout, or TLS failure; inspect its subclass.
19
+ # @see file:docs/API.md#validate_address Ruby usage and parameters
20
+ # @example After configuring Econt::Client
21
+ # addresses = Econt::Services::Nomenclatures::Address.new
22
+ # validation = addresses.validate_address(city: { id: 41 }, street: 'Витоша', num: '1')
23
+ def validate_address(address)
24
+ address = address_to_hash(address)
25
+ response = post('validateAddress', body: { address: address })
26
+ resource(response, Econt::Models::Nomenclatures::AddressValidationResponse)
27
+ end
28
+
29
+ # POST /services/Nomenclatures/AddressService.addressServiceTimes.json(.soap?wsdl)
30
+ # Look up address service availability for a date and shipment type.
31
+ # @note Read. Does not change shipment state.
32
+ # @param city [Hash] City fields.
33
+ # @param address [Hash] Address fields.
34
+ # @param date [String] Requested service date in the carrier format.
35
+ # @param shipment_type [String] Carrier shipment type, such as pack.
36
+ # @return [Econt::Models::Nomenclatures::AddressServiceTimesResponse]
37
+ # Check #error? before using data.
38
+ # @raise [Econt::Error] On HTTP failure.
39
+ # @raise [Econt::TransportError] On connection, timeout, or TLS failure; inspect its subclass.
40
+ # @see file:docs/API.md#address_service_times Ruby usage and parameters
41
+ # @example After configuring Econt::Client
42
+ # addresses = Econt::Services::Nomenclatures::Address.new
43
+ # times = addresses.address_service_times(
44
+ # city: { id: 41 }, address: address_payload,
45
+ # date: '2026-10-12', shipment_type: 'pack'
46
+ # )
47
+ def address_service_times(city:, address:, date:, shipment_type:)
48
+ response = post('addressServiceTimes', body: {
49
+ city: city,
50
+ address: address,
51
+ date: date,
52
+ shipment_type: shipment_type
53
+ })
54
+ resource(response, Econt::Models::Nomenclatures::AddressServiceTimesResponse)
55
+ end
56
+
57
+ # POST /services/Nomenclatures/AddressService.getNearestOffices.json(.soap?wsdl)
58
+ # Find offices near an address for a shipment type.
59
+ # @note Read. Does not change shipment state.
60
+ # @param address [Hash] Address fields.
61
+ # @param shipment_type [String] Carrier shipment type.
62
+ # @return [Econt::Collection<Econt::Models::Nomenclatures::Office>]
63
+ # Check #error? before using data.
64
+ # @raise [Econt::Error] On HTTP failure.
65
+ # @raise [Econt::TransportError] On connection, timeout, or TLS failure; inspect its subclass.
66
+ # @see file:docs/API.md#get_nearest_offices Ruby usage and parameters
67
+ # @example After configuring Econt::Client
68
+ # addresses = Econt::Services::Nomenclatures::Address.new
69
+ # offices = addresses.get_nearest_offices(address: address_payload, shipment_type: 'pack')
70
+ def get_nearest_offices(address:, shipment_type:)
71
+ response = post('getNearestOffices', body: { address: address, shipment_type: shipment_type })
72
+ collection(response, Econt::Models::Nomenclatures::Office)
73
+ end
74
+
75
+ private
76
+
77
+ def address_to_hash(address)
78
+ if address.is_a?(Econt::Models::Nomenclatures::Address)
79
+ address.to_h
80
+ else
81
+ Econt::Models::Nomenclatures::Address.new(address).to_h
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end