invoicing 0.1.0

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.
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