ydim 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitattributes +1 -0
- data/.gitignore +6 -0
- data/.travis.yml +26 -0
- data/Gemfile +11 -0
- data/History.txt +7 -2
- data/Rakefile +16 -23
- data/bin/migrate_to_utf_8 +201 -0
- data/bin/ydim-edit +7 -1
- data/bin/ydim-inject +2 -1
- data/bin/ydimd +4 -2
- data/lib/pdfinvoice/config.rb +53 -0
- data/lib/pdfinvoice/invoice.rb +203 -0
- data/lib/ydim/config.rb +1 -1
- data/lib/ydim/factory.rb +1 -0
- data/lib/ydim/invoice.rb +22 -1
- data/lib/ydim/odba.rb +1 -0
- data/lib/ydim/root_session.rb +12 -5
- data/lib/ydim/server.rb +6 -3
- data/lib/ydim/version.rb +3 -0
- data/readme.md +29 -0
- data/set_initial_ydim_db.sql +440 -0
- data/test/data/config.yml +44 -0
- data/test/data/logo.png +0 -0
- data/test/suite.rb +9 -4
- data/test/test_autoinvoicer.rb +3 -3
- data/test/test_currency_converter.rb +3 -2
- data/test/test_currency_updater.rb +3 -3
- data/test/test_debitor.rb +3 -3
- data/test/test_factory.rb +5 -6
- data/test/test_invoice.rb +69 -23
- data/test/test_item.rb +6 -4
- data/test/test_mail.rb +10 -5
- data/test/test_root_session.rb +15 -15
- data/test/test_root_user.rb +3 -2
- data/test/test_server.rb +7 -14
- data/ydim.gemspec +40 -0
- metadata +302 -72
- data/README.txt +0 -21
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ebd5360c95d8427ee4b3a093102866fce2d3e482
|
4
|
+
data.tar.gz: c2c5e41885205634f338502a40c044eaa7b090c8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 24534e21dd9a128df999e34922820fa4740eb85faedfb0b3069c16802628929491d89a8786d663ae5b918cc61a02c75c33cc10a75be556f3eddea14d44659a0e
|
7
|
+
data.tar.gz: 450bc76a0b030402f9011884cb1392946864764841d8bca4240be27ac7ee03bff80b70d6424710153686ebba07211d9ac21a500599aa55a4583f8ae99005b52f
|
data/.gitattributes
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.rb diff
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
language: ruby
|
2
|
+
|
3
|
+
bundler_args: --without debugger
|
4
|
+
|
5
|
+
cache: bundler
|
6
|
+
sudo: false
|
7
|
+
|
8
|
+
before_install:
|
9
|
+
- gem --version
|
10
|
+
|
11
|
+
script: bundle exec test/suite.rb
|
12
|
+
|
13
|
+
rvm:
|
14
|
+
- 2.1
|
15
|
+
- 2.2
|
16
|
+
- 2.3.0
|
17
|
+
- ruby-head
|
18
|
+
|
19
|
+
matrix:
|
20
|
+
allow_failures:
|
21
|
+
- rvm: ruby-head
|
22
|
+
|
23
|
+
notifications:
|
24
|
+
email:
|
25
|
+
recipients:
|
26
|
+
- ngiger@ywesee.com
|
data/Gemfile
ADDED
data/History.txt
CHANGED
data/Rakefile
CHANGED
@@ -1,28 +1,21 @@
|
|
1
|
-
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'ydim/version'
|
6
|
+
require "bundler/gem_tasks"
|
7
|
+
require 'rspec/core/rake_task'
|
2
8
|
|
3
|
-
|
4
|
-
require 'hoe'
|
9
|
+
RSpec::Core::RakeTask.new(:spec)
|
5
10
|
|
6
|
-
#
|
7
|
-
# Hoe.plugin :cucumberfeatures
|
8
|
-
# Hoe.plugin :gem_prelude_sucks
|
9
|
-
# Hoe.plugin :inline
|
10
|
-
# Hoe.plugin :inline
|
11
|
-
# Hoe.plugin :manifest
|
12
|
-
# Hoe.plugin :newgem
|
13
|
-
# Hoe.plugin :racc
|
14
|
-
# Hoe.plugin :rubyforge
|
15
|
-
# Hoe.plugin :rubyforge
|
16
|
-
# Hoe.plugin :website
|
11
|
+
# dependencies are now declared in ydim.gemspec
|
17
12
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
# (delete this comment too, of course)
|
22
|
-
|
23
|
-
developer('Masaomi Hatakeyama, Zeno R.R. Davatz', 'mhatakeyama@ywesee.com, zdavatz@ywesee.com')
|
24
|
-
|
25
|
-
# self.rubyforge_name = 'ydimx' # if different than 'ydim'
|
13
|
+
desc 'Offer a gem task like hoe'
|
14
|
+
task :gem => :build do
|
15
|
+
Rake::Task[:build].invoke
|
26
16
|
end
|
27
17
|
|
28
|
-
|
18
|
+
task :spec => :clean
|
19
|
+
|
20
|
+
require 'rake/clean'
|
21
|
+
CLEAN.include FileList['pkg/*.gem']
|
@@ -0,0 +1,201 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
puts "#{Time.now}: Loading #{__FILE__}"
|
4
|
+
STDOUT.sync = true
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'pry'
|
8
|
+
rescue LoadError
|
9
|
+
end
|
10
|
+
|
11
|
+
$: << File.expand_path(File.join(File.dirname(__FILE__), 'lib'))
|
12
|
+
require 'logger'
|
13
|
+
require 'needle'
|
14
|
+
require 'odba/id_server'
|
15
|
+
require 'rrba/server'
|
16
|
+
require 'ydim/autoinvoicer'
|
17
|
+
require 'ydim/client'
|
18
|
+
require 'ydim/currency_converter'
|
19
|
+
require 'ydim/currency_updater'
|
20
|
+
require 'ydim/factory'
|
21
|
+
require 'ydim/root_user'
|
22
|
+
require 'ydim/server'
|
23
|
+
require 'ydim/util'
|
24
|
+
require 'odba/18_19_loading_compatibility'
|
25
|
+
|
26
|
+
require 'odba/connection_pool'
|
27
|
+
require 'odba/drbwrapper'
|
28
|
+
require 'ydim/odba'
|
29
|
+
require 'ydim/root_session'
|
30
|
+
require 'ydim/root_user'
|
31
|
+
|
32
|
+
module YDIM
|
33
|
+
class Server
|
34
|
+
# http://stackoverflow.com/questions/2982677/ruby-1-9-invalid-byte-sequence-in-utf-8
|
35
|
+
# https://robots.thoughtbot.com/fight-back-utf-8-invalid-byte-sequences
|
36
|
+
def sanitize_utf8(string)
|
37
|
+
return nil if string.nil?
|
38
|
+
# return string.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
|
39
|
+
return string if string.valid_encoding?
|
40
|
+
if string.force_encoding(Encoding::ISO_8859_1).valid_encoding?
|
41
|
+
string.force_encoding(Encoding::ISO_8859_1).clone.encode(Encoding::UTF_8)
|
42
|
+
else
|
43
|
+
string.chars.select { |c| c.valid_encoding? }.join
|
44
|
+
end
|
45
|
+
end
|
46
|
+
def _migrate_to_utf8 queue, table, opts={}
|
47
|
+
while obj = queue.shift do
|
48
|
+
if obj.is_a?(Numeric)
|
49
|
+
begin
|
50
|
+
obj = ODBA.cache.fetch obj
|
51
|
+
rescue ODBA::OdbaError
|
52
|
+
return
|
53
|
+
end
|
54
|
+
else
|
55
|
+
obj = obj.odba_instance
|
56
|
+
end
|
57
|
+
puts " #{__LINE__}: Migrating #{obj.class} #{obj.to_s}" if $VERBOSE
|
58
|
+
return unless obj
|
59
|
+
_migrate_obj_to_utf8 obj, queue, table, opts
|
60
|
+
obj.odba_store unless obj.odba_unsaved?
|
61
|
+
end
|
62
|
+
end
|
63
|
+
def _migrate_obj_to_utf8 obj, queue, table, opts={}
|
64
|
+
obj.instance_variables.each do |name|
|
65
|
+
child = obj.instance_variable_get name
|
66
|
+
if child.respond_to?(:odba_unsaved?) && !child.odba_unsaved? \
|
67
|
+
&& obj.respond_to?(:odba_serializables) \
|
68
|
+
&& obj.odba_serializables.include?(name)
|
69
|
+
child.instance_variable_set '@odba_persistent', nil
|
70
|
+
end
|
71
|
+
child = _migrate_child_to_utf8 child, queue, table, opts
|
72
|
+
obj.instance_variable_set name, child
|
73
|
+
end
|
74
|
+
if obj.is_a?(Array)
|
75
|
+
obj.collect! do |child|
|
76
|
+
_migrate_child_to_utf8 child, queue, table, opts
|
77
|
+
end
|
78
|
+
end
|
79
|
+
if obj.is_a?(Hash)
|
80
|
+
obj.dup.each do |key, child|
|
81
|
+
obj.store key, _migrate_child_to_utf8(child, queue, table, opts)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
obj
|
85
|
+
end
|
86
|
+
def _migrate_child_to_utf8 child, queue, table, opts={}
|
87
|
+
@serialized ||= {}
|
88
|
+
case child
|
89
|
+
when ODBA::Persistable, ODBA::Stub
|
90
|
+
if child = child.odba_instance
|
91
|
+
if child.odba_unsaved?
|
92
|
+
_migrate_to_utf8 [child], table, opts
|
93
|
+
elsif opts[:all]
|
94
|
+
odba_id = child.odba_id
|
95
|
+
unless table[odba_id]
|
96
|
+
table.store odba_id, true
|
97
|
+
queue.push odba_id
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
when String
|
102
|
+
old = child.encoding
|
103
|
+
if ( child.encoding != Encoding::UTF_8 && child.force_encoding(Encoding::ISO_8859_1).valid_encoding? ) ||
|
104
|
+
( child.encoding == Encoding::UTF_8 && !child.valid_encoding? )
|
105
|
+
child = child.force_encoding(Encoding::ISO_8859_1).clone.encode(Encoding::UTF_8)
|
106
|
+
puts "force_encoding from ISO_8859_1 #{old}. is now #{child}"
|
107
|
+
end
|
108
|
+
binding.pry unless child.valid_encoding?
|
109
|
+
case child.encoding.to_s
|
110
|
+
when /ASCII-8BIT|US-ASCII/
|
111
|
+
# nothing todo
|
112
|
+
when /UTF-8/
|
113
|
+
puts "UTF-8: for #{child.to_s}" if $VERBOSE
|
114
|
+
child = sanitize_utf8(child)
|
115
|
+
when /ISO-8859-1/i
|
116
|
+
child = sanitize_utf8(child)
|
117
|
+
# child = child.force_encoding('UTF-8')
|
118
|
+
puts "force_encoding from #{old}. is now #{child}"
|
119
|
+
else
|
120
|
+
puts "Unhandeled encoding #{child.encoding}"
|
121
|
+
# require 'pry'; binding.pry
|
122
|
+
# child = child.force_encoding
|
123
|
+
end
|
124
|
+
when
|
125
|
+
YDIM::AutoInvoice,
|
126
|
+
YDIM::Debitor,
|
127
|
+
YDIM::Debitor,
|
128
|
+
YDIM::Invoice,
|
129
|
+
YDIM::Invoice::Info,
|
130
|
+
YDIM::Item
|
131
|
+
child = _migrate_obj_to_utf8 child, queue, table, opts
|
132
|
+
when Float, Fixnum, TrueClass, FalseClass, NilClass,
|
133
|
+
Symbol, Time, Date, DateTime,
|
134
|
+
YDIM::Factory,
|
135
|
+
YDIM::CurrencyConverter,
|
136
|
+
YDIM::MobileCurrencyConverter
|
137
|
+
# do nothing
|
138
|
+
else
|
139
|
+
@ignored ||= {}
|
140
|
+
unless @ignored[child.class]
|
141
|
+
@ignored.store child.class, true
|
142
|
+
warn "ignoring #{child.class}"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
child
|
146
|
+
rescue SystemStackError
|
147
|
+
puts child.class
|
148
|
+
raise
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
puts "#{Time.now}: Calling migrate_to_utf8"
|
154
|
+
@logger = Logger.new('migrate_to_utf8.log')
|
155
|
+
@logger.level = Logger::DEBUG
|
156
|
+
config = YDIM::Server.config
|
157
|
+
|
158
|
+
ODBA.storage.dbi = ODBA::ConnectionPool.new(config.db_driver_url,
|
159
|
+
config.db_user, config.db_auth, :client_encoding => 'LATIN1')
|
160
|
+
ODBA.cache.setup
|
161
|
+
|
162
|
+
DRb.install_id_conv ODBA::DRbIdConv.new
|
163
|
+
|
164
|
+
if false
|
165
|
+
server = YDIM::Server.new(config, logger)
|
166
|
+
server.extend(DRbUndumped)
|
167
|
+
|
168
|
+
puts config.inspect
|
169
|
+
if(config.detach)
|
170
|
+
pidfile = '/var/run/ydimd.pid'
|
171
|
+
File.open(pidfile, 'w') { |fh| fh.puts $$ }
|
172
|
+
at_exit { File.unlink(pidfile) }
|
173
|
+
Process.fork and exit!(0)
|
174
|
+
end
|
175
|
+
|
176
|
+
begin
|
177
|
+
url = config.server_url
|
178
|
+
url.untaint
|
179
|
+
DRb.start_service(url, server)
|
180
|
+
$SAFE = 1
|
181
|
+
logger.info('start') {
|
182
|
+
sprintf("starting ydim-server on %s", config.server_url) }
|
183
|
+
DRb.thread.join
|
184
|
+
rescue Exception => error
|
185
|
+
logger.error('fatal') { error }
|
186
|
+
raise
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
@server = YDIM::Server.new(config, @logger)
|
191
|
+
@server.extend(DRbUndumped)
|
192
|
+
session = YDIM::RootSession.new(YDIM::RootUser.new(1))
|
193
|
+
session.serv = @server
|
194
|
+
{ :autoinvoices => session.autoinvoices,
|
195
|
+
:invoices => session.invoices,
|
196
|
+
:debitors => session.debitors,
|
197
|
+
}.each do |name, to_migrate|
|
198
|
+
puts "#{Time.now}: Start migrating #{name}"
|
199
|
+
@server._migrate_to_utf8(to_migrate, {})
|
200
|
+
end
|
201
|
+
puts "#{Time.now}: Finished migrate_to_utf8"
|
data/bin/ydim-edit
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# ypdmd -- ydim -- 09.11.2005 -- hwyss@ywesee.com
|
3
3
|
|
4
|
+
require 'yaml'
|
5
|
+
require 'syck'
|
6
|
+
require 'pg'
|
7
|
+
require 'dbi'
|
8
|
+
puts "YAML is now #{YAML} in #{__FILE__} at #{__LINE__}"
|
9
|
+
|
4
10
|
require 'ydim/server'
|
5
11
|
require 'ydim/odba'
|
6
12
|
require 'rclconf'
|
@@ -39,7 +45,7 @@ defaults = {
|
|
39
45
|
'root_key' => 'root_dsa',
|
40
46
|
'smtp_from' => '',
|
41
47
|
'smtp_server' => 'localhost',
|
42
|
-
'vat_rate' =>
|
48
|
+
'vat_rate' => 8.0,
|
43
49
|
}
|
44
50
|
config = RCLConf::RCLConf.new(ARGV, defaults)
|
45
51
|
config.load(config.config)
|
data/bin/ydim-inject
CHANGED
data/bin/ydimd
CHANGED
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Config -- pdfinvoice -- 28.07.2005 -- hwyss@ywesee.com
|
3
|
+
|
4
|
+
require 'rclconf'
|
5
|
+
|
6
|
+
module PdfInvoice
|
7
|
+
def PdfInvoice.config(argv=[])
|
8
|
+
default_dir = File.join(Dir.home, '.pdfinvoice')
|
9
|
+
default_config_files = [
|
10
|
+
File.join(default_dir, 'config.yml'),
|
11
|
+
'/etc/pdfinvoice/config.yml',
|
12
|
+
]
|
13
|
+
defaults = {
|
14
|
+
'colors' => {
|
15
|
+
'items' => [0xFA, 0xFA, 0xFA],
|
16
|
+
'total' => [0xF0, 0xF0, 0xF0],
|
17
|
+
},
|
18
|
+
'config' => default_config_files,
|
19
|
+
'creditor_address' => "Please set creditor_address etc in: #{default_config_files}",
|
20
|
+
'creditor_email' => '',
|
21
|
+
'creditor_bank' => '',
|
22
|
+
'due_days' => '',
|
23
|
+
'font' => 'Helvetica',
|
24
|
+
'font_b' => 'Helvetica-Bold',
|
25
|
+
'formats' => {
|
26
|
+
'currency' => "%1.2f",
|
27
|
+
'total' => "%1.2f",
|
28
|
+
'date' => "%d.%m.%Y",
|
29
|
+
'invoice_number' => "<b>#%06i</b>",
|
30
|
+
'quantity' => '%1.1f',
|
31
|
+
},
|
32
|
+
'logo_path' => nil,
|
33
|
+
'logo_link' => nil,
|
34
|
+
'tax' => 0,
|
35
|
+
'texts' => {
|
36
|
+
'date' => 'Date',
|
37
|
+
'description' => 'Description',
|
38
|
+
'unit' => 'Unit',
|
39
|
+
'quantity' => 'Quantity',
|
40
|
+
'price' => 'Price',
|
41
|
+
'item_total' => 'Item Total',
|
42
|
+
'subtotal' => 'Subtotal',
|
43
|
+
'tax' => 'Tax',
|
44
|
+
'thanks' => nil,
|
45
|
+
'total' => 'Total',
|
46
|
+
},
|
47
|
+
'text_options' => {:spacing => 1.25},
|
48
|
+
}
|
49
|
+
config = RCLConf::RCLConf.new(ARGV, defaults)
|
50
|
+
config.load(config.config)
|
51
|
+
config
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,203 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
# Invoice -- pdfinvoice -- 25.07.2005 -- hwyss@ywesee.com
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'rubygems'
|
7
|
+
rescue LoadError
|
8
|
+
warn "could not load 'rubygems'"
|
9
|
+
end
|
10
|
+
require 'pdf/writer'
|
11
|
+
require 'pdf/simpletable'
|
12
|
+
|
13
|
+
module PdfInvoice
|
14
|
+
class Invoice
|
15
|
+
attr_accessor :invoice_number, :debitor_address, :items, :date, :description
|
16
|
+
def initialize(config)
|
17
|
+
@config = config
|
18
|
+
@date = Date.today
|
19
|
+
@items = []
|
20
|
+
end
|
21
|
+
def to_pdf
|
22
|
+
pdf = PDF::Writer.new
|
23
|
+
pdf.margins_pt(pdf.mm2pts(15), pdf.mm2pts(25),
|
24
|
+
pdf.mm2pts(15), pdf.mm2pts(15))
|
25
|
+
pdf.select_font(@config.font)
|
26
|
+
pdf_header(pdf)
|
27
|
+
pdf_items(pdf)
|
28
|
+
pdf_footer(pdf)
|
29
|
+
pdf.render
|
30
|
+
end
|
31
|
+
private
|
32
|
+
def calculate_column_widths(pdf, widths, data)
|
33
|
+
data.each { |key, text|
|
34
|
+
widths[key] = [widths[key], text_width(pdf, text)].max
|
35
|
+
}
|
36
|
+
widths
|
37
|
+
end
|
38
|
+
def currency_format(amount, fmt='currency')
|
39
|
+
sprintf(@config.formats[fmt], amount)
|
40
|
+
end
|
41
|
+
def number_format(string)
|
42
|
+
string.reverse.gsub(/\d{3}(?=\d)(?!\d*\.)/) do |match|
|
43
|
+
match << "'"
|
44
|
+
end.reverse
|
45
|
+
end
|
46
|
+
def pdf_footer(pdf)
|
47
|
+
if(txt = @config.texts['thanks'])
|
48
|
+
pdf.move_pointer(pdf.font_height)
|
49
|
+
pdf.text(txt, @config.text_options)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
def pdf_header(pdf)
|
53
|
+
if(path = @config.logo_path)
|
54
|
+
args = {:pad => 0}
|
55
|
+
if(url = @config.logo_link)
|
56
|
+
args.store(:link, url)
|
57
|
+
end
|
58
|
+
pdf.image(path, args)
|
59
|
+
end
|
60
|
+
pdf.start_columns(2)
|
61
|
+
pdf.text(sprintf(@config.formats['invoice_number'],
|
62
|
+
@invoice_number), @config.text_options)
|
63
|
+
pdf.text(@description.to_s, @config.text_options)
|
64
|
+
pdf.start_new_page
|
65
|
+
pdf_lines(pdf, @config.creditor_address)
|
66
|
+
pdf.stop_columns
|
67
|
+
pdf.start_columns(2)
|
68
|
+
pdf_lines(pdf, @debitor_address)
|
69
|
+
pdf.start_new_page
|
70
|
+
pdf.text(@config.creditor_email, @config.text_options)
|
71
|
+
pdf_lines(pdf, @config.creditor_bank)
|
72
|
+
pdf.stop_columns
|
73
|
+
pdf.move_pointer(pdf.font_height)
|
74
|
+
pdf.start_columns(2)
|
75
|
+
pdf.text(@config.due_days, @config.text_options)
|
76
|
+
pdf.start_new_page
|
77
|
+
pdf.text(@date.strftime(@config.formats['date']), @config.text_options)
|
78
|
+
pdf.stop_columns
|
79
|
+
end
|
80
|
+
def pdf_items(pdf)
|
81
|
+
sstyle = PDF::Writer::StrokeStyle::DEFAULT.dup
|
82
|
+
sstyle.width = 0.5
|
83
|
+
sstyle.dash = { :pattern => [1] }
|
84
|
+
pdf.start_columns(1)
|
85
|
+
pdf.move_pointer(pdf.font_height)
|
86
|
+
total = 0.0
|
87
|
+
vat = 0.0
|
88
|
+
left = 0
|
89
|
+
width = 0
|
90
|
+
row_gap = 4
|
91
|
+
columns = ['date', 'description', 'unit', 'quantity', 'price',
|
92
|
+
'item_total']
|
93
|
+
column_widths = {}
|
94
|
+
pdf.select_font(@config.font_b)
|
95
|
+
headings = columns.collect { |col|
|
96
|
+
heading = @config.texts[col]
|
97
|
+
column_widths.store(col, text_width(pdf, heading))
|
98
|
+
heading
|
99
|
+
}
|
100
|
+
['Zwischensumme', 'MwSt 7.5%', 'Fälliger Betrag'].each { |title|
|
101
|
+
calculate_column_widths(pdf, column_widths, {'date' => title})
|
102
|
+
}
|
103
|
+
pdf.select_font(@config.font)
|
104
|
+
PDF::SimpleTable.new { |table|
|
105
|
+
table.column_order = columns
|
106
|
+
columns.each_with_index { |col, idx|
|
107
|
+
table.columns[col] = PDF::SimpleTable::Column.new('date') {
|
108
|
+
|column|
|
109
|
+
column.heading = PDF::SimpleTable::Column::Heading.new(col)
|
110
|
+
column.heading.title = headings.at(idx)
|
111
|
+
if(['quantity', 'price', 'item_total'].include?(col))
|
112
|
+
column.justification = :right
|
113
|
+
column.heading.justification = :right
|
114
|
+
end
|
115
|
+
}
|
116
|
+
}
|
117
|
+
table.data = @items.collect { |line|
|
118
|
+
item_total = line.at(3).to_f * line.at(4).to_f
|
119
|
+
vat += line[5] || @config.tax.to_f * item_total
|
120
|
+
total += item_total
|
121
|
+
date = line.at(0).strftime(@config.formats['date'])
|
122
|
+
cw = pdf.text_width(date) * PDF::SimpleTable::WIDTH_FACTOR
|
123
|
+
data = {
|
124
|
+
'date' => date,
|
125
|
+
'description' => number_format(line.at(1)),
|
126
|
+
'unit' => line.at(2),
|
127
|
+
'quantity' => number_format(sprintf(@config.formats['quantity'],
|
128
|
+
line.at(3))),
|
129
|
+
'price' => number_format(currency_format(line.at(4))),
|
130
|
+
'item_total' => number_format(currency_format(item_total)),
|
131
|
+
}
|
132
|
+
calculate_column_widths(pdf, column_widths, data)
|
133
|
+
data
|
134
|
+
}
|
135
|
+
column_widths.each { |key, col_width|
|
136
|
+
unless(key == 'description')
|
137
|
+
table.columns[key].width = col_width + 2 * table.column_gap
|
138
|
+
end
|
139
|
+
}
|
140
|
+
table.position = left = pdf.left_margin + table.column_gap
|
141
|
+
table.orientation = :right
|
142
|
+
table.width = width = pdf.margin_width - 2 * table.column_gap
|
143
|
+
cl = Color::RGB.new(*@config.colors['items'])
|
144
|
+
table.shade_color2 = table.shade_color = cl
|
145
|
+
table.shade_rows = :striped
|
146
|
+
table.show_lines = :all
|
147
|
+
table.inner_line_style = sstyle
|
148
|
+
table.outer_line_style = sstyle
|
149
|
+
table.row_gap = row_gap
|
150
|
+
table.bold_headings = true
|
151
|
+
table.heading_font_size = 10
|
152
|
+
table.render_on(pdf)
|
153
|
+
}
|
154
|
+
pdf.select_font(@config.font_b)
|
155
|
+
PDF::SimpleTable.new { |table|
|
156
|
+
table.column_order = ['date', 'total']
|
157
|
+
table.data = [
|
158
|
+
{ 'date' => @config.texts['subtotal'],
|
159
|
+
'total' => number_format(currency_format(total, 'total'))},
|
160
|
+
{ 'date' => @config.texts['tax'],
|
161
|
+
'total' => number_format(currency_format(vat, 'total')) },
|
162
|
+
{ 'date' => @config.texts['total'],
|
163
|
+
'total' => number_format(currency_format(total + vat, 'total')) },
|
164
|
+
]
|
165
|
+
table.show_headings = false
|
166
|
+
table.position = left
|
167
|
+
table.orientation = :right
|
168
|
+
table.width = width
|
169
|
+
table.columns['date'] = PDF::SimpleTable::Column.new('date') {
|
170
|
+
|column|
|
171
|
+
column.width = column_widths['date'] + 2 * table.column_gap
|
172
|
+
}
|
173
|
+
table.columns['total'] = PDF::SimpleTable::Column.new('date') {
|
174
|
+
|column|
|
175
|
+
column.justification = :right
|
176
|
+
}
|
177
|
+
cl = Color::RGB.new(*@config.colors['total'])
|
178
|
+
table.shade_color2 = table.shade_color = cl
|
179
|
+
table.shade_rows = :striped
|
180
|
+
table.show_lines = :all
|
181
|
+
table.inner_line_style = sstyle
|
182
|
+
table.outer_line_style = sstyle
|
183
|
+
table.row_gap = row_gap
|
184
|
+
table.render_on(pdf)
|
185
|
+
}
|
186
|
+
pdf.select_font(@config.font)
|
187
|
+
end
|
188
|
+
def pdf_lines(pdf, lines)
|
189
|
+
if (lines && lines.is_a?(Array))
|
190
|
+
lines.each { |line|
|
191
|
+
pdf.text(line.strip, @config.text_options)
|
192
|
+
}
|
193
|
+
elsif (lines && lines.is_a?(String))
|
194
|
+
lines.each_line { |line|
|
195
|
+
pdf.text(line.strip, @config.text_options)
|
196
|
+
}
|
197
|
+
end
|
198
|
+
end
|
199
|
+
def text_width(pdf, text)
|
200
|
+
pdf.text_width(text) * PDF::SimpleTable::WIDTH_FACTOR
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|