pombo 1.0.0.pre.alpha → 1.0.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.
@@ -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