deliveries 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/main.yml +19 -0
  3. data/.gitignore +12 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +34 -0
  6. data/CHANGELOG.md +13 -0
  7. data/Gemfile +12 -0
  8. data/Gemfile.lock +127 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +207 -0
  11. data/Rakefile +12 -0
  12. data/bin/console +15 -0
  13. data/bin/setup +8 -0
  14. data/deliveries.gemspec +36 -0
  15. data/lib/deliveries/address.rb +71 -0
  16. data/lib/deliveries/checkpoint.rb +12 -0
  17. data/lib/deliveries/collection_point.rb +45 -0
  18. data/lib/deliveries/courier.rb +69 -0
  19. data/lib/deliveries/couriers/correos_express/address.rb +31 -0
  20. data/lib/deliveries/couriers/correos_express/collection_points/search/format_response.rb +82 -0
  21. data/lib/deliveries/couriers/correos_express/collection_points/search.rb +56 -0
  22. data/lib/deliveries/couriers/correos_express/labels/generate.rb +68 -0
  23. data/lib/deliveries/couriers/correos_express/pickups/create/defaults.rb +60 -0
  24. data/lib/deliveries/couriers/correos_express/pickups/create/format_params.rb +95 -0
  25. data/lib/deliveries/couriers/correos_express/pickups/create.rb +66 -0
  26. data/lib/deliveries/couriers/correos_express/pickups/cutoff_time/format_params.rb +40 -0
  27. data/lib/deliveries/couriers/correos_express/pickups/cutoff_time.rb +61 -0
  28. data/lib/deliveries/couriers/correos_express/pickups/trace/correos.test.wsdl +163 -0
  29. data/lib/deliveries/couriers/correos_express/pickups/trace/correos.wsdl +163 -0
  30. data/lib/deliveries/couriers/correos_express/pickups/trace/format_response.rb +71 -0
  31. data/lib/deliveries/couriers/correos_express/pickups/trace.rb +49 -0
  32. data/lib/deliveries/couriers/correos_express/shipments/create/defaults.rb +80 -0
  33. data/lib/deliveries/couriers/correos_express/shipments/create/format_params.rb +99 -0
  34. data/lib/deliveries/couriers/correos_express/shipments/create.rb +101 -0
  35. data/lib/deliveries/couriers/correos_express/shipments/trace/format_response.rb +67 -0
  36. data/lib/deliveries/couriers/correos_express/shipments/trace.rb +65 -0
  37. data/lib/deliveries/couriers/correos_express.rb +162 -0
  38. data/lib/deliveries/couriers/dummy.rb +106 -0
  39. data/lib/deliveries/couriers/mondial_relay/address.rb +31 -0
  40. data/lib/deliveries/couriers/mondial_relay/collection_points/search/format_response.rb +103 -0
  41. data/lib/deliveries/couriers/mondial_relay/labels/generate.rb +40 -0
  42. data/lib/deliveries/couriers/mondial_relay/pickups/create/format_params.rb +57 -0
  43. data/lib/deliveries/couriers/mondial_relay/shipments/create/defaults.rb +96 -0
  44. data/lib/deliveries/couriers/mondial_relay/shipments/create/format_params.rb +68 -0
  45. data/lib/deliveries/couriers/mondial_relay/shipments/create.rb +36 -0
  46. data/lib/deliveries/couriers/mondial_relay/shipments/trace/format_response.rb +94 -0
  47. data/lib/deliveries/couriers/mondial_relay/shipments/trace.rb +47 -0
  48. data/lib/deliveries/couriers/mondial_relay/status_codes.rb +105 -0
  49. data/lib/deliveries/couriers/mondial_relay.rb +189 -0
  50. data/lib/deliveries/couriers/mondial_relay_dual/address.rb +31 -0
  51. data/lib/deliveries/couriers/mondial_relay_dual/pickups/create/format_params.rb +39 -0
  52. data/lib/deliveries/couriers/mondial_relay_dual/shipments/create/format_params.rb +101 -0
  53. data/lib/deliveries/couriers/mondial_relay_dual/shipments/create.rb +133 -0
  54. data/lib/deliveries/couriers/mondial_relay_dual.rb +105 -0
  55. data/lib/deliveries/couriers/spring/address.rb +23 -0
  56. data/lib/deliveries/couriers/spring/labels/generate.rb +33 -0
  57. data/lib/deliveries/couriers/spring/request.rb +43 -0
  58. data/lib/deliveries/couriers/spring/shipments/create/defaults.rb +73 -0
  59. data/lib/deliveries/couriers/spring/shipments/create/format_params.rb +77 -0
  60. data/lib/deliveries/couriers/spring/shipments/create.rb +45 -0
  61. data/lib/deliveries/couriers/spring/shipments/trace/format_response.rb +79 -0
  62. data/lib/deliveries/couriers/spring/shipments/trace.rb +29 -0
  63. data/lib/deliveries/couriers/spring.rb +84 -0
  64. data/lib/deliveries/couriers/ups/collection_points/search.rb +142 -0
  65. data/lib/deliveries/couriers/ups/json_request.rb +40 -0
  66. data/lib/deliveries/couriers/ups/labels/generate.rb +72 -0
  67. data/lib/deliveries/couriers/ups/shipments/create.rb +210 -0
  68. data/lib/deliveries/couriers/ups/shipments/trace.rb +79 -0
  69. data/lib/deliveries/couriers/ups.rb +122 -0
  70. data/lib/deliveries/couriers.rb +14 -0
  71. data/lib/deliveries/delivery.rb +20 -0
  72. data/lib/deliveries/errors.rb +22 -0
  73. data/lib/deliveries/label.rb +20 -0
  74. data/lib/deliveries/label_utils.rb +67 -0
  75. data/lib/deliveries/labels.rb +40 -0
  76. data/lib/deliveries/pickup.rb +15 -0
  77. data/lib/deliveries/shipment.rb +15 -0
  78. data/lib/deliveries/tracking_info.rb +29 -0
  79. data/lib/deliveries/version.rb +5 -0
  80. data/lib/deliveries.rb +63 -0
  81. metadata +240 -0
@@ -0,0 +1,101 @@
1
+ require 'httparty'
2
+
3
+ module Deliveries
4
+ module Couriers
5
+ module CorreosExpress
6
+ module Shipments
7
+ class Create
8
+ include HTTParty
9
+
10
+ attr_accessor :sender, :receiver, :collection_point, :parcels,
11
+ :reference_code, :shipment_date, :remarks
12
+
13
+ def initialize(sender:, receiver:, collection_point:, parcels:,
14
+ reference_code:, shipment_date:, remarks:)
15
+ self.sender = sender
16
+ self.receiver = receiver
17
+ self.collection_point = collection_point
18
+ self.parcels = parcels
19
+ self.reference_code = reference_code
20
+ self.shipment_date = shipment_date
21
+ self.remarks = remarks
22
+ end
23
+
24
+ def execute
25
+ auth = {
26
+ username: CorreosExpress.config(:username),
27
+ password: CorreosExpress.config(:password)
28
+ }
29
+
30
+ params = FormatParams.new(
31
+ sender: sender.courierize(:correos_express),
32
+ receiver: receiver.courierize(:correos_express),
33
+ collection_point: collection_point,
34
+ parcels: parcels,
35
+ reference_code: reference_code,
36
+ shipment_date: shipment_date,
37
+ remarks: remarks
38
+ ).execute
39
+
40
+ response = self.class.post(
41
+ api_endpoint,
42
+ basic_auth: auth,
43
+ body: params,
44
+ headers: headers,
45
+ debug_output: Deliveries.debug ? Deliveries.logger : nil
46
+ )
47
+ raise Deliveries::ClientError unless response.success?
48
+
49
+ parsed_response = JSON.parse(response.body, symbolize_names: true)
50
+ if parsed_response[:codigoRetorno].zero? && parsed_response.key?(:datosResultado)
51
+ tracking_code = parsed_response[:datosResultado]
52
+ decoded_label = decode_label(parsed_response.dig(:etiqueta, 0, :etiqueta1))
53
+ label = Label.new(raw: decoded_label) if decoded_label
54
+
55
+ Deliveries::Shipment.new(
56
+ courier_id: 'correos_express',
57
+ sender: sender,
58
+ receiver: receiver,
59
+ parcels: parcels,
60
+ reference_code: reference_code,
61
+ tracking_code: tracking_code,
62
+ shipment_date: shipment_date,
63
+ label: label
64
+ )
65
+ else
66
+ raise Deliveries::APIError.new(
67
+ parsed_response[:mensajeRetorno],
68
+ parsed_response[:codigoRetorno]
69
+ )
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ def api_endpoint
76
+ if CorreosExpress.live?
77
+ CorreosExpress::SHIPMENTS_ENDPOINT_LIVE
78
+ else
79
+ CorreosExpress::SHIPMENTS_ENDPOINT_TEST
80
+ end
81
+ end
82
+
83
+ def headers
84
+ { 'Content-Type' => "application/json; charset='UTF-8'" }
85
+ end
86
+
87
+ def decode_label(encoded_label)
88
+ return nil if encoded_label.blank?
89
+
90
+ decoded_label = Base64.decode64(Base64.decode64(encoded_label)).force_encoding('binary')
91
+
92
+ # Check pdf file signature
93
+ return nil unless decoded_label[0..4].unpack1('H*').hex == 0x255044462d
94
+
95
+ decoded_label
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,67 @@
1
+ require 'active_support/time'
2
+
3
+ module Deliveries
4
+ module Couriers
5
+ module CorreosExpress
6
+ module Shipments
7
+ class Trace
8
+ class FormatResponse
9
+ attr_accessor :response
10
+
11
+ def initialize(response:)
12
+ self.response = response
13
+ end
14
+
15
+ def execute
16
+ tracking_info_params = {}
17
+ tracking_info_params[:courier_id] = 'correos_express'
18
+ tracking_info_params[:tracking_code] = response['NumEnvio']
19
+ tracking_info_params[:status] = status(response['DescEstado'])
20
+ tracking_info_params[:checkpoints] = formatted_checkpoints(response['EstadoEnvios'])
21
+
22
+ tracking_info_params
23
+ end
24
+
25
+ private
26
+
27
+ def formatted_checkpoints(shipment_statuses)
28
+ checkpoints = []
29
+ if shipment_statuses.is_a?(Array)
30
+ shipment_statuses.each do |shipment_status|
31
+ checkpoints << formatted_checkpoint(shipment_status)
32
+ end
33
+ else
34
+ checkpoints << formatted_checkpoint(shipment_statuses)
35
+ end
36
+
37
+ checkpoints
38
+ end
39
+
40
+ def formatted_checkpoint(shipment_status)
41
+ Deliveries::Checkpoint.new(
42
+ status: status(shipment_status['DescEstado']),
43
+ location: nil,
44
+ tracked_at: Time.zone.strptime("#{shipment_status['FechaEstado']} #{shipment_status['HoraEstado']}",
45
+ '%d%m%Y %H%M%S'),
46
+ description: shipment_status['DescEstado']
47
+ )
48
+ end
49
+
50
+ def status(code)
51
+ case code
52
+ when 'SIN RECEPCION'
53
+ :registered
54
+ when 'EN ARRASTRE', 'DELEGACION DESTINO', 'EN REPARTO', 'TRAMO ORIGEN'
55
+ :in_transit
56
+ when 'ENTREGADO'
57
+ :delivered
58
+ else
59
+ :unknown_status
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,65 @@
1
+ require 'httparty'
2
+ require 'active_support/core_ext/hash/conversions'
3
+
4
+ module Deliveries
5
+ module Couriers
6
+ module CorreosExpress
7
+ module Shipments
8
+ class Trace
9
+ include HTTParty
10
+
11
+ attr_accessor :tracking_code
12
+
13
+ def initialize(tracking_code:)
14
+ self.tracking_code = tracking_code
15
+ end
16
+
17
+ def execute
18
+ auth = {
19
+ username: CorreosExpress.config(:username),
20
+ password: CorreosExpress.config(:password)
21
+ }
22
+ solicitante = CorreosExpress.config(:client_code)
23
+
24
+ xml = "<?xml version='1.0'?>
25
+ <SeguimientoEnviosRequest xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
26
+ xsi:noNamespaceSchemaLocation='SeguimientoEnviosRequest.xsd'>
27
+ <Solicitante>#{solicitante}</Solicitante>
28
+ <Dato>#{tracking_code}</Dato>
29
+ </SeguimientoEnviosRequest>"
30
+
31
+ response = self.class.post(
32
+ api_endpoint,
33
+ basic_auth: auth,
34
+ body: xml,
35
+ headers: { 'Content-Type' => 'application/xml' },
36
+ debug_output: Deliveries.debug ? Deliveries.logger : nil
37
+ )
38
+
39
+ raise Deliveries::ClientError unless response.success?
40
+
41
+ result = Hash.from_xml response.force_encoding(Encoding::ISO_8859_1).encode(Encoding::UTF_8)
42
+ if result['SeguimientoEnviosResponse']['Error'] == '0'
43
+ result['SeguimientoEnviosResponse']
44
+ else
45
+ raise Deliveries::APIError.new(
46
+ result['SeguimientoEnviosResponse']['MensajeError'],
47
+ result['SeguimientoEnviosResponse']['Error']
48
+ )
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def api_endpoint
55
+ if CorreosExpress.live?
56
+ CorreosExpress::TRACKING_INFO_ENDPOINT_LIVE
57
+ else
58
+ CorreosExpress::TRACKING_INFO_ENDPOINT_TEST
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,162 @@
1
+ require_relative 'correos_express/shipments/trace/format_response'
2
+ require_relative 'correos_express/shipments/trace'
3
+ require_relative 'correos_express/shipments/create/defaults'
4
+ require_relative 'correos_express/shipments/create/format_params'
5
+ require_relative 'correos_express/shipments/create'
6
+ require_relative 'correos_express/collection_points/search'
7
+ require_relative 'correos_express/collection_points/search/format_response'
8
+ require_relative 'correos_express/labels/generate'
9
+ require_relative 'correos_express/pickups/create/defaults'
10
+ require_relative 'correos_express/pickups/create/format_params'
11
+ require_relative 'correos_express/pickups/create'
12
+ require_relative 'correos_express/pickups/trace/format_response'
13
+ require_relative 'correos_express/pickups/trace'
14
+ require_relative 'correos_express/pickups/cutoff_time/format_params'
15
+ require_relative 'correos_express/pickups/cutoff_time'
16
+ require_relative 'correos_express/address'
17
+
18
+ module Deliveries
19
+ module Couriers
20
+ module CorreosExpress
21
+ extend Courier
22
+
23
+ Config = Struct.new(
24
+ :username,
25
+ :password,
26
+ :client_code,
27
+ :shipment_sender_code,
28
+ :pickup_receiver_code,
29
+ :countries
30
+ )
31
+
32
+ COLLECTION_POINTS_ENDPOINT_TEST = 'https://www.correosexpress.com/wspsc/apiRestOficina/v1/oficinas/listadoOficinasCoordenadas'.freeze
33
+ COLLECTION_POINTS_ENDPOINT_LIVE = 'https://www.correosexpress.com/wpsc/apiRestOficina/v1/oficinas/listadoOficinasCoordenadas'.freeze
34
+ SHIPMENTS_ENDPOINT_LIVE = 'https://www.correosexpress.com/wpsc/apiRestGrabacionEnvio/json/grabacionEnvio'.freeze
35
+ SHIPMENTS_ENDPOINT_TEST = 'https://test.correosexpress.com/wspsc/apiRestGrabacionEnvio/json/grabacionEnvio'.freeze
36
+ TRACKING_INFO_ENDPOINT_LIVE = 'https://www.correosexpress.com/wpsc/apiRestSeguimientoEnvios/rest/seguimientoEnvios'.freeze
37
+ TRACKING_INFO_ENDPOINT_TEST = 'https://test.correosexpress.com/wspsc/apiRestSeguimientoEnvios/rest/seguimientoEnvios'.freeze
38
+ LABELS_ENDPOINT_LIVE = 'https://www.cexpr.es/wspsc/apiRestEtiquetaTransporte/json/etiquetaTransporte'.freeze
39
+ LABELS_ENDPOINT_TEST = 'https://www.test.cexpr.es/wsps/apiRestEtiquetaTransporte/json/etiquetaTransporte'.freeze
40
+ PICKUPS_ENDPOINT_LIVE = 'https://www.correosexpress.com/wpsc/apiRestGrabacionRecogida/json/grabarRecogida'.freeze
41
+ PICKUPS_ENDPOINT_TEST = 'https://test.correosexpress.com/wpsn/apiRestGrabacionRecogida/json/grabarRecogida'.freeze
42
+ CUTOFF_TIME_ENDPOINT_LIVE = 'https://www.correosexpress.com/wpsc/apiRestGrabacionRecogida/json/horaCorte'.freeze
43
+
44
+ module_function
45
+
46
+ def get_collection_points(postcode:, **)
47
+ raise Deliveries::APIError, 'Postcode cannot be null' if postcode.blank?
48
+
49
+ collection_points = []
50
+
51
+ points = CollectionPoints::Search.new(postcode: postcode).execute
52
+ points.each do |point|
53
+ collection_point_params = CollectionPoints::Search::FormatResponse.new(response: point).execute
54
+ collection_points << Deliveries::CollectionPoint.new(collection_point_params)
55
+ end
56
+
57
+ collection_points
58
+ end
59
+
60
+ def get_collection_point(global_point_id:)
61
+ global_point = Deliveries::CollectionPoint.parse_global_point_id(global_point_id: global_point_id)
62
+
63
+ collection_points = get_collection_points(postcode: global_point.postcode)
64
+ collection_point = collection_points.select { |col| col.point_id == global_point.point_id }.first
65
+
66
+ if collection_point.blank?
67
+ raise Deliveries::APIError.new(
68
+ "Collection Point not found - #{global_point.point_id}",
69
+ 1
70
+ )
71
+ end
72
+
73
+ collection_point
74
+ end
75
+
76
+ def shipment_info(tracking_code:, **)
77
+ response = Shipments::Trace.new(
78
+ tracking_code: tracking_code
79
+ ).execute
80
+
81
+ tracking_info_params = Shipments::Trace::FormatResponse.new(response: response).execute
82
+ Deliveries::TrackingInfo.new(tracking_info_params)
83
+ end
84
+
85
+ def pickup_info(tracking_code:, **)
86
+ response = Pickups::Trace.new(
87
+ tracking_code: tracking_code
88
+ ).execute
89
+
90
+ tracking_info_params = Pickups::Trace::FormatResponse.new(response: response).execute
91
+
92
+ Deliveries::TrackingInfo.new(tracking_info_params)
93
+ end
94
+
95
+ def get_label(tracking_code:, **)
96
+ pdf = Labels::Generate.new(
97
+ tracking_codes: tracking_code
98
+ ).execute.first
99
+
100
+ Deliveries::Label.new(raw: pdf)
101
+ end
102
+
103
+ def get_labels(tracking_codes:, **)
104
+ labels = Deliveries::Labels.new
105
+
106
+ Labels::Generate.new(
107
+ tracking_codes: tracking_codes
108
+ ).execute.each do |pdf|
109
+ labels << pdf
110
+ end
111
+
112
+ labels
113
+ end
114
+
115
+ def create_shipment(sender:, receiver:, parcels:, reference_code:, collection_point: nil, shipment_date: nil, remarks: nil, **)
116
+ Shipments::Create.new(
117
+ sender: sender,
118
+ receiver: receiver,
119
+ collection_point: collection_point,
120
+ shipment_date: shipment_date,
121
+ parcels: parcels,
122
+ reference_code: reference_code,
123
+ remarks: remarks
124
+ ).execute
125
+ end
126
+
127
+ def create_pickup(sender:, receiver:, parcels:, reference_code:,
128
+ pickup_date: nil, remarks: nil, **)
129
+ time_interval = nil
130
+ begin
131
+ params = Pickups::Create::FormatParams.new(
132
+ sender: sender.courierize(:correos_express),
133
+ receiver: receiver.courierize(:correos_express),
134
+ parcels: parcels,
135
+ reference_code: reference_code,
136
+ pickup_date: pickup_date,
137
+ remarks: remarks,
138
+ time_interval: time_interval
139
+ ).execute
140
+
141
+ pickup_number = Pickups::Create.new(params: params).execute
142
+ rescue InvalidTimeIntervalError => e
143
+ raise e if time_interval
144
+ raise e unless (cutoff_time = e.message[/\b(\d+):\d{2}\z/, 1])
145
+
146
+ time_interval = 9..cutoff_time.to_i
147
+ retry
148
+ end
149
+
150
+ Deliveries::Pickup.new(
151
+ courier_id: 'correos_express',
152
+ sender: sender,
153
+ receiver: receiver,
154
+ parcels: parcels,
155
+ reference_code: reference_code,
156
+ tracking_code: pickup_number,
157
+ pickup_date: pickup_date
158
+ )
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,106 @@
1
+ module Deliveries
2
+ module Couriers
3
+ module Dummy
4
+ extend Courier
5
+
6
+ module_function
7
+
8
+ def get_collection_point(global_point_id:)
9
+ point = CollectionPoint.parse_global_point_id global_point_id: global_point_id
10
+ CollectionPoint.new name: 'Dummy',
11
+ email: 'dummy@dummy.com',
12
+ phone: '555 555 555',
13
+ country: point.country.to_sym,
14
+ state: 'Bizkaia',
15
+ city: 'Erandio',
16
+ street: 'Axpe',
17
+ postcode: point.postcode,
18
+ courier_id: 'dummy',
19
+ point_id: point.point_id,
20
+ latitude: 43.312132,
21
+ longitude: -2.979586,
22
+ timetable: {
23
+ 0 => [],
24
+ 1 => [OpenStruct.new(open: '8:00', close: '14:00'),
25
+ OpenStruct.new(open: '16:00', close: '20:00')],
26
+ 2 => [OpenStruct.new(open: '8:00', close: '14:00'),
27
+ OpenStruct.new(open: '16:00', close: '20:00')],
28
+ 3 => [OpenStruct.new(open: '8:00', close: '14:00'),
29
+ OpenStruct.new(open: '16:00', close: '20:00')],
30
+ 4 => [OpenStruct.new(open: '8:00', close: '14:00'),
31
+ OpenStruct.new(open: '16:00', close: '20:00')],
32
+ 5 => [OpenStruct.new(open: '8:00', close: '15:00')],
33
+ 6 => []
34
+ },
35
+ url_map: nil,
36
+ url_photo: nil
37
+ end
38
+
39
+ def get_collection_points(country:, postcode:)
40
+ [
41
+ get_collection_point(global_point_id: "dummy~#{country}~#{postcode}~1"),
42
+ get_collection_point(global_point_id: "dummy~#{country}~#{postcode}~2")
43
+ ]
44
+ end
45
+
46
+ def shipment_info(tracking_code:, **)
47
+ TrackingInfo.new courier_id: 'dummy',
48
+ tracking_code: tracking_code,
49
+ status: :in_transit,
50
+ checkpoints: [
51
+ Checkpoint.new(status: :registered, location: 'Source city', tracked_at: 1.week.ago,
52
+ description: 'Parcel taken'),
53
+ Checkpoint.new(status: :in_transit, location: 'Halfway city', tracked_at: 1.day.ago,
54
+ description: 'There is some delay')
55
+ ],
56
+ url: 'https://google.com'
57
+ end
58
+
59
+ def pickup_info(tracking_code:, **)
60
+ TrackingInfo.new courier_id: 'dummy',
61
+ tracking_code: tracking_code,
62
+ status: :in_transit,
63
+ checkpoints: [
64
+ Checkpoint.new(status: :registered, location: 'Source city', tracked_at: 1.week.ago,
65
+ description: 'Parcel taken'),
66
+ Checkpoint.new(status: :in_transit, location: 'Halfway city', tracked_at: 1.day.ago,
67
+ description: 'There is some delay')
68
+ ],
69
+ url: 'https://google.com'
70
+ end
71
+
72
+ def create_shipment(sender:, receiver:, parcels:, reference_code:, shipment_date: nil, **)
73
+ Shipment.new courier_id: 'dummy',
74
+ sender: sender,
75
+ receiver: receiver,
76
+ parcels: parcels,
77
+ reference_code: reference_code,
78
+ tracking_code: reference_code,
79
+ shipment_date: shipment_date
80
+ end
81
+
82
+ def create_pickup(sender:, receiver:, parcels:, reference_code:, pickup_date: nil, **)
83
+ Pickup.new courier_id: 'dummy',
84
+ sender: sender,
85
+ receiver: receiver,
86
+ parcels: parcels,
87
+ reference_code: reference_code,
88
+ tracking_code: reference_code,
89
+ pickup_date: pickup_date
90
+ end
91
+
92
+ def get_label(**)
93
+ pdf = <<~PDF
94
+ %PDF-1.0
95
+ 1 0 obj<</Pages 2 0 R>>endobj 2 0 obj<</Kids[3 0 R]/Count 1>>endobj 3 0 obj<</MediaBox[0 0 3 3]>>endobj
96
+ trailer<</Root 1 0 R>>
97
+ PDF
98
+ Deliveries::Label.new(raw: pdf)
99
+ end
100
+
101
+ def get_labels(tracking_codes:, language: nil)
102
+ get_label tracking_code: tracking_codes, language: language
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,31 @@
1
+ module Deliveries
2
+ module Couriers
3
+ module MondialRelay
4
+ class Address < Deliveries::Address
5
+ def name
6
+ I18n.transliterate(@name.to_s).gsub(%r{[^0-9A-Z_\-'., /]}i, '').upcase.truncate(32, omission: '')
7
+ end
8
+
9
+ def street
10
+ I18n.transliterate(@street.to_s).gsub(%r{[^0-9A-Z_\-'., /]}i, '').upcase.truncate(32, omission: '')
11
+ end
12
+
13
+ def city
14
+ I18n.transliterate(@city.to_s).gsub(/[^A-Z_\-' ]/i, '').upcase.truncate(25, omission: '')
15
+ end
16
+
17
+ def country
18
+ @country.to_s.upcase
19
+ end
20
+
21
+ def phone
22
+ format_international_phone
23
+ end
24
+
25
+ def email
26
+ format_email
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,103 @@
1
+ # :stat=>"0",
2
+ # :num=>"070912",
3
+ # :lg_adr1=>"VENANDCOM ",
4
+ # :lg_adr2=>nil,
5
+ # :lg_adr3=>"CL LANGILERIA 126 ",
6
+ # :lg_adr4=>nil,
7
+ # :cp=>"48940",
8
+ # :ville=>"LEIOA ",
9
+ # :pays=>"ES",
10
+ # :localisation1=>"ENTRE METRO LAMIACO Y ROMO ",
11
+ # :localisation2=>nil,
12
+ # :horaires_lundi=>{:string=>["1000", "1330", "1700", "2000"]},
13
+ # :horaires_mardi=>{:string=>["1000", "1330", "1700", "2000"]},
14
+ # :horaires_mercredi=>{:string=>["1000", "1330", "1700", "2000"]},
15
+ # :horaires_jeudi=>{:string=>["1000", "1330", "1700", "2000"]},
16
+ # :horaires_vendredi=>{:string=>["1000", "1330", "1700", "2000"]},
17
+ # :horaires_samedi=>{:string=>["1000", "1330", "0000", "0000"]},
18
+ # :horaires_dimanche=>{:string=>["0000", "0000", "0000", "0000"]},
19
+ # :information=>nil,
20
+ # :url_photo=>"https://ww2.mondialrelay.com/public/permanent/photo_relais.aspx?ens=CC______41&num=070912&pays=ES&crc=17576B6AE31EA66C7C66463BCDD955A4",
21
+ # :url_plan=>"https://ww2.mondialrelay.com/public/permanent/plan_relais.aspx?ens=test11&num=070912&pays=ES&crc=4F83CD143A1506242F025F9C11311A3C"}
22
+
23
+ # Deliveries.courier('mondial_relay').get_collection_point(point_id: 23191, country: 'ES')
24
+
25
+ module Deliveries
26
+ module Couriers
27
+ module MondialRelay
28
+ module CollectionPoints
29
+ class Search
30
+ class FormatResponse
31
+ WEEKDAYS_STARTING_SUNDAY = %w[
32
+ dimanche
33
+ lundi
34
+ mardi
35
+ mercredi
36
+ jeudi
37
+ vendredi
38
+ samedi
39
+ ].freeze
40
+
41
+ attr_accessor :response
42
+
43
+ def initialize(response:)
44
+ self.response = response
45
+ end
46
+
47
+ def execute
48
+ point = {}
49
+
50
+ point[:courier_id] = 'mondial_relay'
51
+ point[:point_id] = response[:num]
52
+ point[:country] = response[:pays]
53
+ point[:city] = response[:ville].strip unless response[:ville].nil?
54
+ point[:postcode] = response[:cp].strip unless response[:cp].nil?
55
+ point[:url_map] = response[:url_plan]
56
+ point[:latitude] = response[:latitude].tr(',', '.').to_f
57
+ point[:longitude] = response[:longitude].tr(',', '.').to_f
58
+ point[:timetable] = formatted_timetable(response)
59
+ point[:url_photo] = response[:url_photo]
60
+ point[:name] = response[:lg_adr1].strip
61
+ point[:street] = response[:lg_adr3].strip
62
+
63
+ point
64
+ end
65
+
66
+ private
67
+
68
+ def formatted_timetable(result)
69
+ timetable = {}
70
+
71
+ week_hours = get_week_hours_from_result(result)
72
+ week_hours.each do |i, times|
73
+ timetable[i] = []
74
+ if times[0] == '0000'
75
+ timetable[i] << nil
76
+ else
77
+ timetable[i] << formatted_slot(open: times[0], close: times[1])
78
+ timetable[i] << formatted_slot(open: times[2], close: times[3]) if times[2] != '0000'
79
+ end
80
+ timetable[i] = nil unless timetable[i].any?
81
+ end
82
+
83
+ timetable
84
+ end
85
+
86
+ def get_week_hours_from_result(result)
87
+ week_hours = {}
88
+ WEEKDAYS_STARTING_SUNDAY.each_with_index do |day, i|
89
+ week_hours[i] = result["horaires_#{day}".to_sym][:string]
90
+ end
91
+
92
+ week_hours
93
+ end
94
+
95
+ def formatted_slot(open:, close:)
96
+ OpenStruct.new(open: open.insert(2, ':'), close: close.insert(2, ':'))
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,40 @@
1
+ module Deliveries
2
+ module Couriers
3
+ module MondialRelay
4
+ module Labels
5
+ class Generate
6
+ attr_accessor :tracking_codes, :language
7
+
8
+ def initialize(tracking_codes:, language:)
9
+ self.tracking_codes = [tracking_codes].flatten.join(';')
10
+ self.language = language.to_s.upcase
11
+ end
12
+
13
+ def execute
14
+ params = {
15
+ 'Enseigne' => Deliveries::Couriers::MondialRelay.config(:mondial_relay_merchant),
16
+ 'Expeditions' => tracking_codes,
17
+ 'Langue' => language
18
+ }
19
+
20
+ # Calculate security parameters.
21
+ params['Security'] = Deliveries::Couriers::MondialRelay.calculate_security_param params
22
+
23
+ response = MondialRelay.api_client.call :wsi3_get_etiquettes, message: params
24
+ response_stat = response.body.dig(:wsi3_get_etiquettes_response, :wsi3_get_etiquettes_result, :stat)
25
+ if response_stat == '0'
26
+ # Get path for 10x15 format.
27
+ "http://www.mondialrelay.com#{response.body.dig(:wsi3_get_etiquettes_response,
28
+ :wsi3_get_etiquettes_result, :url_pdf_10x15)}"
29
+ else
30
+ raise Deliveries::APIError.new(
31
+ StatusCodes.message_for(response_stat.to_i),
32
+ response_stat
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end