deliveries 0.2.1 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8600bc0cc56888deaa08129100cc3d3539c0151cdb6580eae01a2c8e837cbad6
4
- data.tar.gz: a8a2433d3d0fab403364049d166bc97b7fa0be01991bf246c6e5b3ce4923439b
3
+ metadata.gz: 722f7e2f87a1066c05cde809502b9b6d967046893fcb87e8c1a1409840c039f5
4
+ data.tar.gz: 9d27f01af8de8e2d8b17553b3066ae0cabdac0d3e5d3a45892251e81decd65aa
5
5
  SHA512:
6
- metadata.gz: 25de14c9c5b522e9bf60f9d439e7b9672fcf5fe484b34ea2817970e1c895eab2ad80b6b5885d47b5ec21f89d19048d6c84e9d52741b8f452031831136d4ab54a
7
- data.tar.gz: 154fff2aa85ea1071aed9aaf831c867e010566891b161e5c31b1612c436faa81ad694832d861e630bfbefc810e6f79e8ef949e858eade78bab22d2f9567d3901
6
+ metadata.gz: 6c2e379b47f9499484147b878851c4ab935f7cbbfcf23eb2624b05d5438d4016e363586e2bed09cbadba55faa72c5942d416459b184f5f8cbc2e6b12648d9c87
7
+ data.tar.gz: ab0445d3c2af3fe97db2cdd00c3b54a88f5008459efc274bfbacdce0cf445a350961aa774b5d317f496c2a2bd20c208e660895d27ae3f242be8c787dec9766f4
data/CHANGELOG.md CHANGED
@@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.3.1] - 2023-01-13
10
+ ### Fixed
11
+ - Inpost week hours
12
+
13
+ ## [0.3.0] - 2021-11-26
14
+ ### Added
15
+ - Envialia courier integration
16
+
9
17
  ## [0.2.1] - 2021-11-04
10
18
  ### Fixed
11
19
  - Field `clienteRecogida` must have the same value as `codDest` in Correos Express pickup.
@@ -21,8 +29,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
21
29
  ## [0.1.0] - 2021-09-27
22
30
  🎉 First release!
23
31
 
24
- [Unreleased]: https://github.com/ecommerce-ventures/deliveries/compare/v0.2.1...HEAD
32
+ [Unreleased]: https://github.com/ecommerce-ventures/deliveries/compare/v0.3.1...HEAD
33
+ [0.3.1]: https://github.com/ecommerce-ventures/deliveries/compare/v0.3.0...v0.3.1
34
+ [0.3.0]: https://github.com/ecommerce-ventures/deliveries/compare/v0.2.1...v0.3.0
25
35
  [0.2.1]: https://github.com/ecommerce-ventures/deliveries/compare/v0.2.0...v0.2.1
26
36
  [0.2.0]: https://github.com/ecommerce-ventures/deliveries/compare/v0.1.1...v0.2.0
27
37
  [0.1.1]: https://github.com/ecommerce-ventures/deliveries/compare/v0.1.0...v0.1.1
28
- [0.1.0]: https://github.com/ecommerce-ventures/deliveries/releases/tag/v0.1.0
38
+ [0.1.0]: https://github.com/ecommerce-ventures/deliveries/releases/tag/v0.1.0
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- deliveries (0.2.1)
4
+ deliveries (0.3.1)
5
5
  activesupport (>= 5.2.0)
6
6
  hexapdf
7
7
  httparty
@@ -12,7 +12,7 @@ PATH
12
12
  GEM
13
13
  remote: https://rubygems.org/
14
14
  specs:
15
- activesupport (6.1.4.1)
15
+ activesupport (6.1.7)
16
16
  concurrent-ruby (~> 1.0, >= 1.0.2)
17
17
  i18n (>= 1.6, < 2)
18
18
  minitest (>= 5.1)
@@ -27,40 +27,55 @@ GEM
27
27
  builder (3.2.4)
28
28
  byebug (11.1.3)
29
29
  cmdparse (3.0.7)
30
- concurrent-ruby (1.1.9)
30
+ concurrent-ruby (1.1.10)
31
31
  crack (0.4.5)
32
32
  rexml
33
+ date (3.3.3)
33
34
  diff-lcs (1.4.4)
34
35
  geom2d (0.3.1)
35
- gyoku (1.3.1)
36
+ gyoku (1.4.0)
36
37
  builder (>= 2.1.2)
38
+ rexml (~> 3.0)
37
39
  hashdiff (1.0.1)
38
- hexapdf (0.17.3)
40
+ hexapdf (0.28.0)
39
41
  cmdparse (~> 3.0, >= 3.0.3)
40
42
  geom2d (~> 0.3)
41
- httparty (0.20.0)
42
- mime-types (~> 3.0)
43
+ openssl (>= 2.2.1)
44
+ httparty (0.21.0)
45
+ mini_mime (>= 1.0.0)
43
46
  multi_xml (>= 0.5.2)
44
- httpi (2.5.0)
47
+ httpi (3.0.1)
45
48
  rack
46
- socksify
47
- i18n (1.8.11)
49
+ i18n (1.12.0)
48
50
  concurrent-ruby (~> 1.0)
49
- mime-types (3.3.1)
50
- mime-types-data (~> 3.2015)
51
- mime-types-data (3.2021.0901)
52
- mini_magick (4.11.0)
53
- minitest (5.14.4)
51
+ mail (2.8.0.1)
52
+ mini_mime (>= 0.1.1)
53
+ net-imap
54
+ net-pop
55
+ net-smtp
56
+ mini_magick (4.12.0)
57
+ mini_mime (1.1.2)
58
+ minitest (5.17.0)
54
59
  multi_xml (0.6.0)
55
- nokogiri (1.12.5-x86_64-linux)
60
+ net-imap (0.3.4)
61
+ date
62
+ net-protocol
63
+ net-pop (0.1.2)
64
+ net-protocol
65
+ net-protocol (0.2.1)
66
+ timeout
67
+ net-smtp (0.3.3)
68
+ net-protocol
69
+ nokogiri (1.13.10-x86_64-linux)
56
70
  racc (~> 1.4)
57
71
  nori (2.6.0)
72
+ openssl (3.1.0)
58
73
  parallel (1.21.0)
59
74
  parser (3.0.2.0)
60
75
  ast (~> 2.4.1)
61
76
  public_suffix (4.0.6)
62
- racc (1.6.0)
63
- rack (2.2.3)
77
+ racc (1.6.2)
78
+ rack (3.0.3)
64
79
  rainbow (3.0.0)
65
80
  rake (13.0.6)
66
81
  regexp_parser (2.1.1)
@@ -90,27 +105,28 @@ GEM
90
105
  rubocop-ast (1.12.0)
91
106
  parser (>= 3.0.1.1)
92
107
  ruby-progressbar (1.11.0)
93
- savon (2.12.1)
108
+ savon (2.13.0)
94
109
  akami (~> 1.2)
95
110
  builder (>= 2.1.2)
96
111
  gyoku (~> 1.2)
97
- httpi (~> 2.3)
112
+ httpi (>= 2.4.5)
113
+ mail (~> 2.5)
98
114
  nokogiri (>= 1.8.1)
99
115
  nori (~> 2.4)
100
116
  wasabi (~> 3.4)
101
- socksify (1.7.1)
102
- tzinfo (2.0.4)
117
+ timeout (0.3.1)
118
+ tzinfo (2.0.5)
103
119
  concurrent-ruby (~> 1.0)
104
120
  unicode-display_width (1.8.0)
105
- wasabi (3.6.1)
121
+ wasabi (3.8.0)
106
122
  addressable
107
- httpi (~> 2.0)
123
+ httpi (~> 3.0)
108
124
  nokogiri (>= 1.4.2)
109
125
  webmock (3.14.0)
110
126
  addressable (>= 2.8.0)
111
127
  crack (>= 0.3.2)
112
128
  hashdiff (>= 0.4.0, < 2.0.0)
113
- zeitwerk (2.5.1)
129
+ zeitwerk (2.6.6)
114
130
 
115
131
  PLATFORMS
116
132
  x86_64-linux
data/README.md CHANGED
@@ -6,7 +6,7 @@ Deliveries is a gem that gives you the ability to integrate multiple shipping se
6
6
 
7
7
  Add the following line to your Gemfile
8
8
 
9
- ```bash
9
+ ```ruby
10
10
  gem 'deliveries'
11
11
  ```
12
12
  Then run:
@@ -20,7 +20,7 @@ bundle install
20
20
  Each courier requires a different configuration, below we will leave some examples
21
21
 
22
22
  #### 1. Mondial Relay
23
- ```bash
23
+ ```ruby
24
24
  Deliveries.courier(:mondial_relay).configure do |config|
25
25
  config.mondial_relay_merchant = '...'
26
26
  config.mondial_relay_key = '...'
@@ -28,7 +28,7 @@ end
28
28
  ```
29
29
 
30
30
  #### 2. Mondial Relay Dual
31
- ```bash
31
+ ```ruby
32
32
  Deliveries.courier(:mondial_relay_dual).configure do |config|
33
33
  config.dual_carrier_login = '...'
34
34
  config.dual_carrier_password = '...'
@@ -48,7 +48,7 @@ end
48
48
  ```
49
49
 
50
50
  #### 3. Correos Express
51
- ```bash
51
+ ```ruby
52
52
  Deliveries.courier(:correos_express).configure do |config|
53
53
  config.username = '...'
54
54
  config.password = '...'
@@ -67,7 +67,7 @@ end
67
67
  ```
68
68
 
69
69
  #### 4. Spring
70
- ```bash
70
+ ```ruby
71
71
  Deliveries.courier(:spring).configure do |config|
72
72
  config.api_key = '...'
73
73
  config.countries = {
@@ -89,7 +89,7 @@ end
89
89
  ```
90
90
 
91
91
  #### 5. UPS
92
- ```bash
92
+ ```ruby
93
93
  Deliveries.courier(:ups).configure do |config|
94
94
  config.license_number = '...'
95
95
  config.username = '...'
@@ -103,25 +103,36 @@ Deliveries.courier(:ups).configure do |config|
103
103
  end
104
104
  ```
105
105
 
106
+ #### Time Zone
107
+
108
+ This library uses Active Support's Time extension, so a time zone must be set before using it:
109
+
110
+ ```ruby
111
+ require 'active_support/time'
112
+
113
+ # Configure time zone
114
+ Time.zone = 'Madrid'
115
+ ```
116
+
106
117
  ## Usage
107
118
 
108
119
  #### Get collection point by country and postcode
109
120
 
110
- ```bash
121
+ ```ruby
111
122
  # Example Using Ups
112
123
 
113
124
  Deliveries.courier(:ups).get_collection_points(postcode: '...', country: 'it')
114
125
  ```
115
126
  #### Get collection point info
116
127
 
117
- ```bash
128
+ ```ruby
118
129
  # Example Using Mondial Relay
119
130
 
120
131
  Deliveries.courier(:mondial_relay).get_collection_point(global_point_id: 'mondial_relay~fr~00000~XXXXXX')
121
132
  ```
122
133
 
123
134
  #### Create a Shipment
124
- ```bash
135
+ ```ruby
125
136
  # Example Using Correos Express
126
137
 
127
138
  sender = Deliveries::Address.new(
@@ -158,7 +169,7 @@ response = Deliveries.courier(:correos_express).create_shipment(
158
169
  ```
159
170
 
160
171
  #### Create a Pickup
161
- ```bash
172
+ ```ruby
162
173
  # Example Using Spring
163
174
 
164
175
  sender = Deliveries::Address.new(
@@ -193,7 +204,7 @@ response = Deliveries.courier(:spring).create_pickup(
193
204
  ```
194
205
 
195
206
  #### Download a Label
196
- ```bash
207
+ ```ruby
197
208
  # Example Using Spring
198
209
 
199
210
  label = Deliveries.courier(:spring).get_label(tracking_code: '...')
@@ -0,0 +1,50 @@
1
+ require 'httparty'
2
+
3
+ module Deliveries
4
+ module Couriers
5
+ module Envialia
6
+ module Authentication
7
+ include HTTParty
8
+
9
+ def session_id
10
+ response = HTTParty.post(
11
+ login_endpoint,
12
+ body: login_body,
13
+ headers: login_headers,
14
+ debug_output: Deliveries.debug ? Deliveries.logger : nil
15
+ )
16
+
17
+ raise Deliveries::ClientError unless response.success?
18
+
19
+ response.dig('Envelope', 'Header', 'ROClientIDHeader', 'ID')
20
+ end
21
+
22
+ def login_body
23
+ <<~XML
24
+ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
25
+ <soapenv:Body>
26
+ <tns:LoginWSService___LoginCli2 xmlns:tns="http://tempuri.org/">
27
+ <strCodAge>#{Deliveries.courier(:envialia).config(:agency_code)}</strCodAge>
28
+ <strCliente>#{Deliveries.courier(:envialia).config(:username)}</strCliente>
29
+ <strPass>#{Deliveries.courier(:envialia).config(:password)}</strPass>
30
+ </tns:LoginWSService___LoginCli2>
31
+ </soapenv:Body>
32
+ </soapenv:Envelope>
33
+ XML
34
+ end
35
+
36
+ def login_headers
37
+ { 'Content-Type' => 'application/json;charset=UTF-8', 'Accept' => 'application/json' }
38
+ end
39
+
40
+ def login_endpoint
41
+ if Envialia.live?
42
+ Envialia::ENVIALIA_LOGIN_ENDPOINT_LIVE
43
+ else
44
+ Envialia::ENVIALIA_LOGIN_ENDPOINT_TEST
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,88 @@
1
+ require 'httparty'
2
+
3
+ module Deliveries
4
+ module Couriers
5
+ module Envialia
6
+ module Labels
7
+ class Generate
8
+ include HTTParty
9
+ include Authentication
10
+
11
+ attr_accessor :tracking_codes
12
+
13
+ def initialize(tracking_codes:)
14
+ self.tracking_codes = tracking_codes.respond_to?(:each) ? tracking_codes : [tracking_codes]
15
+ end
16
+
17
+ def execute
18
+ decoded_labels = []
19
+
20
+ tracking_codes.each do |tracking_code|
21
+ response = self.class.post(
22
+ api_endpoint,
23
+ body: body(tracking_code),
24
+ headers: headers,
25
+ debug_output: Deliveries.debug ? Deliveries.logger : nil
26
+ )
27
+
28
+ raise Deliveries::ClientError unless response.success?
29
+
30
+ labels = response.dig('Envelope', 'Body', 'WebServService___ConsEtiquetaEnvio6Response', 'strEtiquetas')
31
+
32
+ if labels.blank?
33
+ raise Deliveries::APIError.new(
34
+ 'No hay etiqutas disponibles',
35
+ 404
36
+ )
37
+ else
38
+ decoded_labels << Base64.decode64(labels).force_encoding('binary')
39
+ end
40
+ end
41
+
42
+ decoded_labels
43
+ end
44
+
45
+ private
46
+
47
+ def body(tracking_code)
48
+ <<~XML
49
+ <?xml version="1.0" encoding="utf-8"?>
50
+ <soap:Envelope
51
+ xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
52
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
53
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema">
54
+ <soap:Header>
55
+ <ROClientIDHeader xmlns="http://tempuri.org/">
56
+ <ID>#{session_id}</ID>
57
+ </ROClientIDHeader>
58
+ </soap:Header>
59
+ <soap:Body>
60
+ <WebServService___ConsEtiquetaEnvio6>
61
+ <strCodAgeOri>#{Deliveries.courier(:envialia).config(:agency_code)}</strCodAgeOri>
62
+ <strAlbaran>#{tracking_code}</strAlbaran>
63
+ <strBulto></strBulto>
64
+ <boPaginaA4>false</boPaginaA4>
65
+ <intNumEtiqImpresasA4>0</intNumEtiqImpresasA4>
66
+ <strFormato>PDF</strFormato>
67
+ </WebServService___ConsEtiquetaEnvio6>
68
+ </soap:Body>
69
+ </soap:Envelope>
70
+ XML
71
+ end
72
+
73
+ def headers
74
+ { 'Content-Type' => 'application/json;charset=UTF-8', 'Accept' => 'application/json' }
75
+ end
76
+
77
+ def api_endpoint
78
+ if Envialia.live?
79
+ Envialia::ENVIALIA_ENDPOINT_LIVE
80
+ else
81
+ Envialia::ENVIALIA_ENDPOINT_TEST
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,147 @@
1
+ require 'httparty'
2
+
3
+ module Deliveries
4
+ module Couriers
5
+ module Envialia
6
+ module Pickups
7
+ class Create
8
+ include HTTParty
9
+ include Authentication
10
+
11
+ attr_accessor :sender, :receiver, :parcels,
12
+ :reference_code, :pickup_date, :remarks, :tracking_code
13
+
14
+ def initialize(sender:, receiver:, parcels:,
15
+ reference_code:, pickup_date:, remarks:, tracking_code:)
16
+
17
+ self.sender = sender
18
+ self.receiver = receiver
19
+ self.parcels = parcels
20
+ self.reference_code = reference_code
21
+ self.pickup_date = pickup_date
22
+ self.remarks = remarks
23
+ self.tracking_code = tracking_code
24
+ end
25
+
26
+ def execute
27
+ response = self.class.post(
28
+ api_endpoint,
29
+ body: body,
30
+ headers: headers,
31
+ debug_output: Deliveries.debug ? Deliveries.logger : nil
32
+ )
33
+
34
+ raise Deliveries::ClientError unless response.success?
35
+
36
+ pickup_number = response.dig('Envelope', 'Body', 'WebServService___GrabaRecogida3Response', 'strCodOut')
37
+
38
+ if pickup_number
39
+ Deliveries::Pickup.new(
40
+ courier_id: 'envialia',
41
+ sender: sender,
42
+ receiver: receiver,
43
+ parcels: parcels,
44
+ reference_code: reference_code,
45
+ tracking_code: pickup_number,
46
+ pickup_date: pickup_date
47
+ )
48
+ else
49
+ exception = response.dig('Envelope', 'Body', 'Fault')
50
+
51
+ if exception['faultcode'].eql?('Exception')
52
+ exception_code, exception_str = exception['faultstring'].split(':')
53
+ else
54
+ exception_code = 400
55
+ exception_str = exception['faultstring']
56
+ end
57
+
58
+ raise Deliveries::APIError.new(
59
+ exception_str.strip,
60
+ exception_code.to_i
61
+ )
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def body
68
+ <<~XML
69
+ <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
70
+ <soap:Header>
71
+ <ROClientIDHeader xmlns="http://tempuri.org/">
72
+ <ID>#{session_id}</ID>
73
+ </ROClientIDHeader>
74
+ </soap:Header>
75
+ <soap:Body>
76
+ <WebServService___GrabaRecogida3 xmlns="http://tempuri.org/">
77
+ <strCod></strCod>
78
+ <strAlbaran>#{tracking_code}</strAlbaran>
79
+ <strCodAgeCargo>#{Deliveries.courier(:envialia).config(:agency_code)}</strCodAgeCargo>
80
+ <strCodAgeOri></strCodAgeOri>
81
+ <dtFecRec>#{pickup_date.strftime('%Y/%m/%d')}</dtFecRec>
82
+ <strNomOri>#{sender.name}</strNomOri>
83
+ <strPobOri>#{sender.city}</strPobOri>
84
+ <strDirOri>#{sender.street}</strDirOri>
85
+ <strCPOri>#{format_postcode(sender.postcode, sender.country)}</strCPOri>
86
+ <strTlfOri>#{sender.phone}</strTlfOri>
87
+ <strNomDes>#{receiver.name}</strNomDes>
88
+ <strPobDes>#{receiver.city}</strPobDes>
89
+ <strDirDes>#{receiver.street}</strDirDes>
90
+ <strCPDes>#{format_postcode(receiver.postcode, receiver.country)}</strCPDes>
91
+ <strTlfDes>#{receiver.phone}</strTlfDes>
92
+ <strCodPais>#{receiver.country}</strCodPais>
93
+ <intBul>#{parcels}</intBul>
94
+ <strCodTipoServ>72</strCodTipoServ>
95
+ <dPesoOri>0</dPesoOri>
96
+ <dAltoOri>0</dAltoOri>
97
+ <dAnchoOri>0</dAnchoOri>
98
+ <dLargoOri>0</dLargoOri>
99
+ <dReembolso>0</dReembolso>
100
+ <dValor>0</dValor>
101
+ <dAnticipo>0</dAnticipo>
102
+ <dCobCli>0</dCobCli>
103
+ <strObs>#{remarks}</strObs>
104
+ <boSabado>false</boSabado>
105
+ <boRetorno>false</boRetorno>
106
+ <boGestOri>false</boGestOri>
107
+ <boGestDes>false</boGestDes>
108
+ <boAnulado>false</boAnulado>
109
+ <boAcuse>false</boAcuse>
110
+ <strRef>#{reference_code}</strRef>
111
+ <dBaseImp>0</dBaseImp>
112
+ <dImpuesto>0</dImpuesto>
113
+ <boPorteDebCli>false</boPorteDebCli>
114
+ <strDesDirEmails>#{receiver.email}</strDesDirEmails>
115
+ <boCampo5>false</boCampo5>
116
+ <boPagoDUAImp>false</boPagoDUAImp>
117
+ <boPagoImpDes>false</boPagoImpDes>
118
+ </WebServService___GrabaRecogida3>
119
+ </soap:Body>
120
+ </soap:Envelope>
121
+ XML
122
+ end
123
+
124
+ def headers
125
+ { 'Content-Type' => 'application/json;charset=UTF-8', 'Accept' => 'application/json' }
126
+ end
127
+
128
+ def api_endpoint
129
+ if Envialia.live?
130
+ Envialia::ENVIALIA_ENDPOINT_LIVE
131
+ else
132
+ Envialia::ENVIALIA_ENDPOINT_TEST
133
+ end
134
+ end
135
+
136
+ def format_postcode(postcode, country)
137
+ if country.to_sym.downcase == :pt
138
+ postcode&.split('-')&.first
139
+ else
140
+ postcode
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,94 @@
1
+ require 'active_support/time'
2
+ require 'active_support/core_ext/hash/conversions'
3
+ require 'active_support/core_ext/time'
4
+
5
+ module Deliveries
6
+ module Couriers
7
+ module Envialia
8
+ module Pickups
9
+ class Trace
10
+ class FormatResponse
11
+ attr_accessor :response
12
+
13
+ def initialize(response:)
14
+ self.response = response
15
+ end
16
+
17
+ STATUS_CODES = {
18
+ 'R0' => 'Solicitada',
19
+ 'R1' => 'Lectura en delegación',
20
+ 'R2' => 'Asignada',
21
+ 'R3' => 'Incidencia',
22
+ 'R4' => 'Realizada',
23
+ 'R5' => 'Pendiente de asignación',
24
+ 'R6' => 'Recogida fallida',
25
+ 'R7' => 'Finalizada',
26
+ 'R8' => 'Anulada',
27
+ 'R9' => 'Lectura repartidor'
28
+ }.freeze
29
+
30
+ def execute
31
+ body = response.dig('Envelope', 'Body', 'WebServService___ConsRecEstadosResponse', 'strRecEstados')
32
+ parsed_response = Hash.from_xml(body).dig('CONSULTA', 'REC_ESTADOS')
33
+
34
+ checkpoints = formatted_checkpoints(parsed_response)
35
+
36
+ tracking_info_params = {}
37
+ tracking_info_params[:courier_id] = 'envialia'
38
+ tracking_info_params[:tracking_code] = nil
39
+ tracking_info_params[:status] = checkpoints.last.try(:status)
40
+ tracking_info_params[:checkpoints] = checkpoints
41
+
42
+ tracking_info_params
43
+ end
44
+
45
+ private
46
+
47
+ def formatted_checkpoints(shipment_statuses)
48
+ checkpoints = []
49
+ if shipment_statuses.is_a?(Array)
50
+ shipment_statuses.each do |shipment_status|
51
+ checkpoints << formatted_checkpoint(shipment_status)
52
+ end
53
+ else
54
+ checkpoints << formatted_checkpoint(shipment_statuses)
55
+ end
56
+
57
+ checkpoints
58
+ end
59
+
60
+ def formatted_checkpoint(shipment_status)
61
+ status = STATUS_CODES[shipment_status['V_COD_TIPO_EST']]
62
+
63
+ date = shipment_status['D_FEC_HORA_ALTA']
64
+
65
+ Deliveries::Checkpoint.new(
66
+ status: status(status),
67
+ location: nil,
68
+ tracked_at: Time.zone.strptime(date, '%m/%d/%Y %H:%M:%S'),
69
+ description: status
70
+ )
71
+ end
72
+
73
+ def status(code)
74
+ case code
75
+ when 'Solicitada', 'Lectura en delegación', 'Asignada'
76
+ :registered
77
+ when 'Realizada', 'Recogida Parcial (Múltiples Destinos)'
78
+ :in_transit
79
+ when 'Recogida fallida', 'Datos insuficientes', 'Error al emitir la recogida'
80
+ :delivery_failed
81
+ when 'Anulada', 'Recogida anulada'
82
+ :cancelled
83
+ when 'Finalizada'
84
+ :delivered
85
+ else
86
+ :unknown_status
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,69 @@
1
+ require 'httparty'
2
+
3
+ module Deliveries
4
+ module Couriers
5
+ module Envialia
6
+ module Pickups
7
+ class Trace
8
+ include HTTParty
9
+ include Authentication
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
+ response = self.class.post(
19
+ api_endpoint,
20
+ body: body,
21
+ headers: headers,
22
+ debug_output: Deliveries.debug ? Deliveries.logger : nil
23
+ )
24
+
25
+ raise Deliveries::ClientError unless response.success?
26
+
27
+ if response.dig('Envelope', 'Body', 'WebServService___ConsRecEstadosResponse', 'strRecEstados').nil?
28
+ raise Deliveries::APIError.new(
29
+ 'No se han encontrado datos para este envío',
30
+ '402'
31
+ )
32
+ else
33
+ response
34
+ end
35
+ end
36
+
37
+ def body
38
+ <<~XML
39
+ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
40
+ <soapenv:Header>
41
+ <tns:ROClientIDHeader xmlns:tns="http://tempuri.org/">
42
+ <tns:ID>#{session_id}</tns:ID>
43
+ </tns:ROClientIDHeader>
44
+ </soapenv:Header>
45
+ <soapenv:Body>
46
+ <tns:WebServService___ConsRecEstados xmlns:tns="http://tempuri.org/">
47
+ <tns:strCodRec>#{tracking_code}</tns:strCodRec>
48
+ </tns:WebServService___ConsRecEstados>
49
+ </soapenv:Body>
50
+ </soapenv:Envelope>
51
+ XML
52
+ end
53
+
54
+ def headers
55
+ { 'Content-Type' => 'application/json;charset=UTF-8', 'Accept' => 'application/json' }
56
+ end
57
+
58
+ def api_endpoint
59
+ if Envialia.live?
60
+ Envialia::ENVIALIA_ENDPOINT_LIVE
61
+ else
62
+ Envialia::ENVIALIA_ENDPOINT_TEST
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,148 @@
1
+ require 'httparty'
2
+
3
+ module Deliveries
4
+ module Couriers
5
+ module Envialia
6
+ module Shipments
7
+ class Create
8
+ include HTTParty
9
+ include Authentication
10
+
11
+ attr_accessor :sender, :receiver, :collection_point, :parcels,
12
+ :reference_code, :shipment_date, :remarks
13
+
14
+ def initialize(sender:, receiver:, collection_point:, parcels:,
15
+ reference_code:, shipment_date:, remarks:)
16
+ self.sender = sender
17
+ self.receiver = receiver
18
+ self.collection_point = collection_point
19
+ self.parcels = parcels
20
+ self.reference_code = reference_code
21
+ self.shipment_date = shipment_date
22
+ self.remarks = remarks
23
+ end
24
+
25
+ def execute
26
+ response = self.class.post(
27
+ api_endpoint,
28
+ body: body,
29
+ headers: headers,
30
+ debug_output: Deliveries.debug ? Deliveries.logger : nil
31
+ )
32
+
33
+ raise Deliveries::ClientError unless response.success?
34
+
35
+ tracking_code = response.dig('Envelope', 'Body', 'WebServService___GrabaEnvio8Response', 'strAlbaranOut')
36
+
37
+ if tracking_code
38
+ Deliveries::Shipment.new(
39
+ courier_id: 'envialia',
40
+ sender: sender,
41
+ receiver: receiver,
42
+ parcels: parcels,
43
+ reference_code: reference_code,
44
+ tracking_code: tracking_code,
45
+ shipment_date: shipment_date,
46
+ label: nil
47
+ )
48
+ else
49
+ exception = response.dig('Envelope', 'Body', 'Fault')
50
+
51
+ if exception['faultcode'].eql?('Exception')
52
+ exception_code, exception_str = exception['faultstring'].split(':')
53
+ else
54
+ exception_code = 400
55
+ exception_str = exception['faultstring']
56
+ end
57
+
58
+ raise Deliveries::APIError.new(
59
+ exception_str.strip,
60
+ exception_code.to_i
61
+ )
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def body
68
+ <<~XML
69
+ <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
70
+ <soap:Header>
71
+ <ROClientIDHeader xmlns="http://tempuri.org/">
72
+ <ID>#{session_id}</ID>
73
+ </ROClientIDHeader>
74
+ </soap:Header>
75
+ <soap:Body>
76
+ <WebServService___GrabaEnvio8 xmlns="http://tempuri.org/">
77
+ <strCodAgeCargo>#{Deliveries.courier(:envialia).config(:agency_code)}</strCodAgeCargo>
78
+ <strCodAgeOri>#{Deliveries.courier(:envialia).config(:agency_code)}</strCodAgeOri>
79
+ <dtFecha>#{shipment_date.strftime('%Y/%m/%d')}</dtFecha>
80
+ <strCodTipoServ>72</strCodTipoServ>
81
+ <strCodCli>#{Deliveries.courier(:envialia).config(:username)}</strCodCli>
82
+ <strNomOri>#{sender.name}</strNomOri>
83
+ <strPobOri>#{sender.city}</strPobOri>
84
+ <strDirOri>#{sender.street}</strDirOri>
85
+ <strCPOri>#{format_postcode(sender.postcode, sender.country)}</strCPOri>
86
+ <strTlfOri>#{sender.phone}</strTlfOri>
87
+ <strNomDes>#{receiver.name}</strNomDes>
88
+ <strPobDes>#{receiver.city}</strPobDes>
89
+ <strDirDes>#{receiver.street}</strDirDes>
90
+ <strCPDes>#{format_postcode(receiver.postcode, receiver.country)}</strCPDes>
91
+ <strTlfDes>#{receiver.phone}</strTlfDes>
92
+ <strCodPais>#{receiver.country}</strCodPais>
93
+ <intDoc>0</intDoc>
94
+ <intPaq>#{parcels}</intPaq>
95
+ <dPesoOri>0</dPesoOri>
96
+ <dAltoOri>0</dAltoOri>
97
+ <dAnchoOri>0</dAnchoOri>
98
+ <dLargoOri>0</dLargoOri>
99
+ <dReembolso>0</dReembolso>
100
+ <dValor>0</dValor>
101
+ <dAnticipo>0</dAnticipo>
102
+ <dCobCli>0</dCobCli>
103
+ <strObs>#{remarks}</strObs>
104
+ <boSabado>false</boSabado>
105
+ <boRetorno>false</boRetorno>
106
+ <boGestOri>false</boGestOri>
107
+ <boGestDes>false</boGestDes>
108
+ <boAnulado>false</boAnulado>
109
+ <boAcuse>false</boAcuse>
110
+ <strRef>#{reference_code}</strRef>
111
+ <dBaseImp>0</dBaseImp>
112
+ <dImpuesto>0</dImpuesto>
113
+ <boPorteDebCli>false</boPorteDebCli>
114
+ <strDesDirEmails>#{receiver.email}</strDesDirEmails>
115
+ <boInsert>true</boInsert>
116
+ <boCampo5>false</boCampo5>
117
+ <boPagoDUAImp>false</boPagoDUAImp>
118
+ <boPagoImpDes>false</boPagoImpDes>
119
+ </WebServService___GrabaEnvio8>
120
+ </soap:Body>
121
+ </soap:Envelope>
122
+ XML
123
+ end
124
+
125
+ def headers
126
+ { 'Content-Type' => 'application/json;charset=UTF-8', 'Accept' => 'application/json' }
127
+ end
128
+
129
+ def api_endpoint
130
+ if Envialia.live?
131
+ Envialia::ENVIALIA_ENDPOINT_LIVE
132
+ else
133
+ Envialia::ENVIALIA_ENDPOINT_TEST
134
+ end
135
+ end
136
+
137
+ def format_postcode(postcode, country)
138
+ if country.to_sym.downcase == :pt
139
+ postcode&.split('-')&.first
140
+ else
141
+ postcode
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,97 @@
1
+ require 'active_support/time'
2
+ require 'active_support/core_ext/time'
3
+ require 'active_support/core_ext/hash/conversions'
4
+
5
+ module Deliveries
6
+ module Couriers
7
+ module Envialia
8
+ module Shipments
9
+ class Trace
10
+ class FormatResponse
11
+ attr_accessor :response
12
+
13
+ def initialize(response:)
14
+ self.response = response
15
+ end
16
+
17
+ STATUS_CODES = {
18
+ '0' => 'Documentado',
19
+ '1' => 'En Tránsito',
20
+ '2' => 'En Reparto',
21
+ '3' => 'Incidencia',
22
+ '4' => 'Entregado',
23
+ '5' => 'Devuelto',
24
+ '6' => 'Recanalizado',
25
+ '8' => 'Destruido (P.O.Delegación)',
26
+ '9' => 'Falta definitiva de expedición',
27
+ '10' => 'Pendiente nuevo reparto',
28
+ '11' => 'En CS destino',
29
+ '12' => 'Recogeran en delegacion',
30
+ '14' => 'Entrega Parcial',
31
+ '15' => 'Tránsito 72H.',
32
+ '16' => 'Pendiente de emisión'
33
+ }.freeze
34
+
35
+ def execute
36
+ body = response.dig('Envelope', 'Body', 'WebServService___ConsEnvEstadosResponse', 'strEnvEstados')
37
+ parsed_response = Hash.from_xml(body).dig('CONSULTA', 'ENV_ESTADOS')
38
+
39
+ checkpoints = formatted_checkpoints(parsed_response)
40
+
41
+ tracking_info_params = {}
42
+ tracking_info_params[:courier_id] = 'envialia'
43
+ tracking_info_params[:tracking_code] = nil
44
+ tracking_info_params[:status] = checkpoints.last.try(:status)
45
+ tracking_info_params[:checkpoints] = formatted_checkpoints(parsed_response)
46
+
47
+ tracking_info_params
48
+ end
49
+
50
+ private
51
+
52
+ def formatted_checkpoints(shipment_statuses)
53
+ checkpoints = []
54
+ if shipment_statuses.is_a?(Array)
55
+ shipment_statuses.each do |shipment_status|
56
+ checkpoints << formatted_checkpoint(shipment_status)
57
+ end
58
+ else
59
+ checkpoints << formatted_checkpoint(shipment_statuses)
60
+ end
61
+
62
+ checkpoints
63
+ end
64
+
65
+ def formatted_checkpoint(shipment_status)
66
+ status = STATUS_CODES[shipment_status['V_COD_TIPO_EST']]
67
+
68
+ date = shipment_status['D_FEC_HORA_ALTA']
69
+
70
+ Deliveries::Checkpoint.new(
71
+ status: status(status),
72
+ location: nil,
73
+ tracked_at: Time.zone.strptime(date, '%m/%d/%Y %H:%M:%S'),
74
+ description: status
75
+ )
76
+ end
77
+
78
+ def status(code)
79
+ case code
80
+ when 'Documentado'
81
+ :registered
82
+ when 'En Tránsito', 'En Reparto', 'En CS destino'
83
+ :in_transit
84
+ when 'Entregado'
85
+ :delivered
86
+ when 'Devuelto'
87
+ :cancelled
88
+ else
89
+ :unknown_status
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,71 @@
1
+ require 'httparty'
2
+
3
+ module Deliveries
4
+ module Couriers
5
+ module Envialia
6
+ module Shipments
7
+ class Trace
8
+ include HTTParty
9
+ include Authentication
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
+ response = self.class.post(
19
+ api_endpoint,
20
+ body: body,
21
+ headers: headers,
22
+ debug_output: Deliveries.debug ? Deliveries.logger : nil
23
+ )
24
+
25
+ raise Deliveries::ClientError unless response.success?
26
+
27
+ if response.dig('Envelope', 'Body', 'WebServService___ConsEnvEstadosResponse', 'strEnvEstados').nil?
28
+ raise Deliveries::APIError.new(
29
+ 'No se han encontrado datos para este envío',
30
+ '402'
31
+ )
32
+ else
33
+ response
34
+ end
35
+ end
36
+
37
+ def body
38
+ <<~XML
39
+ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
40
+ <soapenv:Header>
41
+ <tns:ROClientIDHeader xmlns:tns="http://tempuri.org/">
42
+ <tns:ID>#{session_id}</tns:ID>
43
+ </tns:ROClientIDHeader>
44
+ </soapenv:Header>
45
+ <soapenv:Body>
46
+ <tns:WebServService___ConsEnvEstados xmlns:tns="http://tempuri.org/">
47
+ <tns:strCodAgeCargo>#{Deliveries.courier(:envialia).config(:agency_code)}</tns:strCodAgeCargo>
48
+ <tns:strCodAgeOri>#{Deliveries.courier(:envialia).config(:agency_code)}</tns:strCodAgeOri>
49
+ <tns:strAlbaran>#{tracking_code}</tns:strAlbaran>
50
+ </tns:WebServService___ConsEnvEstados>
51
+ </soapenv:Body>
52
+ </soapenv:Envelope>
53
+ XML
54
+ end
55
+
56
+ def headers
57
+ { 'Content-Type' => 'application/json;charset=UTF-8', 'Accept' => 'application/json' }
58
+ end
59
+
60
+ def api_endpoint
61
+ if Envialia.live?
62
+ Envialia::ENVIALIA_ENDPOINT_LIVE
63
+ else
64
+ Envialia::ENVIALIA_ENDPOINT_TEST
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,93 @@
1
+ require_relative 'envialia/authentication'
2
+ require_relative 'envialia/shipments/create'
3
+ require_relative 'envialia/shipments/trace/format_response'
4
+ require_relative 'envialia/shipments/trace'
5
+ require_relative 'envialia/pickups/trace/format_response'
6
+ require_relative 'envialia/pickups/trace'
7
+ require_relative 'envialia/pickups/create'
8
+ require_relative 'envialia/labels/generate'
9
+
10
+ module Deliveries
11
+ module Couriers
12
+ module Envialia
13
+ extend Courier
14
+
15
+ Config = Struct.new(
16
+ :username,
17
+ :password,
18
+ :agency_code
19
+ )
20
+
21
+ ENVIALIA_LOGIN_ENDPOINT_LIVE = 'http://ws.envialia.com/SOAP?service=LoginService'.freeze
22
+ ENVIALIA_LOGIN_ENDPOINT_TEST = 'http://wstest.envialia.com:9085/SOAP?service=LoginService'.freeze
23
+ ENVIALIA_ENDPOINT_LIVE = 'http://ws.envialia.com/SOAP?service=WebServService'.freeze
24
+ ENVIALIA_ENDPOINT_TEST = 'http://wstest.envialia.com:9085/SOAP?service=WebServService'.freeze
25
+
26
+ module_function
27
+
28
+ def create_shipment(sender:, receiver:, parcels:, reference_code:, collection_point: nil, shipment_date: nil, remarks: nil, **)
29
+ Shipments::Create.new(
30
+ sender: sender,
31
+ receiver: receiver,
32
+ collection_point: collection_point,
33
+ shipment_date: shipment_date,
34
+ parcels: parcels,
35
+ reference_code: reference_code,
36
+ remarks: remarks
37
+ ).execute
38
+ end
39
+
40
+ def create_pickup(sender:, receiver:, parcels:, reference_code:, pickup_date: nil, remarks: nil, tracking_code: nil, **)
41
+ Pickups::Create.new(
42
+ sender: sender,
43
+ receiver: receiver,
44
+ parcels: parcels,
45
+ reference_code: reference_code,
46
+ pickup_date: pickup_date,
47
+ remarks: remarks,
48
+ tracking_code: tracking_code
49
+ ).execute
50
+ end
51
+
52
+ def shipment_info(tracking_code:, **)
53
+ response = Shipments::Trace.new(
54
+ tracking_code: tracking_code
55
+ ).execute
56
+
57
+ tracking_info_params = Shipments::Trace::FormatResponse.new(response: response).execute
58
+ tracking_info_params.merge!({ tracking_code: tracking_code })
59
+ Deliveries::TrackingInfo.new(**tracking_info_params)
60
+ end
61
+
62
+ def pickup_info(tracking_code:, **)
63
+ response = Pickups::Trace.new(
64
+ tracking_code: tracking_code
65
+ ).execute
66
+
67
+ tracking_info_params = Pickups::Trace::FormatResponse.new(response: response).execute
68
+ tracking_info_params.merge!({ tracking_code: tracking_code })
69
+ Deliveries::TrackingInfo.new(**tracking_info_params)
70
+ end
71
+
72
+ def get_label(tracking_code:, **)
73
+ pdf = Labels::Generate.new(
74
+ tracking_codes: tracking_code
75
+ ).execute.first
76
+
77
+ Deliveries::Label.new(raw: pdf)
78
+ end
79
+
80
+ def get_labels(tracking_codes:, **)
81
+ labels = Deliveries::Labels.new
82
+
83
+ Labels::Generate.new(
84
+ tracking_codes: tracking_codes
85
+ ).execute.each do |pdf|
86
+ labels << pdf
87
+ end
88
+
89
+ labels
90
+ end
91
+ end
92
+ end
93
+ end
@@ -71,7 +71,7 @@ module Deliveries
71
71
  week_hours = get_week_hours_from_result(result)
72
72
  week_hours.each do |i, times|
73
73
  timetable[i] = []
74
- if times[0] == '0000'
74
+ if times[0] == '0000' && times[1] == '0000'
75
75
  timetable[i] << nil
76
76
  else
77
77
  timetable[i] << formatted_slot(open: times[0], close: times[1])
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Deliveries
4
- VERSION = '0.2.1'
4
+ VERSION = '0.3.1'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deliveries
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fran Vega
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2021-11-04 00:00:00.000000000 Z
14
+ date: 2023-01-13 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activesupport
@@ -171,6 +171,15 @@ files:
171
171
  - lib/deliveries/couriers/correos_express/shipments/trace.rb
172
172
  - lib/deliveries/couriers/correos_express/shipments/trace/format_response.rb
173
173
  - lib/deliveries/couriers/dummy.rb
174
+ - lib/deliveries/couriers/envialia.rb
175
+ - lib/deliveries/couriers/envialia/authentication.rb
176
+ - lib/deliveries/couriers/envialia/labels/generate.rb
177
+ - lib/deliveries/couriers/envialia/pickups/create.rb
178
+ - lib/deliveries/couriers/envialia/pickups/trace.rb
179
+ - lib/deliveries/couriers/envialia/pickups/trace/format_response.rb
180
+ - lib/deliveries/couriers/envialia/shipments/create.rb
181
+ - lib/deliveries/couriers/envialia/shipments/trace.rb
182
+ - lib/deliveries/couriers/envialia/shipments/trace/format_response.rb
174
183
  - lib/deliveries/couriers/mondial_relay.rb
175
184
  - lib/deliveries/couriers/mondial_relay/address.rb
176
185
  - lib/deliveries/couriers/mondial_relay/collection_points/search/format_response.rb