eleVAT 1.0.1

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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 01b6b289ace0072baff51ec1c0752b1860359e72
4
+ data.tar.gz: 9505ddeeda0424b65a19353243e88b4af2ec4257
5
+ SHA512:
6
+ metadata.gz: 159cc376f7223e7b3c707c33966cd1c34a83aa6dd7f91aaa3edce997911fd64f1230c5289fd634301da5ea69bd834fcb52ef8ce18b68f18e3d3df2d1144d0fd2
7
+ data.tar.gz: 2cdec9bb307d8d9f40d609115700018462e44976c108e6de39e0ac214c32b69d6ccfc6ee0bdc05adea791fc4d7f6f3ad170d49b8b26edbb5358185b786a3bd46
@@ -0,0 +1,18 @@
1
+ c
2
+ product.key?(:name)c
3
+ product.key?(:name)
4
+ product.key?(:name, :quantity)
5
+ product.key?([:name, :quantity])
6
+ product
7
+ product.
8
+ c
9
+ product.keys & [:quantity, :name, :net_price, :taxable, :imported, :gross_price, :tax].size == product.keys.size
10
+ c
11
+ product.keys && [:quantity, :name, :net_price, :taxable, :imported, :gross_price, :tax].size == product.keys.size
12
+ product.keys && [:quantity, :name, :net_price, :taxable, :imported, :gross_price, :tax].size == 7
13
+ product.keys && [:quantity, :name, :net_price, :taxable, :imported, :gross_price, :tax]
14
+ product.keys == [:quantity, :name, :net_price, :taxable, :imported, :gross_price, :tax]
15
+ product.class == Hash && product.keys == [:quantity, :name, :net_price, :taxable, :imported, :gross_price, :tax]
16
+ n
17
+ product.keys
18
+ product
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /.byebug_hystory
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
11
+ /*.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in eleVAT.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Simone
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,79 @@
1
+ # EleVAT
2
+
3
+ This gem is a simple receipts creator. It allow you to calculate the amount of taxes and the amount of the total price for a list of products.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'eleVAT'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install eleVAT
20
+
21
+ ## Usage
22
+
23
+ Configure the tax rates, the rounding precision and the list of tax free items
24
+
25
+ ```ruby
26
+ require 'eleVAT'
27
+
28
+ EleVAT.configure do |config|
29
+ # Rate for all the items except for the items included in the tax free item
30
+ # list
31
+ config.basic_tax_rate = 10
32
+ # Rate for the imported items
33
+ config.import_tax_rate = 5
34
+ # list of tax free items
35
+ config.tax_free_items = %w(chocolate chocolates pills book)
36
+ # Tax amount will be rounded up to the nearest rounding precision value
37
+ config.rounding_precision = 0.05
38
+ end
39
+ ```
40
+
41
+ Use the `EleVAT::Importer` to import products and the `EleVAT::Recipt` to calculate the amounts.
42
+ ```ruby
43
+ # For each product the string pattern have to be '$quantity $name at $net_price'
44
+ importer = Importer.new(
45
+ '1 imported box of chocolates at 10.00 1 imported bottle of perfume at 47.50'
46
+ )
47
+ data_for_receipt = importer.export_data_for_receipt
48
+ receipt = Receipt.new data_for_receipt
49
+ ```
50
+ You can calculate the the amounts using the following `receipt.calculate_total` and `receipt.calculate_taxes` and access the value through `receipt.total_amount`
51
+ and `receipt.taxes`. You can also access the products list `receipt.products`.
52
+
53
+ If you don't need to use the importer you can create manually the products and add them to the receipt after prepareing them.
54
+
55
+ ```ruby
56
+ product = Product.new(1, 'Chocolate', 2.0, taxable = true, imported = false)
57
+ receipt.add(product.prepare_for_receipt)
58
+ # or
59
+ product_2 = Product.new(1, 'Beer', 5.0).prepare_for_receipt
60
+ product_3 = Product.new(1, 'Lemon', 2.0).prepare_for_receipt
61
+ receipt.add([product_2, product_3])
62
+ ```
63
+
64
+ Use `receipt.to_s` to view the printable receipt.
65
+
66
+ ## TO DO
67
+
68
+ 1. Implement the importer function to precess xls file
69
+ 2. Implement the function receipt `to_xls`
70
+ 3. Implement the importer function to precess csv file
71
+ 4. Implement the function receipt `to_csv`
72
+
73
+ ## Contributing
74
+
75
+ 1. Fork it ( https://github.com/[my-github-username]/eleVAT/fork )
76
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
77
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
78
+ 4. Push to the branch (`git push origin my-new-feature`)
79
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "eleVAT"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'eleVAT/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "eleVAT"
8
+ spec.version = EleVAT::VERSION
9
+ spec.authors = ["Simone Romanelli"]
10
+ spec.email = ["simone.romanelli.dev@gmail.com"]
11
+ spec.homepage = 'https://github.com/simoneromanelli/eleVAT'
12
+
13
+ spec.summary = "eleVAT"
14
+ spec.description = "A simple receipts calculator."
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "rspec", "~> 3.0"
23
+ spec.add_development_dependency "bundler", "~> 1.8"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "byebug"
26
+ end
@@ -0,0 +1,35 @@
1
+ require 'eleVAT/configuration'
2
+ require 'eleVAT/product'
3
+ require 'eleVAT/receipt'
4
+ require 'eleVAT/importer'
5
+
6
+ module EleVAT
7
+ def self.configure
8
+ @config ||= Configuration.new
9
+ yield(@config) if block_given?
10
+ @config
11
+ end
12
+
13
+ def self.config
14
+ @config || configure
15
+ end
16
+
17
+ module CalculatorHelper
18
+ def self.round(price)
19
+ precision = 1 / EleVAT.config.rounding_precision
20
+ (price * precision).ceil / precision
21
+ end
22
+
23
+ def self.percentage(net_price, rate)
24
+ net_price * rate / 100
25
+ end
26
+
27
+ def self.num_to_currency(n)
28
+ if n.to_s.split('.').last.size == 1
29
+ return "#{n}0"
30
+ else
31
+ return "#{n}"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,14 @@
1
+ module EleVAT
2
+ class Configuration
3
+ attr_accessor :basic_tax_rate, :import_tax_rate, :rounding_precision,
4
+ :tax_free_items, :import_label
5
+
6
+ def initialize
7
+ @basic_tax_rate = 10
8
+ @import_tax_rate = 5
9
+ @rounding_precision = 0.05
10
+ @tax_free_items = %w(chocolate chocolates pills book)
11
+ @import_label = 'imported'
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,64 @@
1
+ module EleVAT
2
+ class Importer
3
+ attr_accessor :imported_data
4
+
5
+ def initialize(input_data)
6
+ begin
7
+ if input_data.class == String
8
+ @imported_data = initialize_string(input_data)
9
+ elsif input_data.content_type == 'text/csv'
10
+ @imported_data = initialize_csv(input_data)
11
+ elsif input_data.content_type == 'application/vnd.ms-excel'
12
+ @imported_data = initialize_xls(input_data)
13
+ end
14
+ rescue
15
+ raise NotImplementedError, 'Your data import is not precessable yet'
16
+ end
17
+ end
18
+
19
+ def export_data_for_receipt
20
+ @imported_data.map { |p| p.prepare_for_receipt }
21
+ end
22
+
23
+ private
24
+
25
+ def initialize_string(input_data)
26
+ products = []
27
+ tmp_array = input_data.strip.split(/ (?=\d+)/)
28
+ tmp_array.each_with_index do |product_string, index|
29
+ next unless index.even?
30
+ product_array = product_string.split(' ')
31
+ quantity = product_array.shift.to_i
32
+ imported = product_string.downcase.include? EleVAT.config.import_label
33
+ taxable = taxable?(product_array)
34
+ name = build_name(product_array)
35
+ net_price = tmp_array[index + 1].to_f
36
+ products << Product.new(
37
+ quantity, name, net_price, taxable, imported
38
+ )
39
+ end
40
+ products
41
+ end
42
+
43
+ def build_name(array_name)
44
+ if (imported = array_name.delete(EleVAT.config.import_label))
45
+ array_name.unshift(imported)
46
+ end
47
+ array_name[0...-1].join(' ')
48
+ end
49
+
50
+ def taxable?(product)
51
+ (product & EleVAT.config.tax_free_items).empty?
52
+ end
53
+
54
+ def initialize_csv
55
+ # TO _DO
56
+ fail NotImplementedError, 'Your data import is not precessable yet'
57
+ end
58
+
59
+ def initialize_xls
60
+ # TO _DO
61
+ fail NotImplementedError, 'Your data import is not precessable yet'
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,71 @@
1
+ module EleVAT
2
+ class Product
3
+ attr_accessor :quantity, :name, :net_price, :gross_price,
4
+ :tax, :imported, :taxable
5
+
6
+ def initialize(quantity, name, net_price, taxable = true, imported = false)
7
+ @quantity = quantity
8
+ @name = name
9
+ @net_price = net_price
10
+ @taxable = taxable
11
+ @imported = imported
12
+ @gross_price = nil
13
+ @tax = nil
14
+ validate_product
15
+ end
16
+
17
+ def prepare_for_receipt
18
+ calculate_tax
19
+ {
20
+ name: @name,
21
+ quantity: @quantity,
22
+ net_price: @net_price,
23
+ gross_price: @gross_price,
24
+ tax: @tax,
25
+ imported: @imported,
26
+ taxable: @taxable
27
+ }
28
+ end
29
+
30
+ private
31
+
32
+ def calculate_tax
33
+ tax = 0.0
34
+ @imported && tax += CalculatorHelper.percentage(
35
+ @net_price, EleVAT.config.import_tax_rate
36
+ )
37
+ @taxable && tax += CalculatorHelper.percentage(
38
+ @net_price, EleVAT.config.basic_tax_rate
39
+ )
40
+ @tax = CalculatorHelper.round(tax) * @quantity
41
+ gross_price = @tax + @net_price * @quantity
42
+ @gross_price = gross_price.round 2
43
+ end
44
+
45
+ def validate_product
46
+ validate_net_price
47
+ validate_name
48
+ validate_quantity
49
+ end
50
+
51
+ def validate_net_price
52
+ net_price_is_a_float = @net_price.class == Float
53
+ net_price_gt_zero = @net_price > 0.0
54
+
55
+ fail ArgumentError, 'Net price must be a float > 0.0' unless
56
+ net_price_is_a_float && net_price_gt_zero
57
+ end
58
+
59
+ def validate_name
60
+ name_is_blank = name.nil? || name == ''
61
+ fail ArgumentError, 'Invalid name' if name_is_blank
62
+ end
63
+
64
+ def validate_quantity
65
+ quantity_is_gt_zero = quantity > 0
66
+ quantity_is_int = quantity.class == Fixnum
67
+ fail ArgumentError, 'Invalid quantity' unless
68
+ quantity_is_int && quantity_is_gt_zero
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,69 @@
1
+ module EleVAT
2
+ class Receipt
3
+ attr_accessor :products, :total_amount, :taxes
4
+
5
+ def initialize(products = [])
6
+ @products = products
7
+ @total_amount = 0.0
8
+ @taxes = 0.0
9
+ end
10
+
11
+ def add(product)
12
+ if Receipt.valid_product(product)
13
+ @products << product
14
+ elsif product.class == Array && product.all? do |p|
15
+ p.is_a?(Hash) && Receipt.valid_product(p)
16
+ end
17
+ @products = product
18
+ else
19
+ fail ArgumentError, 'Parameter must be EleVAT::Product '\
20
+ 'or an array of Products'
21
+ end
22
+ end
23
+
24
+ def calculate_total
25
+ @total_amount =
26
+ @products.map { |product| product[:gross_price] }.inject(:+).round 2
27
+ end
28
+
29
+ def calculate_taxes
30
+ @taxes = @products.map { |product| product[:tax] }.inject(:+).round 2
31
+ end
32
+
33
+ def to_s
34
+ @total_amount == 0.0 && calculate_total
35
+ @taxes == 0.0 && calculate_taxes
36
+
37
+ output = @products.map do |product|
38
+ "#{product[:quantity]} #{product[:name]}: "\
39
+ "#{CalculatorHelper.num_to_currency(product[:gross_price])} "
40
+ end
41
+ output << ("Sales Taxes: #{CalculatorHelper.num_to_currency(@taxes)} "\
42
+ "Total: #{CalculatorHelper.num_to_currency(@total_amount)}")
43
+ output.join
44
+ end
45
+
46
+ def size
47
+ @products.size
48
+ end
49
+
50
+ def to_xls
51
+ # TO _DO
52
+ fail NotImplementedError
53
+ end
54
+
55
+ def to_csv
56
+ # TO _DO
57
+ fail NotImplementedError
58
+ end
59
+
60
+ private
61
+
62
+ def self.valid_product(product)
63
+ product.class == Hash && [
64
+ :quantity, :name, :net_price,
65
+ :taxable, :imported, :gross_price, :tax
66
+ ].all? { |s| product.key? s }
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,3 @@
1
+ module EleVAT
2
+ VERSION = "1.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: eleVAT
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Simone Romanelli
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-05-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.8'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: A simple receipts calculator.
70
+ email:
71
+ - simone.romanelli.dev@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".byebug_history"
77
+ - ".gitignore"
78
+ - ".rspec"
79
+ - ".travis.yml"
80
+ - Gemfile
81
+ - LICENSE
82
+ - README.md
83
+ - Rakefile
84
+ - bin/console
85
+ - bin/setup
86
+ - eleVAT.gemspec
87
+ - lib/eleVAT.rb
88
+ - lib/eleVAT/configuration.rb
89
+ - lib/eleVAT/importer.rb
90
+ - lib/eleVAT/product.rb
91
+ - lib/eleVAT/receipt.rb
92
+ - lib/eleVAT/version.rb
93
+ homepage: https://github.com/simoneromanelli/eleVAT
94
+ licenses:
95
+ - MIT
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.6.4
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: eleVAT
117
+ test_files: []