magelex 0.1.2 → 0.1.3

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
  SHA1:
3
- metadata.gz: 032119d67096a3213c374635a710796c3732ea30
4
- data.tar.gz: 9451eb9eba3fddd6bf7d6a12d0af3e554dc53222
3
+ metadata.gz: de06fc18a480aa62a7229eb17dd1039513345fd3
4
+ data.tar.gz: 2c47cad6e86d40495ddd67c32a6533ab5e2d4e77
5
5
  SHA512:
6
- metadata.gz: a4e4e62c48ffa8fca02d241e5a953b191cf8fd3e6a7ad29769140aef3a0eae03b681822fa23a251b1aa33aac76afc108a798f97865d44eed6a606fce294e1a0d
7
- data.tar.gz: cf520013296e47b60ac59790e43b677337673b7bb65bd18c292a3af5b9e95fddf60a0411492af011d0cc4cbaf8587e09a4c53961955cba9e46cc431ad694bbd3
6
+ metadata.gz: 07b259c2f497d0345b89ec13819b6717e2c64293bc212d7fe1a805214270aacf77f80fec7d0478462c2002cfd2a55b81741d6f171a971933aa1e924846873026
7
+ data.tar.gz: 7efba0085ec0ecfe48693fd2b0e71af54f7f4351769d943338d9bd8e39a2a339af03c9ab7e199b12f5ddd748318300778f5b8ccca1e43a543c78e71be301baea
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  *This README reflects (more or less) the current development state, for documentation of a given version, see the README shipped with that gem (or respective tag on github).*
4
4
 
5
- Magelex takes Magento data and presents it in a format that Lexware can read.
5
+ Magelex takes Magento online shop order data and presents it in a format that Lexware can read to model open positions.
6
6
 
7
7
  Aim is to manage the cash flow in Lexware.
8
8
 
@@ -16,7 +16,7 @@ Install it yourself as:
16
16
 
17
17
  ## Assumptions
18
18
 
19
- Customer accounts are hard coded. Database access necessary for date corrections.
19
+ Customer accounts are hard coded. Database access is necessary for date corrections (but can be skipped).
20
20
 
21
21
  ## Usage
22
22
 
@@ -34,9 +34,9 @@ Call `magelex --help` to get a basic idea:
34
34
  --version Show version and exit.
35
35
 
36
36
 
37
- By default, `magelex` will log to `STDERR`, put you can pass the path to a log file.
37
+ By default, `magelex` will log to `STDERR`, but you can pass the path to a log file.
38
38
 
39
- It consumes a single file (given as argument, as in `magelex magento_orders.csv`). `magelex` will create a file with same filename in the path `lexware` (can be changed with the `--out-dir` switch).
39
+ It consumes a single file (given as argument, as in `magelex magento_orders.csv`) or a directory of files. `magelex` will create a file with same filename in the path `lexware` (can be changed with the `--out-dir` option).
40
40
 
41
41
  ### Configuration
42
42
 
@@ -48,9 +48,14 @@ If no database queries should be done, invoke with `--skip-db`.
48
48
 
49
49
  Call `magelex --help` to get a basic idea.
50
50
 
51
- ## TODOs
51
+ ## Documentation of process
52
52
 
53
- - Respect Discounts (item and totals).
53
+ `bin/magelex` will read in a CSV file with orders exported by magento (`Magelex::MagentoCSV`). In this file, one row accounts for one 'order item'. Items are added up to form a `Magelex::LexwareBill`. Adding Items to a `LexWareBill` collects the brutto values separated by tax. For this, the tax category (0%, 7% or 19%) has to be guessed (`Magelex::TaxGuesser`).
54
+
55
+ Result of this processing are a number of `LexwareBill`s.
56
+ Swiss orders require some special attention, so steps are undertaken to adjust these to reality. Afterwards, the shipping costs can be included.
57
+
58
+ Finally the `LexwareBill`s that conform to the rules (`LexwareBill#check`) can be exported to be imported to Lexware (`Magelex::LexwareCSV`).
54
59
 
55
60
  ## Development
56
61
 
data/bin/magelex CHANGED
@@ -37,7 +37,7 @@ optparse = OptionParser.new do |opts|
37
37
  end.parse!
38
38
 
39
39
  if ARGV.length != 1
40
- STDERR.puts "Need an argument (directory or file)"
40
+ STDERR.puts "Need a single argument (directory or file)"
41
41
  exit 1
42
42
  end
43
43
 
@@ -50,7 +50,7 @@ Magelex.logger.formatter = proc { |severity, datetime, progname, msg|
50
50
  }
51
51
 
52
52
  def main options
53
- Magelex.logger.info("Started")
53
+ Magelex.logger.info("Started (version #{Magelex::VERSION})")
54
54
 
55
55
  Dir.mkdir options[:out_dir] rescue {}
56
56
  outdir = Pathname.new(options[:out_dir]).realpath
data/bin/magelex_debug ADDED
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "magelex"
4
+
5
+ require 'yaml'
6
+ require 'optparse'
7
+ require 'terminal-table'
8
+
9
+ options = {}
10
+
11
+ optparse = OptionParser.new do |opts|
12
+ opts.banner = "Usage: #{$PROGRAM_NAME} DIR_OR_FILE"
13
+ opts.separator ""
14
+ opts.separator "Debug magelex im- and export"
15
+ opts.separator ""
16
+
17
+ opts.on('-v', '--verbose', 'Run verbosely') do |o|
18
+ options[:verbose] = o
19
+ end
20
+ opts.on('-s', '--skip-db', 'Do not update dates from mysql database.') do |o|
21
+ options[:skipdb] = o
22
+ end
23
+ opts.on_tail('--version', 'Show version and exit.') do
24
+ puts "Magelex #{Magelex::VERSION}"
25
+ exit 0
26
+ end
27
+ opts.on('-h', '--help', 'Show this help and exit.') do
28
+ puts opts
29
+ exit 0
30
+ end
31
+ end.parse!
32
+
33
+ if ARGV.length != 1
34
+ STDERR.puts "Need an argument (directory or file)"
35
+ exit 1
36
+ end
37
+
38
+ Magelex.logger = Logger.new(options[:log_file] ? options[:log_file] : STDERR)
39
+
40
+ Magelex.logger.level = options[:verbose] ? Logger::DEBUG : Logger::INFO
41
+ Magelex.logger.datetime_format = "%Y-%m-%d %H:%M:%S"
42
+ Magelex.logger.formatter = proc { |severity, datetime, progname, msg|
43
+ "#{severity} - #{datetime} - #{msg}\n"
44
+ }
45
+
46
+ def main options
47
+ Magelex.logger.info("Started")
48
+
49
+ # Import/Read file.
50
+ bills = Magelex::MagentoCSV.read ARGV[0]
51
+ bills.each(&:swissify)
52
+ bills.each(&:process_shipping_costs)
53
+ bill_rows = bills.map do |bill|
54
+ [
55
+ bill.order_nr,
56
+ bill.swiss? ? 'Y' : 'N',
57
+ bill.total,
58
+ "%.3f" %bill.total_0, "%.3f" % bill.total_7, "%.3f" % bill.total_19,
59
+ "%.3f" % bill.tax_7, "%.3f" % bill.tax_19,
60
+ "%.3f" % bill.shipping_cost, "%.3f" % bill.check_diff, bill.check ? "Y" : "N"
61
+ ]
62
+ end
63
+
64
+ t = Terminal::Table.new(headings: ["nr", "S?","total_b",
65
+ "total0", "total7", "total19",
66
+ "tax7", "tax19",
67
+ "ship", "diff", "C"],
68
+ rows: bill_rows)
69
+
70
+ puts t
71
+ puts Magelex::LexwareCSV::render bills
72
+ Magelex.logger.info("Finished")
73
+ end
74
+
75
+ main options
@@ -0,0 +1,38 @@
1
+ module Magelex
2
+ module BillModifier
3
+ def self.process bill
4
+ # 'Trick' around with bill
5
+ swissify bill
6
+ process_shipping_costs bill
7
+ adjust_order_number bill
8
+ end
9
+
10
+ def self.process_shipping_costs bill
11
+ if bill.swiss?
12
+ bill.total_0 += LexwareBill.floor2(bill.shipping_cost)
13
+ else
14
+ bill.tax_19 += bill.shipping_cost * 0.19
15
+ bill.total_19 += LexwareBill.floor2(bill.shipping_cost * 1.19)
16
+ end
17
+ end
18
+
19
+ def self.adjust_order_number bill
20
+ bill.order_nr.to_s.gsub!(/^e-/, '')
21
+ end
22
+
23
+ # total0 consumes total and resets others, if check passes
24
+ # shipping costs should be consumed before
25
+ # this has to be layed out in a graph or documented properly
26
+ # (what happens when)
27
+ def self.swissify bill
28
+ return if !bill.swiss?
29
+
30
+ bill.incorrect_tax += (bill.total_19 - bill.total_19 / 1.19)
31
+ bill.incorrect_tax += (bill.total_7 - bill.total_7 / 1.07)
32
+ bill.total_0 += (bill.total_19 / 1.19)
33
+ bill.total_19 = 0
34
+ bill.total_0 += (bill.total_7 / 1.07)
35
+ bill.total_7 = 0
36
+ end
37
+ end
38
+ end
@@ -12,7 +12,8 @@ module Magelex
12
12
  10000 + ord * 100
13
13
  end
14
14
 
15
- # get tax for :total_0, :total_7 or :total_19
15
+ # Get account number for
16
+ # :incorrect_tax, :total_0, :total_7 or :total_19
16
17
  def self.for(bill, tax_kind)
17
18
  if tax_kind == :total_0
18
19
  return for_0 bill
@@ -20,6 +21,8 @@ module Magelex
20
21
  return for_7 bill
21
22
  elsif tax_kind == :total_19
22
23
  return for_19 bill
24
+ elsif tax_kind == :incorrect_tax
25
+ return for_incorrect_tax bill
23
26
  else
24
27
  raise "unknown tax_kind (#{tax_kind})"
25
28
  end
@@ -36,5 +39,9 @@ module Magelex
36
39
  def self.for_0 bill
37
40
  '8120'
38
41
  end
42
+
43
+ def self.for_incorrect_tax bill
44
+ '1783'
45
+ end
39
46
  end
40
47
  end
@@ -7,20 +7,23 @@ module Magelex
7
7
  'NL','AT','PL','PT','RO','SI','SK','FI','SE','UK']
8
8
 
9
9
  attr_accessor :order_nr, :customer_name, :country_code,
10
- :date, :status, :shipping_cost, :total, :total_0, :total_7, :total_19, :has_problems
10
+ :date, :status, :shipping_cost, :total, :total_0, :total_7, :total_19, :has_problems, :tax_7, :tax_19, :incorrect_tax
11
11
 
12
12
  def initialize values={}
13
13
  @total_0, @total_7, @total_19, @total = 0, 0, 0, 0
14
14
  @customer_name = values.delete(:customer_name) || ""
15
15
  @order_nr = values.delete(:order_nr) || nil
16
- @date = values.delete(:date) || nil
16
+ @date = values.delete(:date) || nil
17
17
  @total = values.delete(:total) || 0
18
- @total_0 = values.delete(:total_0) || 0
19
- @total_7 = values.delete(:total_7) || 0
18
+ @total_0 = values.delete(:total_0) || 0
19
+ @total_7 = values.delete(:total_7) || 0
20
20
  @total_19 = values.delete(:total_19) || 0
21
+ @tax_7 = values.delete(:tax_7) || 0
22
+ @tax_19 = values.delete(:tax_19) || 0
23
+ @incorrect_tax = values.delete(:incorrect_tax) || 0
21
24
  @status = values.delete(:status) || nil
22
25
  @shipping_cost = values.delete(:shipping_cost) || nil
23
- @country_code = values.delete(:country_code) || nil
26
+ @country_code = values.delete(:country_code) || nil
24
27
  @has_problems = false
25
28
  if !values.empty?
26
29
  raise "Unknown values for bill: #{values.inspect}"
@@ -31,17 +34,35 @@ module Magelex
31
34
  @country_code == 'CH'
32
35
  end
33
36
 
37
+ # Add item values to corresponding total_ and tax_ attributes
38
+ # depending on discount, include or exclude taxes.
34
39
  def add_item amount, tax, name, discount=0
35
40
  begin
36
41
  case TaxGuess.guess(amount, tax)
37
42
  when :tax0
38
- @total_0 += amount.round(2)# - discount.round(0)
43
+ @total_0 += amount.round(2)
39
44
  when :tax7
40
- @total_7 += amount.round(2)# - discount.round(0)
45
+ if discount != 0
46
+ @total_7 += (amount.round(2) * 1.07)
47
+ else
48
+ @total_7 += amount.round(2)
49
+ end
50
+ @tax_7 += tax
41
51
  when :tax19
42
- @total_19 += amount.round(2)# - discount.round(0)
52
+ if discount != 0
53
+ @total_19 += (amount.round(2) * 1.18)
54
+ else
55
+ @total_19 += amount.round(2)
56
+ end
57
+ if swiss?
58
+ Magelex::logger.info("19% Tax Item in swiss order: #{@order_nr}: #{name}")
59
+ end
60
+ @tax_19 += tax
61
+ when :empty_item
62
+ Magelex::logger.debug("Empty item: '#{name}' #{amount}, tax: #{tax}")
43
63
  end
44
- rescue
64
+ rescue RuntimeError
65
+ Magelex::logger.warn("Unguessable tax (#{@order_nr}: #{name} #{amount}/#{tax})")
45
66
  @has_problems = true
46
67
  end
47
68
  end
@@ -54,33 +75,21 @@ module Magelex
54
75
  @@EU_CODES.include? @country_code
55
76
  end
56
77
 
78
+ def check_diff
79
+ @total.round(2) - (@total_0.round(2) + @total_7.round(2) + @total_19.round(2) + @incorrect_tax.round(2)).round(2)
80
+ end
81
+
57
82
  def check
58
- @has_problems == false && @total > 0 && @total.round(2) == (@total_0.round(2) + @total_7.round(2) + @total_19.round(2)).round(2)
83
+ @has_problems == false && @total > 0 && check_diff == 0
59
84
  end
60
85
 
61
86
  def self.floor2 value
62
87
  (value * 100).to_i / 100.0
63
88
  end
64
-
65
- def consume_shipping_cost
66
- if swiss?
67
- @total_0 += LexwareBill.floor2(@shipping_cost)
68
- else
69
- @total_19 += LexwareBill.floor2(@shipping_cost * 1.19)
70
- end
71
- @shipping_cost = 0
72
89
  end
73
90
 
74
91
  def complete?
75
92
  @status == "complete"
76
93
  end
77
-
78
- def swissify
79
- return if !swiss?
80
- @total_0 += @total_19
81
- @total_19 = 0
82
- @total_0 += @total_7
83
- @total_7 = 0
84
- end
85
94
  end
86
95
  end
@@ -16,7 +16,7 @@ module Magelex
16
16
  Magelex::AccountNumber.for_customer(bill),
17
17
  0]
18
18
  # subs
19
- [:total_0, :total_7, :total_19].each do |part|
19
+ [:total_0, :total_7, :total_19, :incorrect_tax].each do |part|
20
20
  if (amount = bill.send(part)) != 0
21
21
  rows << [
22
22
  bill.date.strftime("%d.%m.%Y"),
@@ -3,7 +3,7 @@ require 'csv'
3
3
  module Magelex
4
4
  module MagentoCSV
5
5
  MONEY_FIELDS = ['Order Shipping', 'Order Grand Total',
6
- 'Item Total', 'Item Tax']
6
+ 'Item Total', 'Item Tax', 'Item Discount']
7
7
 
8
8
  CSV::Converters[:german_money_amount] = lambda do |value, info|
9
9
  if MONEY_FIELDS.include? info[:header]
@@ -39,6 +39,13 @@ module Magelex
39
39
  bill.status = row['Order Status']
40
40
 
41
41
  bill.shipping_cost = row['Order Shipping']
42
+ if bill.shipping_cost == 12.6
43
+ Magelex::logger.info "Correcting shipping cost of #{bill.order_nr} (12.6 -> 15 / 1.19 €)"
44
+ bill.shipping_cost = 15 / 1.19
45
+ elsif bill.shipping_cost == 4.15
46
+ Magelex::logger.info "Correcting shipping cost of #{bill.order_nr} (4.15 -> 4.95 / 1.19 €)"
47
+ bill.shipping_cost = 4.95 / 1.19
48
+ end
42
49
  bill.total = row['Order Grand Total']
43
50
  bill
44
51
  end
@@ -57,7 +64,8 @@ module Magelex
57
64
 
58
65
  current_bill.add_item(row['Item Total'],
59
66
  row['Item Tax'],
60
- row['Item Name'])
67
+ row['Item Name'],
68
+ row['Item Discount'])
61
69
 
62
70
  if !bills.include? (current_bill)
63
71
  bills << current_bill
@@ -1,16 +1,34 @@
1
1
  module Magelex
2
2
  module TaxGuess
3
+ # Guesses the tax category.
4
+ # Question is: how many percent of total is tax_amount.
3
5
  def self.guess(total, tax_amount)
4
- if tax_amount == 0
5
- :tax0
6
- elsif (total - total/1.06) <= tax_amount && (total - total/1.08) >= tax_amount
7
- :tax7
8
- elsif (total - total/1.18) <= tax_amount && (total - total/1.20) >= tax_amount
9
- :tax19
10
- else
6
+ if total == 0 && tax_amount == 0
7
+ return :empty_item
8
+ end
9
+ if total == 0
11
10
  raise "TaxGuess: Cannot guess tax of "\
12
11
  "#{total}/#{tax_amount} (#{total - total/tax_amount})"
13
12
  end
13
+
14
+ # net: netto, gro: gross/brutto
15
+ # gro_price = net_price + taxes ## (1: net_price = gro_price - taxes)
16
+ # gro_price = net_price + net_price * tax_perce
17
+ # tax_perce = (gro_price - net_price) / net_price
18
+ # tax_perce = gro_price / net_price - 1 ## (see 1)
19
+ percentage = total.to_f / (total - tax_amount) - 1
20
+
21
+ case percentage
22
+ when -0.01..0.01
23
+ :tax0
24
+ when 0.06..0.09
25
+ :tax7
26
+ when 0.16..0.20
27
+ :tax19
28
+ else
29
+ raise "TaxGuess: Cannot guess tax of "\
30
+ "#{total}/#{tax_amount} (#{total - total/tax_amount}) - #{tax_amount/total if total != 0}"
31
+ end
14
32
  end
15
33
  end
16
34
  end
@@ -1,3 +1,3 @@
1
1
  module Magelex
2
- VERSION = "0.1.2".freeze
2
+ VERSION = "0.1.3".freeze
3
3
  end
data/lib/magelex.rb CHANGED
@@ -5,12 +5,13 @@ require 'magelex/lexware_csv'
5
5
  require 'magelex/tax_guess'
6
6
  require 'magelex/lexware_account'
7
7
  require 'magelex/magento_mysql'
8
+ require 'magelex/bill_modifier'
8
9
 
9
10
  require 'logger'
10
11
 
11
12
  module Magelex
12
13
  def self.logger
13
- @logger ||= Logger.new
14
+ @logger ||= Logger.new STDERR
14
15
  end
15
16
  def self.logger= logger
16
17
  @logger = logger
@@ -24,15 +25,17 @@ module Magelex
24
25
  if !bill.complete?
25
26
  Magelex.logger.info("Skip order #{bill.order_nr} (incomplete: #{bill.status})")
26
27
  else # complete!
27
- bill.consume_shipping_cost
28
- bill.swissify
28
+ Magelex::BillModifier.process bill
29
29
  if !bill.check
30
- Magelex.logger.info("Skip order #{bill.order_nr}#{bill.swiss? ? ' (swiss)' : ''}")
30
+ Magelex.logger.info("Skip order #{bill.order_nr}#{bill.swiss? ? ' (swiss)' : ''} #{bill.has_problems ? ' (broken item)': '' }")
31
31
  Magelex.logger.info(" (totals do not match #{bill.total} != "\
32
32
  "(0: #{bill.total_0} + 7: #{bill.total_7} "\
33
33
  "+ 19: #{bill.total_19} "\
34
34
  "= #{bill.total_0 + bill.total_7 + bill.total_19})")
35
35
  else
36
+ if bill.swiss?
37
+ Magelex.logger.info("#{bill.order_nr}: swiss")
38
+ end
36
39
  Magelex.logger.debug("Handle #{bill.order_nr}")
37
40
  bills_export << bill
38
41
  end
data/magelex.gemspec CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency 'mysql2', '~> 0.4'
22
+ spec.add_dependency 'terminal-table', '~> 1.5'
22
23
 
23
24
  spec.add_development_dependency "bundler", "~> 1.11"
24
25
  spec.add_development_dependency "rake", "~> 10.0"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: magelex
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felix Wolfsteller
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-10 00:00:00.000000000 Z
11
+ date: 2016-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mysql2
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: terminal-table
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.5'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -71,6 +85,7 @@ email:
71
85
  - felix.wolfsteller@gmail.com
72
86
  executables:
73
87
  - magelex
88
+ - magelex_debug
74
89
  extensions: []
75
90
  extra_rdoc_files: []
76
91
  files:
@@ -81,7 +96,9 @@ files:
81
96
  - README.md
82
97
  - Rakefile
83
98
  - bin/magelex
99
+ - bin/magelex_debug
84
100
  - lib/magelex.rb
101
+ - lib/magelex/bill_modifier.rb
85
102
  - lib/magelex/lexware_account.rb
86
103
  - lib/magelex/lexware_bill.rb
87
104
  - lib/magelex/lexware_csv.rb