invoicing 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/CHANGELOG +3 -0
  2. data/LICENSE +20 -0
  3. data/Manifest +60 -0
  4. data/README +48 -0
  5. data/Rakefile +75 -0
  6. data/invoicing.gemspec +41 -0
  7. data/lib/invoicing.rb +9 -0
  8. data/lib/invoicing/cached_record.rb +107 -0
  9. data/lib/invoicing/class_info.rb +187 -0
  10. data/lib/invoicing/connection_adapter_ext.rb +44 -0
  11. data/lib/invoicing/countries/uk.rb +24 -0
  12. data/lib/invoicing/currency_value.rb +212 -0
  13. data/lib/invoicing/find_subclasses.rb +193 -0
  14. data/lib/invoicing/ledger_item.rb +718 -0
  15. data/lib/invoicing/ledger_item/render_html.rb +515 -0
  16. data/lib/invoicing/ledger_item/render_ubl.rb +268 -0
  17. data/lib/invoicing/line_item.rb +246 -0
  18. data/lib/invoicing/price.rb +9 -0
  19. data/lib/invoicing/tax_rate.rb +9 -0
  20. data/lib/invoicing/taxable.rb +355 -0
  21. data/lib/invoicing/time_dependent.rb +388 -0
  22. data/lib/invoicing/version.rb +21 -0
  23. data/test/cached_record_test.rb +100 -0
  24. data/test/class_info_test.rb +253 -0
  25. data/test/connection_adapter_ext_test.rb +71 -0
  26. data/test/currency_value_test.rb +184 -0
  27. data/test/find_subclasses_test.rb +120 -0
  28. data/test/fixtures/README +7 -0
  29. data/test/fixtures/cached_record.sql +22 -0
  30. data/test/fixtures/class_info.sql +28 -0
  31. data/test/fixtures/currency_value.sql +29 -0
  32. data/test/fixtures/find_subclasses.sql +43 -0
  33. data/test/fixtures/ledger_item.sql +39 -0
  34. data/test/fixtures/line_item.sql +33 -0
  35. data/test/fixtures/price.sql +4 -0
  36. data/test/fixtures/tax_rate.sql +4 -0
  37. data/test/fixtures/taxable.sql +14 -0
  38. data/test/fixtures/time_dependent.sql +35 -0
  39. data/test/ledger_item_test.rb +352 -0
  40. data/test/line_item_test.rb +139 -0
  41. data/test/models/README +4 -0
  42. data/test/models/test_subclass_in_another_file.rb +3 -0
  43. data/test/models/test_subclass_not_in_database.rb +6 -0
  44. data/test/price_test.rb +9 -0
  45. data/test/ref-output/creditnote3.html +82 -0
  46. data/test/ref-output/creditnote3.xml +89 -0
  47. data/test/ref-output/invoice1.html +93 -0
  48. data/test/ref-output/invoice1.xml +111 -0
  49. data/test/ref-output/invoice2.html +86 -0
  50. data/test/ref-output/invoice2.xml +98 -0
  51. data/test/ref-output/invoice_null.html +36 -0
  52. data/test/render_html_test.rb +69 -0
  53. data/test/render_ubl_test.rb +32 -0
  54. data/test/setup.rb +37 -0
  55. data/test/tax_rate_test.rb +9 -0
  56. data/test/taxable_test.rb +180 -0
  57. data/test/test_helper.rb +48 -0
  58. data/test/time_dependent_test.rb +180 -0
  59. data/website/curvycorners.js +1 -0
  60. data/website/screen.css +149 -0
  61. data/website/template.html.erb +43 -0
  62. metadata +180 -0
@@ -0,0 +1,48 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'activerecord'
4
+ require 'activesupport'
5
+ require 'flexmock/test_unit'
6
+ require 'mocha'
7
+
8
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
9
+
10
+ ActiveSupport::Dependencies.load_paths << File.join(File.dirname(__FILE__), 'models')
11
+
12
+ require 'invoicing'
13
+
14
+ TEST_DB_CONFIG = {
15
+ :postgresql => {:adapter => "postgresql", :host => "localhost", :database => "invoicing_test",
16
+ :username => "postgres", :password => ""},
17
+ :mysql => {:adapter => "mysql", :host => "localhost", :database => "invoicing_test",
18
+ :username => "root", :password => ""},
19
+ :sqlite3 => {:adapter => "sqlite3", :database => Tempfile.new('invoicing_sqlite').path}
20
+ }
21
+
22
+ def connect_to_testing_database
23
+ ActiveRecord::Base.establish_connection(TEST_DB_CONFIG[(ENV['DATABASE'] || :mysql).to_sym])
24
+ end
25
+
26
+ connect_to_testing_database
27
+
28
+ ENV['TZ'] = 'Etc/UTC' # timezone of values in database
29
+ ActiveRecord::Base.default_timezone = :utc # timezone of created_at and updated_at
30
+ Time.zone = 'Etc/UTC' # timezone for output (when using Time#in_time_zone)
31
+
32
+
33
+ # Behave a bit like ActiveRecord's transactional fixtures.
34
+ module Test
35
+ module Unit
36
+ class TestCase
37
+ def setup
38
+ ActiveRecord::Base.connection.increment_open_transactions
39
+ ActiveRecord::Base.connection.begin_db_transaction
40
+ end
41
+
42
+ def teardown
43
+ ActiveRecord::Base.connection.rollback_db_transaction
44
+ ActiveRecord::Base.connection.decrement_open_transactions
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,180 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper.rb')
2
+
3
+ class CachedRecordTest < Test::Unit::TestCase
4
+
5
+ class TimeDependentRecord < ActiveRecord::Base
6
+ # All columns are renamed to test renaming
7
+ set_primary_key 'id2'
8
+ acts_as_time_dependent :id => 'id2', :valid_from => 'valid_from2', :valid_until => 'valid_until2',
9
+ :replaced_by_id => 'replaced_by_id2', :value => 'value2', :is_default => 'is_default2'
10
+ end
11
+
12
+
13
+ def test_valid_records_during_single_period
14
+ records = TimeDependentRecord.valid_records_during(DateTime.parse('2009-01-01'), DateTime.parse('2009-03-01'))
15
+ assert_equal [3, 6, 8, 10], records.map{|r| r.id2}.sort
16
+ end
17
+
18
+ def test_valid_records_during_single_period_ending_on_change_date
19
+ records = TimeDependentRecord.valid_records_during(DateTime.parse('2008-10-31'), DateTime.parse('2009-01-01'))
20
+ assert_equal [1, 2, 5, 8, 10], records.map{|r| r.id2}.sort
21
+ end
22
+
23
+ def test_valid_records_during_transition_period
24
+ records = TimeDependentRecord.valid_records_during(DateTime.parse('2008-09-01'), DateTime.parse('2009-02-28'))
25
+ assert_equal [1, 2, 5, 6, 8, 10], records.map{|r| r.id2}.sort
26
+ end
27
+
28
+ def test_valid_records_during_period_after_unreplaced_expiry
29
+ records = TimeDependentRecord.valid_records_during(DateTime.parse('2011-09-01'), DateTime.parse('2011-09-02'))
30
+ assert_equal [4, 9, 10], records.map{|r| r.id2}.sort
31
+ end
32
+
33
+ def test_valid_records_at_boundary
34
+ records = TimeDependentRecord.valid_records_at(DateTime.parse('2010-01-01'))
35
+ assert_equal [4, 7, 8, 10], records.map{|r| r.id2}.sort
36
+ end
37
+
38
+ def test_valid_records_at_middle_of_period
39
+ records = TimeDependentRecord.valid_records_at(DateTime.parse('2009-07-01'))
40
+ assert_equal [3, 6, 8, 10], records.map{|r| r.id2}.sort
41
+ end
42
+
43
+ def test_valid_records_at_just_before_end_of_period
44
+ records = TimeDependentRecord.valid_records_at(DateTime.parse('2008-12-31 23:59:59'))
45
+ assert_equal [1, 2, 5, 8, 10], records.map{|r| r.id2}.sort
46
+ end
47
+
48
+ def test_default_record_at_returns_default
49
+ assert_equal 9, TimeDependentRecord.default_record_at(DateTime.parse('2011-04-01')).id2
50
+ end
51
+
52
+ def test_default_record_at_where_there_is_no_default
53
+ assert_nil TimeDependentRecord.default_record_at(DateTime.parse('2008-03-01'))
54
+ end
55
+
56
+ def test_default_value_at
57
+ assert_equal 'Seven', TimeDependentRecord.default_value_at(DateTime.parse('2010-01-01 00:00:01'))
58
+ end
59
+
60
+ def test_default_value_at_alias
61
+ assert_equal 'Six', TimeDependentRecord.default_value2_at(DateTime.parse('2009-12-31 23:59:59'))
62
+ end
63
+
64
+ def test_default_record_now
65
+ # Hello future. This is January 2009 speaking. Is someone out there still using this library?
66
+ # If so, you may want to update this test from time to time. But you probably won't need to.
67
+ expected = case Date.today.year
68
+ when 2009 then 6
69
+ when 2010 then 7
70
+ else 9
71
+ end
72
+ assert_equal expected, TimeDependentRecord.default_record_now.id2
73
+ end
74
+
75
+ def test_default_value_now
76
+ expected = case Date.today.year
77
+ when 2009 then 'Six'
78
+ when 2010 then 'Seven'
79
+ else 'Nine'
80
+ end
81
+ assert_equal expected, TimeDependentRecord.default_value_now
82
+ end
83
+
84
+ def test_default_value_now_alias
85
+ expected = case Date.today.year
86
+ when 2009 then 'Six'
87
+ when 2010 then 'Seven'
88
+ else 'Nine'
89
+ end
90
+ assert_equal expected, TimeDependentRecord.default_value2_now
91
+ end
92
+
93
+ def test_multiple_predecessors
94
+ assert_equal [2, 5], TimeDependentRecord.find(3).predecessors.map{|r| r.id2}.sort
95
+ end
96
+
97
+ def test_one_predecessor
98
+ assert_equal [8], TimeDependentRecord.find(9).predecessors.map{|r| r.id2}
99
+ end
100
+
101
+ def test_no_predecessors
102
+ assert_equal [], TimeDependentRecord.find(1).predecessors
103
+ end
104
+
105
+ def test_record_at_same_period
106
+ assert_equal 3, TimeDependentRecord.find(3).record_at(DateTime.parse('2009-12-31 23:59:59')).id2
107
+ end
108
+
109
+ def test_record_at_next_period
110
+ assert_equal 4, TimeDependentRecord.find(3).record_at(DateTime.parse('2010-01-01 00:00:00')).id2
111
+ end
112
+
113
+ def test_record_at_future_period
114
+ assert_equal 4, TimeDependentRecord.find(2).record_at(DateTime.parse('2036-07-09')).id2
115
+ end
116
+
117
+ def test_record_at_within_long_period
118
+ assert_equal 8, TimeDependentRecord.find(8).record_at(DateTime.parse('2010-12-31 23:59:58')).id2
119
+ end
120
+
121
+ def test_record_at_with_no_replacement
122
+ assert_nil TimeDependentRecord.find(1).record_at(DateTime.parse('2009-07-09'))
123
+ end
124
+
125
+ def test_record_at_with_no_predecessor
126
+ assert_nil TimeDependentRecord.find(7).record_at(DateTime.parse('2008-07-09'))
127
+ end
128
+
129
+ def test_record_at_with_unique_predecessor
130
+ assert_equal 3, TimeDependentRecord.find(4).record_at(DateTime.parse('2009-01-01')).id2
131
+ end
132
+
133
+ def test_record_at_with_ambiguous_predecessor
134
+ assert_nil TimeDependentRecord.find(4).record_at(DateTime.parse('2008-12-31'))
135
+ end
136
+
137
+ def test_record_at_long_ago
138
+ assert_nil TimeDependentRecord.find(10).record_at(DateTime.parse('1970-01-01'))
139
+ end
140
+
141
+ def test_record_now
142
+ assert_equal 10, TimeDependentRecord.find(10).record_now.id2
143
+ end
144
+
145
+ def test_value_at
146
+ assert_equal 'Four', TimeDependentRecord.find(5).value_at(DateTime.parse('2028-01-13'))
147
+ end
148
+
149
+ def test_value_at_alias
150
+ assert_equal 'Four', TimeDependentRecord.find(5).value2_at(DateTime.parse('2028-01-13'))
151
+ end
152
+
153
+ def test_value_now
154
+ assert_equal 'Ten', TimeDependentRecord.find(10).value_now
155
+ end
156
+
157
+ def test_value_now_alias
158
+ assert_equal 'Ten', TimeDependentRecord.find(10).value2_now
159
+ end
160
+
161
+ def test_changes_until_without_changes
162
+ assert_equal [], TimeDependentRecord.find(8).changes_until(DateTime.parse('2010-12-31 23:59:59'))
163
+ end
164
+
165
+ def test_changes_until_with_one_change
166
+ assert_equal [9], TimeDependentRecord.find(8).changes_until(DateTime.parse('2011-01-01')).map{|r| r.id2}
167
+ end
168
+
169
+ def test_changes_until_with_multiple_changes
170
+ assert_equal [3, 4], TimeDependentRecord.find(2).changes_until(DateTime.parse('2034-01-01')).map{|r| r.id2}
171
+ end
172
+
173
+ def test_changes_until_with_imminent_expiry
174
+ assert_equal [nil], TimeDependentRecord.find(1).changes_until(DateTime.parse('2009-01-01'))
175
+ end
176
+
177
+ def test_changes_until_with_future_expiry
178
+ assert_equal [TimeDependentRecord.find(7), nil], TimeDependentRecord.find(6).changes_until(DateTime.parse('2012-01-01'))
179
+ end
180
+ end
@@ -0,0 +1 @@
1
+ var isIE=navigator.userAgent.toLowerCase().indexOf("msie")>-1;var isMoz=document.implementation&&document.implementation.createDocument;var isSafari=((navigator.userAgent.toLowerCase().indexOf("safari")!=-1)&&(navigator.userAgent.toLowerCase().indexOf("mac")!=-1))?true:false;function curvyCorners(){if(typeof(arguments[0])!="object"){throw newCurvyError("First parameter of curvyCorners() must be an object.")}if(typeof(arguments[1])!="object"&&typeof(arguments[1])!="string"){throw newCurvyError("Second parameter of curvyCorners() must be an object or a class name.")}if(typeof(arguments[1])=="string"){var G=0;var A=getElementsByClass(arguments[1])}else{var G=1;var A=arguments}var D=new Array();if(arguments[0].validTags){var F=arguments[0].validTags}else{var F=["div"]}for(var C=G,B=A.length;C<B;C++){var E=A[C].tagName.toLowerCase();if(inArray(F,E)!==false){D[D.length]=new curvyObject(arguments[0],A[C])}}this.objects=D;this.applyCornersToAll=function(){for(var H=0,I=this.objects.length;H<I;H++){this.objects[H].applyCorners()}}}function curvyObject(){this.box=arguments[1];this.settings=arguments[0];this.topContainer=null;this.bottomContainer=null;this.masterCorners=new Array();this.contentDIV=null;var G=get_style(this.box,"height","height");var D=get_style(this.box,"width","width");var A=get_style(this.box,"borderTopWidth","border-top-width");var H=get_style(this.box,"borderTopColor","border-top-color");var C=get_style(this.box,"backgroundColor","background-color");var E=get_style(this.box,"backgroundImage","background-image");var B=get_style(this.box,"position","position");var F=get_style(this.box,"paddingTop","padding-top");this.boxHeight=parseInt(((G!=""&&G!="auto"&&G.indexOf("%")==-1)?G.substring(0,G.indexOf("px")):this.box.scrollHeight));this.boxWidth=parseInt(((D!=""&&D!="auto"&&D.indexOf("%")==-1)?D.substring(0,D.indexOf("px")):this.box.scrollWidth));this.borderWidth=parseInt(((A!=""&&A.indexOf("px")!==-1)?A.slice(0,A.indexOf("px")):0));this.boxColour=format_colour(C);this.boxPadding=parseInt(((F!=""&&F.indexOf("px")!==-1)?F.slice(0,F.indexOf("px")):0));this.borderColour=format_colour(H);this.borderString=this.borderWidth+"px solid "+this.borderColour;this.backgroundImage=((E!="none")?E:"");this.boxContent=this.box.innerHTML;if(B!="absolute"){this.box.style.position="relative"}this.box.style.padding="0px";if(isIE&&D=="auto"&&G=="auto"){this.box.style.width="100%"}if(this.settings.autoPad==true&&this.boxPadding>0){this.box.innerHTML=""}this.applyCorners=function(){for(var Z=0;Z<2;Z++){switch(Z){case 0:if(this.settings.tl||this.settings.tr){var W=document.createElement("DIV");W.style.width="100%";W.style.fontSize="1px";W.style.overflow="hidden";W.style.position="absolute";W.style.paddingLeft=this.borderWidth+"px";W.style.paddingRight=this.borderWidth+"px";var R=Math.max(this.settings.tl?this.settings.tl.radius:0,this.settings.tr?this.settings.tr.radius:0);W.style.height=R+"px";W.style.top=0-R+"px";W.style.left=0-this.borderWidth+"px";this.topContainer=this.box.appendChild(W)}break;case 1:if(this.settings.bl||this.settings.br){var W=document.createElement("DIV");W.style.width="100%";W.style.fontSize="1px";W.style.overflow="hidden";W.style.position="absolute";W.style.paddingLeft=this.borderWidth+"px";W.style.paddingRight=this.borderWidth+"px";var X=Math.max(this.settings.bl?this.settings.bl.radius:0,this.settings.br?this.settings.br.radius:0);W.style.height=X+"px";W.style.bottom=0-X+"px";W.style.left=0-this.borderWidth+"px";this.bottomContainer=this.box.appendChild(W)}break}}if(this.topContainer){this.box.style.borderTopWidth="0px"}if(this.bottomContainer){this.box.style.borderBottomWidth="0px"}var d=["tr","tl","br","bl"];for(var h in d){if(h>-1<4){var c=d[h];if(!this.settings[c]){if(((c=="tr"||c=="tl")&&this.topContainer!=null)||((c=="br"||c=="bl")&&this.bottomContainer!=null)){var V=document.createElement("DIV");V.style.position="relative";V.style.fontSize="1px";V.style.overflow="hidden";if(this.backgroundImage==""){V.style.backgroundColor=this.boxColour}else{V.style.backgroundImage=this.backgroundImage}switch(c){case"tl":V.style.height=R-this.borderWidth+"px";V.style.marginRight=this.settings.tr.radius-(this.borderWidth*2)+"px";V.style.borderLeft=this.borderString;V.style.borderTop=this.borderString;V.style.left=-this.borderWidth+"px";break;case"tr":V.style.height=R-this.borderWidth+"px";V.style.marginLeft=this.settings.tl.radius-(this.borderWidth*2)+"px";V.style.borderRight=this.borderString;V.style.borderTop=this.borderString;V.style.backgroundPosition="-"+(R+this.borderWidth)+"px 0px";V.style.left=this.borderWidth+"px";break;case"bl":V.style.height=X-this.borderWidth+"px";V.style.marginRight=this.settings.br.radius-(this.borderWidth*2)+"px";V.style.borderLeft=this.borderString;V.style.borderBottom=this.borderString;V.style.left=-this.borderWidth+"px";V.style.backgroundPosition="-"+(this.borderWidth)+"px -"+(this.boxHeight+(X+this.borderWidth))+"px";break;case"br":V.style.height=X-this.borderWidth+"px";V.style.marginLeft=this.settings.bl.radius-(this.borderWidth*2)+"px";V.style.borderRight=this.borderString;V.style.borderBottom=this.borderString;V.style.left=this.borderWidth+"px";V.style.backgroundPosition="-"+(X+this.borderWidth)+"px -"+(this.boxHeight+(X+this.borderWidth))+"px";break}}}else{if(this.masterCorners[this.settings[c].radius]){var V=this.masterCorners[this.settings[c].radius].cloneNode(true)}else{var V=document.createElement("DIV");V.style.height=this.settings[c].radius+"px";V.style.width=this.settings[c].radius+"px";V.style.position="absolute";V.style.fontSize="1px";V.style.overflow="hidden";var M=parseInt(this.settings[c].radius-this.borderWidth);for(var T=0,g=this.settings[c].radius;T<g;T++){if((T+1)>=M){var O=-1}else{var O=(Math.floor(Math.sqrt(Math.pow(M,2)-Math.pow((T+1),2)))-1)}if(M!=g){if((T)>=M){var L=-1}else{var L=Math.ceil(Math.sqrt(Math.pow(M,2)-Math.pow(T,2)))}if((T+1)>=g){var J=-1}else{var J=(Math.floor(Math.sqrt(Math.pow(g,2)-Math.pow((T+1),2)))-1)}}if((T)>=g){var I=-1}else{var I=Math.ceil(Math.sqrt(Math.pow(g,2)-Math.pow(T,2)))}if(O>-1){this.drawPixel(T,0,this.boxColour,100,(O+1),V,-1,this.settings[c].radius)}if(M!=g){for(var S=(O+1);S<L;S++){if(this.settings.antiAlias){if(this.backgroundImage!=""){var K=(pixelFraction(T,S,M)*100);if(K<30){this.drawPixel(T,S,this.borderColour,100,1,V,0,this.settings[c].radius)}else{this.drawPixel(T,S,this.borderColour,100,1,V,-1,this.settings[c].radius)}}else{var b=BlendColour(this.boxColour,this.borderColour,pixelFraction(T,S,M));this.drawPixel(T,S,b,100,1,V,0,this.settings[c].radius,c)}}}if(this.settings.antiAlias){if(J>=L){if(L==-1){L=0}this.drawPixel(T,L,this.borderColour,100,(J-L+1),V,0,0)}}else{if(J>=O){this.drawPixel(T,(O+1),this.borderColour,100,(J-O),V,0,0)}}var Q=this.borderColour}else{var Q=this.boxColour;var J=O}if(this.settings.antiAlias){for(var S=(J+1);S<I;S++){this.drawPixel(T,S,Q,(pixelFraction(T,S,g)*100),1,V,((this.borderWidth>0)?0:-1),this.settings[c].radius)}}}this.masterCorners[this.settings[c].radius]=V.cloneNode(true)}if(c!="br"){for(var Z=0,f=V.childNodes.length;Z<f;Z++){var U=V.childNodes[Z];var e=parseInt(U.style.top.substring(0,U.style.top.indexOf("px")));var m=parseInt(U.style.left.substring(0,U.style.left.indexOf("px")));var o=parseInt(U.style.height.substring(0,U.style.height.indexOf("px")));if(c=="tl"||c=="bl"){U.style.left=this.settings[c].radius-m-1+"px"}if(c=="tr"||c=="tl"){U.style.top=this.settings[c].radius-o-e+"px"}switch(c){case"tr":U.style.backgroundPosition="-"+Math.abs((this.boxWidth-this.settings[c].radius+this.borderWidth)+m)+"px -"+Math.abs(this.settings[c].radius-o-e-this.borderWidth)+"px";break;case"tl":U.style.backgroundPosition="-"+Math.abs((this.settings[c].radius-m-1)-this.borderWidth)+"px -"+Math.abs(this.settings[c].radius-o-e-this.borderWidth)+"px";break;case"bl":U.style.backgroundPosition="-"+Math.abs((this.settings[c].radius-m-1)-this.borderWidth)+"px -"+Math.abs((this.boxHeight+this.settings[c].radius+e)-this.borderWidth)+"px";break}}}}if(V){switch(c){case"tl":if(V.style.position=="absolute"){V.style.top="0px"}if(V.style.position=="absolute"){V.style.left="0px"}if(this.topContainer){this.topContainer.appendChild(V)}break;case"tr":if(V.style.position=="absolute"){V.style.top="0px"}if(V.style.position=="absolute"){V.style.right="0px"}if(this.topContainer){this.topContainer.appendChild(V)}break;case"bl":if(V.style.position=="absolute"){V.style.bottom="0px"}if(V.style.position=="absolute"){V.style.left="0px"}if(this.bottomContainer){this.bottomContainer.appendChild(V)}break;case"br":if(V.style.position=="absolute"){V.style.bottom="0px"}if(V.style.position=="absolute"){V.style.right="0px"}if(this.bottomContainer){this.bottomContainer.appendChild(V)}break}}}}var Y=new Array();Y.t=Math.abs(this.settings.tl.radius-this.settings.tr.radius);Y.b=Math.abs(this.settings.bl.radius-this.settings.br.radius);for(z in Y){if(z=="t"||z=="b"){if(Y[z]){var l=((this.settings[z+"l"].radius<this.settings[z+"r"].radius)?z+"l":z+"r");var N=document.createElement("DIV");N.style.height=Y[z]+"px";N.style.width=this.settings[l].radius+"px";N.style.position="absolute";N.style.fontSize="1px";N.style.overflow="hidden";N.style.backgroundColor=this.boxColour;switch(l){case"tl":N.style.bottom="0px";N.style.left="0px";N.style.borderLeft=this.borderString;this.topContainer.appendChild(N);break;case"tr":N.style.bottom="0px";N.style.right="0px";N.style.borderRight=this.borderString;this.topContainer.appendChild(N);break;case"bl":N.style.top="0px";N.style.left="0px";N.style.borderLeft=this.borderString;this.bottomContainer.appendChild(N);break;case"br":N.style.top="0px";N.style.right="0px";N.style.borderRight=this.borderString;this.bottomContainer.appendChild(N);break}}var P=document.createElement("DIV");P.style.position="relative";P.style.fontSize="1px";P.style.overflow="hidden";P.style.backgroundColor=this.boxColour;P.style.backgroundImage=this.backgroundImage;switch(z){case"t":if(this.topContainer){if(this.settings.tl.radius&&this.settings.tr.radius){P.style.height=R-this.borderWidth+"px";P.style.marginLeft=this.settings.tl.radius-this.borderWidth+"px";P.style.marginRight=this.settings.tr.radius-this.borderWidth+"px";P.style.borderTop=this.borderString;if(this.backgroundImage!=""){P.style.backgroundPosition="-"+(R-this.borderWidth)+"px 0px"}this.topContainer.appendChild(P)}this.box.style.backgroundPosition="0px -"+(R-this.borderWidth)+"px"}break;case"b":if(this.bottomContainer){if(this.settings.bl.radius&&this.settings.br.radius){P.style.height=X-this.borderWidth+"px";P.style.marginLeft=this.settings.bl.radius-this.borderWidth+"px";P.style.marginRight=this.settings.br.radius-this.borderWidth+"px";P.style.borderBottom=this.borderString;if(this.backgroundImage!=""){P.style.backgroundPosition="-"+(X-this.borderWidth)+"px -"+(this.boxHeight+(R-this.borderWidth))+"px"}this.bottomContainer.appendChild(P)}}break}}}if(this.settings.autoPad==true&&this.boxPadding>0){var a=document.createElement("DIV");a.style.position="relative";a.innerHTML=this.boxContent;a.className="autoPadDiv";var n=Math.abs(R-this.boxPadding);var p=Math.abs(X-this.boxPadding);if(R<this.boxPadding){a.style.paddingTop=n+"px"}if(X<this.boxPadding){a.style.paddingBottom=X+"px"}a.style.paddingLeft=this.boxPadding+"px";a.style.paddingRight=this.boxPadding+"px";this.contentDIV=this.box.appendChild(a)}};this.drawPixel=function(R,O,I,N,P,Q,K,M){var J=document.createElement("DIV");J.style.height=P+"px";J.style.width="1px";J.style.position="absolute";J.style.fontSize="1px";J.style.overflow="hidden";var L=Math.max(this.settings.tr.radius,this.settings.tl.radius);if(K==-1&&this.backgroundImage!=""){J.style.backgroundImage=this.backgroundImage;J.style.backgroundPosition="-"+(this.boxWidth-(M-R)+this.borderWidth)+"px -"+((this.boxHeight+L+O)-this.borderWidth)+"px"}else{J.style.backgroundColor=I}if(N!=100){setOpacity(J,N)}J.style.top=O+"px";J.style.left=R+"px";Q.appendChild(J)}}function insertAfter(B,C,A){B.insertBefore(C,A.nextSibling)}function BlendColour(L,J,G){var D=parseInt(L.substr(1,2),16);var K=parseInt(L.substr(3,2),16);var F=parseInt(L.substr(5,2),16);var C=parseInt(J.substr(1,2),16);var I=parseInt(J.substr(3,2),16);var E=parseInt(J.substr(5,2),16);if(G>1||G<0){G=1}var H=Math.round((D*G)+(C*(1-G)));if(H>255){H=255}if(H<0){H=0}var B=Math.round((K*G)+(I*(1-G)));if(B>255){B=255}if(B<0){B=0}var A=Math.round((F*G)+(E*(1-G)));if(A>255){A=255}if(A<0){A=0}return"#"+IntToHex(H)+IntToHex(B)+IntToHex(A)}function IntToHex(A){base=A/16;rem=A%16;base=base-(rem/16);baseS=MakeHex(base);remS=MakeHex(rem);return baseS+""+remS}function MakeHex(A){if((A>=0)&&(A<=9)){return A}else{switch(A){case 10:return"A";case 11:return"B";case 12:return"C";case 13:return"D";case 14:return"E";case 15:return"F"}}}function pixelFraction(H,G,A){var C=0;var B=new Array(1);var F=new Array(1);var I=0;var D="";var E=Math.sqrt((Math.pow(A,2)-Math.pow(H,2)));if((E>=G)&&(E<(G+1))){D="Left";B[I]=0;F[I]=E-G;I=I+1}var E=Math.sqrt((Math.pow(A,2)-Math.pow(G+1,2)));if((E>=H)&&(E<(H+1))){D=D+"Top";B[I]=E-H;F[I]=1;I=I+1}var E=Math.sqrt((Math.pow(A,2)-Math.pow(H+1,2)));if((E>=G)&&(E<(G+1))){D=D+"Right";B[I]=1;F[I]=E-G;I=I+1}var E=Math.sqrt((Math.pow(A,2)-Math.pow(G,2)));if((E>=H)&&(E<(H+1))){D=D+"Bottom";B[I]=E-H;F[I]=0}switch(D){case"LeftRight":C=Math.min(F[0],F[1])+((Math.max(F[0],F[1])-Math.min(F[0],F[1]))/2);break;case"TopRight":C=1-(((1-B[0])*(1-F[1]))/2);break;case"TopBottom":C=Math.min(B[0],B[1])+((Math.max(B[0],B[1])-Math.min(B[0],B[1]))/2);break;case"LeftBottom":C=(F[0]*B[1])/2;break;default:C=1}return C}function rgb2Hex(B){try{var C=rgb2Array(B);var G=parseInt(C[0]);var E=parseInt(C[1]);var A=parseInt(C[2]);var D="#"+IntToHex(G)+IntToHex(E)+IntToHex(A)}catch(F){alert("There was an error converting the RGB value to Hexadecimal in function rgb2Hex")}return D}function rgb2Array(A){var C=A.substring(4,A.indexOf(")"));var B=C.split(", ");return B}function setOpacity(F,C){C=(C==100)?99.999:C;if(isSafari&&F.tagName!="IFRAME"){var B=rgb2Array(F.style.backgroundColor);var E=parseInt(B[0]);var D=parseInt(B[1]);var A=parseInt(B[2]);F.style.backgroundColor="rgba("+E+", "+D+", "+A+", "+C/100+")"}else{if(typeof(F.style.opacity)!="undefined"){F.style.opacity=C/100}else{if(typeof(F.style.MozOpacity)!="undefined"){F.style.MozOpacity=C/100}else{if(typeof(F.style.filter)!="undefined"){F.style.filter="alpha(opacity:"+C+")"}else{if(typeof(F.style.KHTMLOpacity)!="undefined"){F.style.KHTMLOpacity=C/100}}}}}}function inArray(C,B){for(var A=0;A<C.length;A++){if(C[A]===B){return A}}return false}function inArrayKey(B,A){for(key in B){if(key===A){return true}}return false}function addEvent(E,D,B,A){if(E.addEventListener){E.addEventListener(D,B,A);return true}else{if(E.attachEvent){var C=E.attachEvent("on"+D,B);return C}else{E["on"+D]=B}}}function removeEvent(E,D,B,A){if(E.removeEventListener){E.removeEventListener(D,B,A);return true}else{if(E.detachEvent){var C=E.detachEvent("on"+D,B);return C}else{alert("Handler could not be removed")}}}function format_colour(B){var A="#ffffff";if(B!=""&&B!="transparent"){if(B.substr(0,3)=="rgb"){A=rgb2Hex(B)}else{if(B.length==4){A="#"+B.substring(1,2)+B.substring(1,2)+B.substring(2,3)+B.substring(2,3)+B.substring(3,4)+B.substring(3,4)}else{A=B}}}return A}function get_style(obj,property,propertyNS){try{if(obj.currentStyle){var returnVal=eval("obj.currentStyle."+property)}else{if(isSafari&&obj.style.display=="none"){obj.style.display="";var wasHidden=true}var returnVal=document.defaultView.getComputedStyle(obj,"").getPropertyValue(propertyNS);if(isSafari&&wasHidden){obj.style.display="none"}}}catch(e){}return returnVal}function getElementsByClass(G,E,A){var D=new Array();if(E==null){E=document}if(A==null){A="*"}var C=E.getElementsByTagName(A);var B=C.length;var F=new RegExp("(^|s)"+G+"(s|$)");for(i=0,j=0;i<B;i++){if(F.test(C[i].className)){D[j]=C[i];j++}}return D}function newCurvyError(A){return new Error("curvyCorners Error:\n"+A)};
@@ -0,0 +1,149 @@
1
+ body {
2
+ background-color: #b33;
3
+ font-family: Georgia, sans-serif;
4
+ font-size: 16px;
5
+ line-height: 1.6em;
6
+ padding: 1.6em 0 0 0;
7
+ color: #FFF;
8
+ }
9
+
10
+ h1, h2, h3, h4, h5, h6 {
11
+ color: #FFF;
12
+ }
13
+
14
+ h1 {
15
+ font-family: sans-serif;
16
+ font-weight: normal;
17
+ font-size: 4em;
18
+ line-height: 0.8em;
19
+ letter-spacing: -0.1ex;
20
+ margin: 5px;
21
+ }
22
+
23
+ li {
24
+ padding: 0;
25
+ margin: 0;
26
+ list-style-type: square;
27
+ }
28
+
29
+ a {
30
+ color: #5E5AFF;
31
+ background-color: #DAC;
32
+ font-weight: normal;
33
+ text-decoration: underline;
34
+ }
35
+
36
+ blockquote {
37
+ font-size: 90%;
38
+ font-style: italic;
39
+ border-left: 1px solid #111;
40
+ padding-left: 1em;
41
+ }
42
+
43
+ .caps {
44
+ font-size: 80%;
45
+ }
46
+
47
+ #main {
48
+ width: 45em;
49
+ padding: 0;
50
+ margin: 0 auto;
51
+ }
52
+
53
+ .coda {
54
+ text-align: right;
55
+ color: #77f;
56
+ font-size: smaller;
57
+ }
58
+
59
+ table {
60
+ font-size: 90%;
61
+ line-height: 1.4em;
62
+ color: #ff8;
63
+ background-color: #111;
64
+ padding: 2px 10px 2px 10px;
65
+ border-style: dashed;
66
+ }
67
+
68
+ th {
69
+ color: #fff;
70
+ }
71
+
72
+ td {
73
+ padding: 2px 10px 2px 10px;
74
+ }
75
+
76
+ .success {
77
+ color: #0CC52B;
78
+ }
79
+
80
+ .failed {
81
+ color: #E90A1B;
82
+ }
83
+
84
+ .unknown {
85
+ color: #995000;
86
+ }
87
+
88
+ pre, code {
89
+ font-family: monospace;
90
+ font-size: 90%;
91
+ line-height: 1.4em;
92
+ color: #ff8;
93
+ background-color: #111;
94
+ padding: 2px 10px 2px 10px;
95
+ }
96
+
97
+ .comment { color: #aaa; font-style: italic; }
98
+ .keyword { color: #eff; font-weight: bold; }
99
+ .punct { color: #eee; font-weight: bold; }
100
+ .symbol { color: #0bb; }
101
+ .string { color: #6b4; }
102
+ .ident { color: #ff8; }
103
+ .constant { color: #66f; }
104
+ .regex { color: #ec6; }
105
+ .number { color: #F99; }
106
+ .expr { color: #227; }
107
+
108
+ .sidebar {
109
+ float: right;
110
+ }
111
+
112
+ #version {
113
+ width: 170px;
114
+ padding: 15px 20px 10px 20px;
115
+ margin: 0 auto;
116
+ text-align: right;
117
+ font-family: sans-serif;
118
+ font-weight: normal;
119
+ border: 3px solid #DDD;
120
+ background-color: #468EFF;
121
+ color: #EEE;
122
+ }
123
+
124
+ #version .numbers {
125
+ display: block;
126
+ font-size: 4em;
127
+ line-height: 0.8em;
128
+ letter-spacing: -0.1ex;
129
+ margin-bottom: 15px;
130
+ }
131
+
132
+ #version p {
133
+ text-decoration: none;
134
+ color: #EEE;
135
+ background-color: #468EFF;
136
+ margin: 0;
137
+ padding: 0;
138
+ }
139
+
140
+ #version a {
141
+ text-decoration: none;
142
+ color: #EEE;
143
+ background-color: #468EFF;
144
+ }
145
+
146
+ .clickable {
147
+ cursor: pointer;
148
+ cursor: hand;
149
+ }
@@ -0,0 +1,43 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
3
+ <head>
4
+ <!-- link rel="stylesheet" href="screen.css" type="text/css" media="screen" / -->
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
+ <title>
7
+ <%= title %>
8
+ </title>
9
+ <script src="curvycorners.js" type="text/javascript"></script>
10
+ <style>
11
+ </style>
12
+ <script type="text/javascript">
13
+ window.onload = function() {
14
+ settings = {
15
+ tl: { radius: 10 },
16
+ tr: { radius: 10 },
17
+ bl: { radius: 10 },
18
+ br: { radius: 10 },
19
+ antiAlias: true,
20
+ autoPad: true,
21
+ validTags: ["div"]
22
+ }
23
+ var versionBox = new curvyCorners(settings, document.getElementById("version"));
24
+ versionBox.applyCornersToAll();
25
+ }
26
+ </script>
27
+ </head>
28
+ <body>
29
+ <div id="main">
30
+ <h1><%= title %></h1>
31
+ <div class="sidebar">
32
+ <div id="version" class="clickable" onclick='document.location = "<%= download %>"; return false'>
33
+ <p>Get Version</p>
34
+ <a href="<%= download %>" class="numbers"><%= version %></a>
35
+ </div>
36
+ </div>
37
+ <%= body %>
38
+ <p class="coda">
39
+ <a href="http://www.yes-no-cancel.co.uk/">Martin Kleppmann</a>
40
+ </p>
41
+ </div>
42
+ </body>
43
+ </html>
metadata ADDED
@@ -0,0 +1,180 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: invoicing
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Martin Kleppmann
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-10 00:00:00 +00:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.1.0
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: builder
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ - - "="
35
+ - !ruby/object:Gem::Version
36
+ version: "2.0"
37
+ version:
38
+ - !ruby/object:Gem::Dependency
39
+ name: echoe
40
+ type: :development
41
+ version_requirement:
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ description: Provides tools for applications which need to generate invoices for customers.
49
+ email: rubyforge@eptcomputing.com
50
+ executables: []
51
+
52
+ extensions: []
53
+
54
+ extra_rdoc_files:
55
+ - CHANGELOG
56
+ - lib/invoicing/cached_record.rb
57
+ - lib/invoicing/class_info.rb
58
+ - lib/invoicing/connection_adapter_ext.rb
59
+ - lib/invoicing/countries/uk.rb
60
+ - lib/invoicing/currency_value.rb
61
+ - lib/invoicing/find_subclasses.rb
62
+ - lib/invoicing/ledger_item/render_html.rb
63
+ - lib/invoicing/ledger_item/render_ubl.rb
64
+ - lib/invoicing/ledger_item.rb
65
+ - lib/invoicing/line_item.rb
66
+ - lib/invoicing/price.rb
67
+ - lib/invoicing/tax_rate.rb
68
+ - lib/invoicing/taxable.rb
69
+ - lib/invoicing/time_dependent.rb
70
+ - lib/invoicing/version.rb
71
+ - lib/invoicing.rb
72
+ - LICENSE
73
+ - README
74
+ files:
75
+ - CHANGELOG
76
+ - lib/invoicing/cached_record.rb
77
+ - lib/invoicing/class_info.rb
78
+ - lib/invoicing/connection_adapter_ext.rb
79
+ - lib/invoicing/countries/uk.rb
80
+ - lib/invoicing/currency_value.rb
81
+ - lib/invoicing/find_subclasses.rb
82
+ - lib/invoicing/ledger_item/render_html.rb
83
+ - lib/invoicing/ledger_item/render_ubl.rb
84
+ - lib/invoicing/ledger_item.rb
85
+ - lib/invoicing/line_item.rb
86
+ - lib/invoicing/price.rb
87
+ - lib/invoicing/tax_rate.rb
88
+ - lib/invoicing/taxable.rb
89
+ - lib/invoicing/time_dependent.rb
90
+ - lib/invoicing/version.rb
91
+ - lib/invoicing.rb
92
+ - LICENSE
93
+ - Manifest
94
+ - Rakefile
95
+ - README
96
+ - test/cached_record_test.rb
97
+ - test/class_info_test.rb
98
+ - test/connection_adapter_ext_test.rb
99
+ - test/currency_value_test.rb
100
+ - test/find_subclasses_test.rb
101
+ - test/fixtures/cached_record.sql
102
+ - test/fixtures/class_info.sql
103
+ - test/fixtures/currency_value.sql
104
+ - test/fixtures/find_subclasses.sql
105
+ - test/fixtures/ledger_item.sql
106
+ - test/fixtures/line_item.sql
107
+ - test/fixtures/price.sql
108
+ - test/fixtures/README
109
+ - test/fixtures/tax_rate.sql
110
+ - test/fixtures/taxable.sql
111
+ - test/fixtures/time_dependent.sql
112
+ - test/ledger_item_test.rb
113
+ - test/line_item_test.rb
114
+ - test/models/README
115
+ - test/models/test_subclass_in_another_file.rb
116
+ - test/models/test_subclass_not_in_database.rb
117
+ - test/price_test.rb
118
+ - test/ref-output/creditnote3.html
119
+ - test/ref-output/creditnote3.xml
120
+ - test/ref-output/invoice1.html
121
+ - test/ref-output/invoice1.xml
122
+ - test/ref-output/invoice2.html
123
+ - test/ref-output/invoice2.xml
124
+ - test/ref-output/invoice_null.html
125
+ - test/render_html_test.rb
126
+ - test/render_ubl_test.rb
127
+ - test/setup.rb
128
+ - test/tax_rate_test.rb
129
+ - test/taxable_test.rb
130
+ - test/test_helper.rb
131
+ - test/time_dependent_test.rb
132
+ - website/curvycorners.js
133
+ - website/screen.css
134
+ - website/template.html.erb
135
+ - invoicing.gemspec
136
+ has_rdoc: true
137
+ homepage: http://invoicing.rubyforge.org/
138
+ post_install_message:
139
+ rdoc_options:
140
+ - --line-numbers
141
+ - --inline-source
142
+ - --title
143
+ - Invoicing
144
+ - --main
145
+ - README
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: "0"
153
+ version:
154
+ required_rubygems_version: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: "1.2"
159
+ version:
160
+ requirements: []
161
+
162
+ rubyforge_project: invoicing
163
+ rubygems_version: 1.3.1
164
+ signing_key:
165
+ specification_version: 2
166
+ summary: Ruby invoicing framework
167
+ test_files:
168
+ - test/cached_record_test.rb
169
+ - test/class_info_test.rb
170
+ - test/connection_adapter_ext_test.rb
171
+ - test/currency_value_test.rb
172
+ - test/find_subclasses_test.rb
173
+ - test/ledger_item_test.rb
174
+ - test/line_item_test.rb
175
+ - test/price_test.rb
176
+ - test/render_html_test.rb
177
+ - test/render_ubl_test.rb
178
+ - test/tax_rate_test.rb
179
+ - test/taxable_test.rb
180
+ - test/time_dependent_test.rb