pombo 1.0.0.pre.alpha → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,16 @@
1
1
  module Pombo
2
- class Error < StandardError; end
2
+ # Generic exception
3
+ class Error < StandardError
4
+ def initializer(msg = nil)
5
+ super
3
6
 
7
+ Pombo.logger.error('exception.pombo') { msg }
8
+ end
9
+ end
10
+
11
+ # Exception triggered to manage settings
4
12
  class ConfigurationError < Pombo::Error; end
5
13
 
14
+ # Exception triggered when managing the webservice
6
15
  class WebserviceError < Pombo::Error; end
7
16
  end
@@ -0,0 +1,17 @@
1
+ require 'logger'
2
+
3
+ module Pombo
4
+ # Used to extend the Logger class and customize the message
5
+ # @exemple
6
+ # Pombo.logger.info('event.namespace'){ 'Any error message' }
7
+ # # => 2016-05-13 15:15:49 -0300 | POMBO | event.namespace | INFO: Any error message
8
+ class Logger < ::Logger
9
+
10
+ private
11
+
12
+ def format_message(severity, datetime, progname, msg)
13
+ "#{ datetime } | POMBO | #{ progname } | #{ severity }: #{ msg }\n"
14
+ end
15
+
16
+ end
17
+ end
data/lib/pombo/package.rb CHANGED
@@ -1,4 +1,25 @@
1
1
  module Pombo
2
+ # This is the composite package of items that will be sent
3
+ #
4
+ # @example
5
+ # package = Pombo::Package.new ({
6
+ # destination_zip_code: '29999000',
7
+ # origin_zip_code: '28888000',
8
+ # services: "40010",
9
+ # in_hand: false,
10
+ # delivery_notice: false
11
+ # })
12
+ # # => <Pombo::Package:0x007fcfd32080f0 @items=[], @length=0, @height=0, @width=0, @declared_value=0, @destination_zip_code="29999000", @origin_zip_code="28888000">
13
+ #
14
+ # package.add_item weight: 5, length: 4, height: 3, width: 5, diameter: 0
15
+ # package.add_item weight: 4, length: 10, height: 5, width: 5, diameter: 5, format: Pombo::Package::Format.find(:roll).code
16
+ # package.in_hand? # => false
17
+ # package.delivery_notice? # => false
18
+ # package.weight # => 9
19
+ # package.diameter # => 0
20
+ # package.format # => 1
21
+ # package.volume # => 158.17000000000002
22
+ # package.single_item? # => false
2
23
  class Package
3
24
  attr_accessor :destination_zip_code, :origin_zip_code, :declared_value
4
25
  attr_reader :items, :length, :height, :width, :services
@@ -9,6 +30,10 @@ module Pombo
9
30
  args.each { |key, value| __send__("#{ key }=", value) }
10
31
  end
11
32
 
33
+ # @!method in_hand?
34
+ # Informs you are contracted delivery in hand service
35
+ # @!method delivery_notice?
36
+ # Informs you are contracted delivery notice service
12
37
  %i[in_hand delivery_notice].each do |method|
13
38
  define_method("#{ method }?"){ instance_variable_get "@#{ method }" }
14
39
  end
@@ -20,45 +45,79 @@ module Pombo
20
45
  elsif Pombo::Support::FALSE_VALUES.include? value
21
46
  instance_variable_set "@#{ method }", false
22
47
  else
23
- raise TypeError, "no implicit conversion of #{ value } into True or False"
48
+ raise TypeError, "no implicit conversion of #{ value } into TrueClass or FalseClass"
24
49
  end
25
50
  end
26
51
  end
27
52
 
53
+ # @!method length
54
+ # returns the length of the package or the format if `min_package` is true
55
+ # @!method height
56
+ # returns the height of the package or the format if `min_package` is true
57
+ # @!method width
58
+ # returns the width of the package or the format if `min_package` is true
59
+ %i[length height width].each do |method|
60
+ define_method("#{ method }") do
61
+ value = instance_variable_get("@#{ method }")
62
+ return value unless Pombo.configurations.min_package?
63
+
64
+ current_format = Pombo::Package::Format.find(format)
65
+ [value, current_format.send("min_#{ method }")].max
66
+ end
67
+ end
68
+
69
+ # The services used to send the package
70
+ # @return [Array<String>] codes services
28
71
  def services=(services)
29
72
  @services = services.kind_of?(Array) ? services : [services]
30
73
  end
31
74
 
75
+ # It allows you to add an item to the package
76
+ # @return [Pombo::Package::Item] the added item
77
+ #
78
+ # @example
79
+ # item = Pombo::Package::Item.new weight: 5, length: 4, height: 3, width: 5, diameter: 0
80
+ # package.add_item item
81
+ #
82
+ # # => or
83
+ #
84
+ # package.add_item weight: 5, length: 4, height: 3, width: 5, diameter: 0
32
85
  def add_item(item = nil, **args)
33
86
  item = if item.kind_of?(Pombo::Package::Item)
34
- item
35
- else
36
- Pombo::Package::Item.new(args)
37
- end
87
+ item
88
+ else
89
+ Pombo::Package::Item.new(args)
90
+ end
38
91
 
39
92
  @items << item
40
93
  update_measures
41
94
  item
42
95
  end
43
96
 
97
+ # @return [Float] the total weight of the items
44
98
  def weight
45
99
  @items.inject(0) { |sum, item| sum += item.weight }
46
100
  end
47
101
 
102
+ # @return [Float] the total diameter of the items
48
103
  def diameter
49
104
  return @items.first.diameter if single_item? && format == Pombo::Package::Format.find(:roll).code
50
105
  0
51
106
  end
52
107
 
108
+ # @return [Fixnum] the code of the packet format
109
+ # For packages with more than one item format will be 1 (:box)
53
110
  def format
54
111
  return @items.first.format if single_item?
55
112
  Pombo::Package::Format.find(:box).code
56
113
  end
57
114
 
115
+ # @return [Float] the total volume of the items
58
116
  def volume
59
117
  @items.inject(0) { |sum, item| sum += item.volume }
60
118
  end
61
119
 
120
+ # @return [Boolean] tells if the package contains only one item
62
121
  def single_item?
63
122
  @items.size == 1 && @items.first.quantity == 1
64
123
  end
@@ -66,7 +125,16 @@ module Pombo
66
125
  private
67
126
 
68
127
  def update_measures
69
- @length = @height = @width = Math.cbrt volume
128
+ if single_item?
129
+ item = @items.first
130
+ @length, @height, @width = item.length, item.height, item.width
131
+ else
132
+ @length = @height = @width = Math.cbrt volume
133
+ end
134
+ end
135
+
136
+ def min_measure_for(measure, value)
137
+
70
138
  end
71
139
  end
72
140
  end
@@ -1,24 +1,44 @@
1
1
  module Pombo
2
2
  class Package
3
+ # The formats are pre-defined objects with the information provided by the Correios
3
4
  module Format
4
- @@all_formats = {
5
- '1' => OpenStruct.new(code: 1, name: 'Caixa/Pacote', max_length: 105, min_length: 16, max_height: 105, min_height: 2, max_width: 105, min_width: 11, max_dimension: 200),
6
- '2' => OpenStruct.new(code: 2, name: 'Rolo/Prisma', max_length: 105, min_length: 18, max_diameter: 91, min_diameter: 5, max_dimension: 200),
7
- '3' => OpenStruct.new(code: 3, name: 'Envelope', max_length: 60, min_length: 16, max_width: 60, min_width: 11, max_weight: 1),
8
- }
9
-
5
+ # List all formats supported by delivery services
6
+ # @return [Array<OpenStruct>] with the data structure representing a format
7
+ #
8
+ # @example
9
+ # Pombo::Package::Format.all
10
+ # # => [
11
+ # # => #<OpenStruct code=3, name="Envelope", max_length=60, min_length=16, max_width=60, min_width=11, max_weight=1>
12
+ # # => ....
13
+ # # => ]
14
+ #
10
15
  def self.all
11
- @@all_formats.values
16
+ [
17
+ OpenStruct.new(code: 1, name: Pombo.t('formats.1'), max_length: 105, min_length: 16, max_height: 105, min_height: 2, max_width: 105, min_width: 11, max_dimension: 200),
18
+ OpenStruct.new(code: 2, name: Pombo.t('formats.2'), max_length: 105, min_length: 18, max_diameter: 91, min_diameter: 5, max_dimension: 200),
19
+ OpenStruct.new(code: 3, name: Pombo.t('formats.3'), max_length: 60, min_length: 16, max_width: 60, min_width: 11, max_weight: 1)
20
+ ]
12
21
  end
13
22
 
23
+ # Find a specific format by code or by name
24
+ # @return [OpenStruct] the data structure representing a format
25
+ # @param code [String] code or the format name, to box `1, box or package`, to roll `2, roll or prism` and to envelope `3 or envelope`
26
+ # @example
27
+ # Pombo::Package::Format.find '3'
28
+ # # => #<OpenStruct code=3, name="Envelope", max_length=60, min_length=16, max_width=60, min_width=11, max_weight=1>
29
+ #
30
+ # # => Or
31
+ #
32
+ # Pombo::Package::Format.find 'envelope'
33
+ # # => #<OpenStruct code=3, name="Envelope", max_length=60, min_length=16, max_width=60, min_width=11, max_weight=1>
14
34
  def self.find(code)
15
35
  case code.to_s
16
36
  when '1', 'box', 'package'
17
- @@all_formats.values_at('1').first
37
+ all[0]
18
38
  when '2', 'roll', 'prism'
19
- @@all_formats.values_at('2').first
39
+ all[1]
20
40
  when '3', 'envelope'
21
- @@all_formats.values_at('3').first
41
+ all[2]
22
42
  end
23
43
  end
24
44
  end
@@ -1,4 +1,7 @@
1
1
  module Pombo
2
+ # Item is the object that will be sent in the package through the Brazilian Post Service
3
+ #
4
+ # By default the quantity is 1 and the format is +Pombo::Package::Format.find(:box).code+
2
5
  class Package::Item
3
6
  attr_accessor :weight, :length, :height, :width, :diameter, :quantity, :format
4
7
 
@@ -7,6 +10,8 @@ module Pombo
7
10
  args.each { |key, value| __send__("#{ key }=", value) }
8
11
  end
9
12
 
13
+ # Calculates the volume item in accordance with the format
14
+ # @return [Float] the volume value
10
15
  def volume
11
16
  case format
12
17
  when Pombo::Package::Format.find(:box).code
@@ -1,52 +1,88 @@
1
1
  require 'ostruct'
2
2
 
3
3
  module Pombo
4
+ # Contains delivery services
4
5
  module Services
5
- @@all_pac = {
6
- "41106" => OpenStruct.new(code: "41106", max_weight: 30, name: 'PAC', description: 'PAC (sem contrato)'),
7
- "41068" => OpenStruct.new(code: "41068", max_weight: 50, name: 'PAC', description: 'PAC (com contrato)'),
8
- "41300" => OpenStruct.new(code: "41300", max_weight: 600, name: 'PAC GF', description: 'PAC (grandes formatos)')
9
- }
10
-
11
- @@all_sedex = {
12
- "40010" => OpenStruct.new(code: "40010", max_weight: 30, name: 'SEDEX', description: 'SEDEX (sem contrato)'),
13
- "40045" => OpenStruct.new(code: "40045", max_weight: 30, name: 'SEDEX a cobrar', description: 'SEDEX a cobrar (sem contrato)'),
14
- "40126" => OpenStruct.new(code: "40126", max_weight: 30, name: 'SEDEX a cobrar', description: 'SEDEX a cobrar (com contrato)'),
15
- "40215" => OpenStruct.new(code: "40215", max_weight: 10, name: 'SEDEX 10', description: 'SEDEX 10 (sem contrato)'),
16
- "40290" => OpenStruct.new(code: "40290", max_weight: 10, name: 'SEDEX hoje', description: 'SEDEX hoje (sem contrato)'),
17
- "40096" => OpenStruct.new(code: "40096", max_weight: 30, name: 'SEDEX', description: 'SEDEX (com contrato)'),
18
- "40436" => OpenStruct.new(code: "40436", max_weight: 30, name: 'SEDEX', description: 'SEDEX (com contrato)'),
19
- "40444" => OpenStruct.new(code: "40444", max_weight: 30, name: 'SEDEX', description: 'SEDEX (com contrato)'),
20
- "40568" => OpenStruct.new(code: "40568", max_weight: 30, name: 'SEDEX', description: 'SEDEX (com contrato)'),
21
- "40606" => OpenStruct.new(code: "40606", max_weight: 30, name: 'SEDEX', description: 'SEDEX (com contrato)')
22
- }
23
-
24
- @@all_e_sedex = {
25
- "81019" => OpenStruct.new(code: "81019", max_weight: 15, name: 'E-SEDEX', description: 'E-SEDEX (com contrato)'),
26
- "81027" => OpenStruct.new(code: "81027", max_weight: 15, name: 'E-SEDEX', description: 'E-SEDEX Prioritário (com contrato)'),
27
- "81035" => OpenStruct.new(code: "81035", max_weight: 15, name: 'E-SEDEX', description: 'E-SEDEX Express (com contrato)'),
28
- "81868" => OpenStruct.new(code: "81868", max_weight: 15, name: 'E-SEDEX', description: 'E-SEDEX (com contrato, grupo 1)'),
29
- "81833" => OpenStruct.new(code: "81833", max_weight: 15, name: 'E-SEDEX', description: 'E-SEDEX (com contrato, grupo 2)'),
30
- "81850" => OpenStruct.new(code: "81850", max_weight: 15, name: 'E-SEDEX', description: 'E-SEDEX (com contrato, grupo 3)')
31
- }
32
-
33
- @@all_services = @@all_pac.merge(@@all_sedex).merge(@@all_e_sedex)
34
-
6
+ # List all services supported
7
+ # @param service [Symbol] group services, `:pac`, `sedex` or `e_sedex`
8
+ # @return [Array<OpenStruct>] with the data structure representing a service
9
+ #
10
+ # @example
11
+ # Pombo::Services.all
12
+ # # => [
13
+ # # => #<OpenStruct code="41106", max_weight=30, name="PAC", description="PAC (without contract)">,
14
+ # # => ....
15
+ # # => ]
16
+ #
17
+ # Listing all the services of a group
18
+ #
19
+ # @example
20
+ # Pombo::Services.all :pac
21
+ # # => [
22
+ # # => #<OpenStruct code="41106", max_weight=30, name="PAC", description="PAC (without contract)">,
23
+ # # => ....
24
+ # # => ]
25
+ #
35
26
  def self.all(service = nil)
36
27
  case service
37
28
  when :pac
38
- @@all_pac.values
29
+ all_pac.values
39
30
  when :sedex
40
- @@all_sedex.values
31
+ all_sedex.values
41
32
  when :e_sedex
42
- @@all_e_sedex.values
33
+ all_e_sedex.values
43
34
  else
44
- @@all_pac.values + @@all_sedex.values + @@all_e_sedex.values
35
+ all_pac.values + all_sedex.values + all_e_sedex.values
45
36
  end
46
37
  end
47
38
 
39
+ # Search for a service code
40
+ # @return [OpenStruct] the data structure representing a service
41
+ # @example
42
+ # Pombo::Services.find "41106"
43
+ # # => #<OpenStruct code="41106", max_weight=30, name="PAC", description="PAC (without contract)">
48
44
  def self.find(code)
49
- @@all_services.values_at(code).first
45
+ all_services.values_at(code).first
46
+ end
47
+
48
+ private
49
+
50
+ def self.all_pac
51
+ {
52
+ "41106" => OpenStruct.new(code: "41106", max_weight: 30, name: 'PAC', description: Pombo.t('services.pac.41106')),
53
+ "41068" => OpenStruct.new(code: "41068", max_weight: 50, name: 'PAC', description: Pombo.t('services.pac.41068')),
54
+ "41300" => OpenStruct.new(code: "41300", max_weight: 600, name: 'PAC GF', description: Pombo.t('services.pac.41300'))
55
+ }
56
+ end
57
+
58
+ def self.all_sedex
59
+ {
60
+ "40010" => OpenStruct.new(code: "40010", max_weight: 30, name: 'SEDEX', description: Pombo.t('services.sedex.40010')),
61
+ "40045" => OpenStruct.new(code: "40045", max_weight: 30, name: 'SEDEX a cobrar', description: Pombo.t('services.sedex.40045')),
62
+ "40126" => OpenStruct.new(code: "40126", max_weight: 30, name: 'SEDEX a cobrar', description: Pombo.t('services.sedex.40126')),
63
+ "40215" => OpenStruct.new(code: "40215", max_weight: 10, name: 'SEDEX 10', description: Pombo.t('services.sedex.40215')),
64
+ "40290" => OpenStruct.new(code: "40290", max_weight: 10, name: 'SEDEX hoje', description: Pombo.t('services.sedex.40290')),
65
+ "40096" => OpenStruct.new(code: "40096", max_weight: 30, name: 'SEDEX', description: Pombo.t('services.sedex.40096')),
66
+ "40436" => OpenStruct.new(code: "40436", max_weight: 30, name: 'SEDEX', description: Pombo.t('services.sedex.40436')),
67
+ "40444" => OpenStruct.new(code: "40444", max_weight: 30, name: 'SEDEX', description: Pombo.t('services.sedex.40444')),
68
+ "40568" => OpenStruct.new(code: "40568", max_weight: 30, name: 'SEDEX', description: Pombo.t('services.sedex.40568')),
69
+ "40606" => OpenStruct.new(code: "40606", max_weight: 30, name: 'SEDEX', description: Pombo.t('services.sedex.40606'))
70
+ }
71
+ end
72
+
73
+ def self.all_e_sedex
74
+ {
75
+ "81019" => OpenStruct.new(code: "81019", max_weight: 15, name: 'E-SEDEX', description: Pombo.t('services.e_sedex.81019')),
76
+ "81027" => OpenStruct.new(code: "81027", max_weight: 15, name: 'E-SEDEX', description: Pombo.t('services.e_sedex.81027')),
77
+ "81035" => OpenStruct.new(code: "81035", max_weight: 15, name: 'E-SEDEX', description: Pombo.t('services.e_sedex.81035')),
78
+ "81868" => OpenStruct.new(code: "81868", max_weight: 15, name: 'E-SEDEX', description: Pombo.t('services.e_sedex.81868')),
79
+ "81833" => OpenStruct.new(code: "81833", max_weight: 15, name: 'E-SEDEX', description: Pombo.t('services.e_sedex.81833')),
80
+ "81850" => OpenStruct.new(code: "81850", max_weight: 15, name: 'E-SEDEX', description: Pombo.t('services.e_sedex.81850'))
81
+ }
82
+ end
83
+
84
+ def self.all_services
85
+ all_pac.merge(all_sedex).merge(all_e_sedex)
50
86
  end
51
87
  end
52
88
  end
data/lib/pombo/support.rb CHANGED
@@ -1,13 +1,26 @@
1
1
  module Pombo
2
+ # Generic methods
2
3
  module Support
3
4
  TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE']
4
5
  FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE']
5
6
 
7
+ # Convert the string of Brazilian currency to float
8
+ # @return [String] the converted string pattern R$ (unit brazilian) to pattern Float.
9
+ # @raise [TypeError] if the value is not a String
10
+ # @example
11
+ # Pombo::Support.str_real_to_float('2,00')
12
+ # # => '2.00'
6
13
  def self.str_real_to_float(value)
7
14
  raise TypeError, "no implicit conversion of #{ value.class.name } into String" unless value.kind_of? String
8
- value.gsub(',','.').to_f
15
+ value.tr(',','.').to_f
9
16
  end
10
17
 
18
+ # Used to convert Boolean values to String
19
+ # @param [Boolean] the value to be converted
20
+ # @return [String] the string representation of a boolean. 'S' to +true+ and 'N' to +false+
21
+ # @example
22
+ # Pombo::Support.boolean_to_string(true)
23
+ # # => 'S'
11
24
  def self.boolean_to_string(value)
12
25
  value ? 'S' : 'N'
13
26
  end
data/lib/pombo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Pombo
2
- VERSION = "1.0.0.pre.alpha"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -1,4 +1,5 @@
1
1
  module Pombo
2
+ # Namespace for webservices
2
3
  module Webservice
3
4
  end
4
5
  end
@@ -3,9 +3,12 @@ require 'net/http'
3
3
 
4
4
  module Pombo
5
5
  module Webservice
6
+ # Class contains the base to make requests
7
+ # @abstract
6
8
  class Base
7
9
 
8
10
  def self.get(url, request = nil)
11
+ Pombo.logger.info('start_request.webservice') { "GET request: #{ url }" }
9
12
  uri = URI.parse url
10
13
  uri.query = request.to_param unless request.nil?
11
14
  http_request = Net::HTTP::Get.new uri
@@ -22,7 +25,9 @@ module Pombo
22
25
  http = Net::HTTP.new host, port
23
26
  #http.set_debug_output($stdout)
24
27
  http.open_timeout = Pombo.configurations.request_timeout
25
- http.request(http_request)
28
+ response = http.request(http_request)
29
+ Pombo.logger.info('end_request.webservice') { "GET #{ response.code } response: #{ response.body }" }
30
+ response
26
31
  end
27
32
  end
28
33
  end
@@ -7,20 +7,21 @@ module Pombo
7
7
  URL = "#{ PROTOCOL }://#{ HOST }/calculador/CalcPrecoPrazo.asmx"
8
8
 
9
9
  def self.shipping(package)
10
- url = "#{ URL }/CalcPrecoPrazo"
11
- response = Response.new get(url, ShippingRequest.new(package))
12
- response.body
10
+ resource "#{ URL }/CalcPrecoPrazo", ShippingRequest.new(package)
13
11
  end
14
12
 
15
13
  def self.delivery_time(package)
16
- url = "#{ URL }/CalcPrazo"
17
- response = Response.new get(url, DeliveryTimeRequest.new(package))
18
- response.body
14
+ resource "#{ URL }/CalcPrazo", DeliveryTimeRequest.new(package)
19
15
  end
20
16
 
21
17
  def self.shipping_value(package)
22
- url = "#{ URL }/CalcPreco"
23
- response = Response.new get(url, ShippingValueRequest.new(package))
18
+ resource "#{ URL }/CalcPreco", ShippingValueRequest.new(package)
19
+ end
20
+
21
+ private
22
+
23
+ def self.resource(url, request)
24
+ response = Response.new get(url, request)
24
25
  response.body
25
26
  end
26
27
  end