pombo 1.0.0.beta

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.
@@ -0,0 +1,67 @@
1
+ module Pombo
2
+ # It allows you to modify the settings of Pombo
3
+ # @!attribute [rw] contract_code
4
+ # Its administrative code by the ECT
5
+ # @!attribute [rw] password
6
+ # Password to access the service, associated with its contract code
7
+ # @!attribute [rw] extends_delivery
8
+ # Days late on a package
9
+ # @!attribute [rw] request_timeout
10
+ # Second delay when accessing the webservice
11
+ # @!attribute [rw] log_level
12
+ # Level compatible with Ruby Logger
13
+ # @!attribute [rw] logger
14
+ # Object to trigger messages (defaults to +Pombo::Logger+)
15
+ # @!attribute [rw] locale
16
+ # Tells you what language will be used (defaults to `pt-BR`)
17
+ class Configuration
18
+ @@default = {
19
+ contract_code: nil,
20
+ password: nil,
21
+ extends_delivery: 0,
22
+ log_level: Pombo::Logger::INFO,
23
+ logger: Pombo::Logger.new(STDOUT),
24
+ request_timeout: 5,
25
+ locale: 'pt-BR'
26
+ }
27
+
28
+ attr_accessor :contract_code, :password, :extends_delivery, :log_level, :logger, :request_timeout, :locale
29
+
30
+ def initialize(**args)
31
+ args = @@default.merge(args)
32
+ args.each { |key, value| __send__("#{ key }=", value) }
33
+
34
+ logger.level = log_level
35
+ end
36
+
37
+ # Saves the current state of the standard as an object
38
+ # @return [Pombo::Configuration] with default settings
39
+ def set_default
40
+ attributes = {}
41
+ instance_variables.each{ |v| attributes[v.to_s.delete('@').to_sym] = instance_variable_get(v) }
42
+ @@default.merge!(attributes)
43
+ Pombo.logger.info('update.configuration'){ 'Update the default settings' }
44
+ self
45
+ end
46
+
47
+ # Inform settings for persisting with default
48
+ # @param [Proc] with the configuration data.
49
+ # @return [Pombo::Configuration] the updated settings
50
+ # @raise [Pombo::ConfigurationError] if not passed a block
51
+ def self.setup(&block)
52
+ if block_given?
53
+ config = new
54
+ block.call config
55
+ config.set_default
56
+ self
57
+ else
58
+ raise Pombo::ConfigurationError, 'expected block the .setup'
59
+ end
60
+ end
61
+
62
+ # @return [Hash] The settings that are set as default
63
+ def self.default
64
+ @@default
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,16 @@
1
+ module Pombo
2
+ # Generic exception
3
+ class Error < StandardError
4
+ def initializer(msg = nil)
5
+ super
6
+
7
+ Pombo.logger.error('exception.pombo') { msg }
8
+ end
9
+ end
10
+
11
+ # Exception triggered to manage settings
12
+ class ConfigurationError < Pombo::Error; end
13
+
14
+ # Exception triggered when managing the webservice
15
+ class WebserviceError < Pombo::Error; end
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
@@ -0,0 +1,120 @@
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
23
+ class Package
24
+ attr_accessor :destination_zip_code, :origin_zip_code, :declared_value
25
+ attr_reader :items, :length, :height, :width, :services
26
+
27
+ def initialize(**args)
28
+ { items: [], length: 0, height: 0, width: 0 }.each { |key, value| instance_variable_set("@#{ key }", value) }
29
+ args = { declared_value: 0 }.merge(args)
30
+ args.each { |key, value| __send__("#{ key }=", value) }
31
+ end
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
37
+ %i[in_hand delivery_notice].each do |method|
38
+ define_method("#{ method }?"){ instance_variable_get "@#{ method }" }
39
+ end
40
+
41
+ %i[in_hand delivery_notice].each do |method|
42
+ define_method("#{ method }=") do |value|
43
+ if Pombo::Support::TRUE_VALUES.include? value
44
+ instance_variable_set "@#{ method }", true
45
+ elsif Pombo::Support::FALSE_VALUES.include? value
46
+ instance_variable_set "@#{ method }", false
47
+ else
48
+ raise TypeError, "no implicit conversion of #{ value } into True or False"
49
+ end
50
+ end
51
+ end
52
+
53
+ # The services used to send the package
54
+ # @return [Array<String>] codes services
55
+ def services=(services)
56
+ @services = services.kind_of?(Array) ? services : [services]
57
+ end
58
+
59
+ # It allows you to add an item to the package
60
+ # @return [Pombo::Package::Item] the added item
61
+ #
62
+ # @example
63
+ # item = Pombo::Package::Item.new weight: 5, length: 4, height: 3, width: 5, diameter: 0
64
+ # package.add_item item
65
+ #
66
+ # # => or
67
+ #
68
+ # package.add_item weight: 5, length: 4, height: 3, width: 5, diameter: 0
69
+ def add_item(item = nil, **args)
70
+ item = if item.kind_of?(Pombo::Package::Item)
71
+ item
72
+ else
73
+ Pombo::Package::Item.new(args)
74
+ end
75
+
76
+ @items << item
77
+ update_measures
78
+ item
79
+ end
80
+
81
+ # @return [Float] the total weight of the items
82
+ def weight
83
+ @items.inject(0) { |sum, item| sum += item.weight }
84
+ end
85
+
86
+ # @return [Float] the total diameter of the items
87
+ def diameter
88
+ return @items.first.diameter if single_item? && format == Pombo::Package::Format.find(:roll).code
89
+ 0
90
+ end
91
+
92
+ # @return [Fixnum] the code of the packet format
93
+ # For packages with more than one item format will be 1 (:box)
94
+ def format
95
+ return @items.first.format if single_item?
96
+ Pombo::Package::Format.find(:box).code
97
+ end
98
+
99
+ # @return [Float] the total volume of the items
100
+ def volume
101
+ @items.inject(0) { |sum, item| sum += item.volume }
102
+ end
103
+
104
+ # @return [Boolean] tells if the package contains only one item
105
+ def single_item?
106
+ @items.size == 1 && @items.first.quantity == 1
107
+ end
108
+
109
+ private
110
+
111
+ def update_measures
112
+ if single_item?
113
+ item = @items.first
114
+ @length, @height, @width = item.length, item.height, item.width
115
+ else
116
+ @length = @height = @width = Math.cbrt volume
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,46 @@
1
+ module Pombo
2
+ class Package
3
+ # The formats are pre-defined objects with the information provided by the Correios
4
+ module Format
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
+ #
15
+ def self.all
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
+ ]
21
+ end
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>
34
+ def self.find(code)
35
+ case code.to_s
36
+ when '1', 'box', 'package'
37
+ all[0]
38
+ when '2', 'roll', 'prism'
39
+ all[1]
40
+ when '3', 'envelope'
41
+ all[2]
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,37 @@
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+
5
+ class Package::Item
6
+ attr_accessor :weight, :length, :height, :width, :diameter, :quantity, :format
7
+
8
+ def initialize(**args)
9
+ args = { weight: 0.0, length: 0.0, height: 0.0, width: 0.0, diameter: 0.0, quantity: 1, format: Pombo::Package::Format.find(:box).code }.merge(args)
10
+ args.each { |key, value| __send__("#{ key }=", value) }
11
+ end
12
+
13
+ # Calculates the volume item in accordance with the format
14
+ # @return [Float] the volume value
15
+ def volume
16
+ case format
17
+ when Pombo::Package::Format.find(:box).code
18
+ package_volume * quantity
19
+ when Pombo::Package::Format.find(:roll).code
20
+ roll_volume * quantity
21
+ when Pombo::Package::Format.find(:envelope).code
22
+ 0
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def package_volume
29
+ length.to_f * width.to_f * height.to_f
30
+ end
31
+
32
+ def roll_volume
33
+ radius = diameter.to_f / 2
34
+ (height.to_f * (Math::PI * radius**2)).round(2)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,88 @@
1
+ require 'ostruct'
2
+
3
+ module Pombo
4
+ # Contains delivery services
5
+ module Services
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
+ #
26
+ def self.all(service = nil)
27
+ case service
28
+ when :pac
29
+ all_pac.values
30
+ when :sedex
31
+ all_sedex.values
32
+ when :e_sedex
33
+ all_e_sedex.values
34
+ else
35
+ all_pac.values + all_sedex.values + all_e_sedex.values
36
+ end
37
+ end
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)">
44
+ def self.find(code)
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)
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,28 @@
1
+ module Pombo
2
+ # Generic methods
3
+ module Support
4
+ TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE']
5
+ FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE']
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'
13
+ def self.str_real_to_float(value)
14
+ raise TypeError, "no implicit conversion of #{ value.class.name } into String" unless value.kind_of? String
15
+ value.tr(',','.').to_f
16
+ end
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'
24
+ def self.boolean_to_string(value)
25
+ value ? 'S' : 'N'
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module Pombo
2
+ VERSION = "1.0.0.beta"
3
+ end
@@ -0,0 +1,5 @@
1
+ module Pombo
2
+ # Namespace for webservices
3
+ module Webservice
4
+ end
5
+ end
@@ -0,0 +1,34 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+
4
+ module Pombo
5
+ module Webservice
6
+ # Class contains the base to make requests
7
+ # @abstract
8
+ class Base
9
+
10
+ def self.get(url, request = nil)
11
+ Pombo.logger.info('start_request.webservice') { "GET - #{ url }" }
12
+ uri = URI.parse url
13
+ uri.query = request.to_param unless request.nil?
14
+ http_request = Net::HTTP::Get.new uri
15
+ http http_request, uri.host, uri.port
16
+ rescue TypeError
17
+ raise WebserviceError, "can't solve the given URL"
18
+ rescue NoMethodError
19
+ raise WebserviceError, "can't parameterize the data provided"
20
+ end
21
+
22
+ private
23
+
24
+ def self.http(http_request, host, port)
25
+ http = Net::HTTP.new host, port
26
+ #http.set_debug_output($stdout)
27
+ http.open_timeout = Pombo.configurations.request_timeout
28
+ response = http.request(http_request)
29
+ Pombo.logger.info('end_request.webservice') { response.inspect }
30
+ response
31
+ end
32
+ end
33
+ end
34
+ end