| @@ -0,0 +1,3 @@ | |||
| data/ | |||
| *sqlite3 | |||
| @@ -0,0 +1,111 @@ | |||
| require 'rubygems' | |||
| require 'sinatra' | |||
| require 'sinatra-helpers/haml/partials' | |||
| require 'haml' | |||
| require 'lib/models' | |||
| get '/' do | |||
| @directorates = Directorate.all | |||
| # @results = repository(:default).adapter.query(" | |||
| # SELECT p.name, | |||
| # sum(c.votes_2010) AS votes, | |||
| # p.colour | |||
| # | |||
| # FROM parties p, | |||
| # councilcandidates c | |||
| # | |||
| # WHERE p.id = c.party_id | |||
| # | |||
| # GROUP BY p.name, p.colour | |||
| # | |||
| # ORDER BY votes desc | |||
| # ;") | |||
| # select p.name, count(c.*) AS seats | |||
| # FROM parties p, councilcandidates c | |||
| # GROUP BY p.id | |||
| haml :home | |||
| end | |||
| get '/directorates/:id' do | |||
| @directorate = Directorate.get(params[:id]) | |||
| haml :directorate | |||
| end | |||
| get '/suppliers/:id.csv' do | |||
| @supplier = Supplier.get(params[:id]) | |||
| headers "Content-Disposition" => "attachment;filename=supplier#{@supplier.id}.csv", | |||
| "Content-Type" => "application/octet-stream" | |||
| result = "Date,Trans No,Directorate,Service,Amount ex. VAT\n" | |||
| for payment in @supplier.payments | |||
| result += "#{payment.d.strftime("%d %b %Y")},#{payment.trans_no},\"#{payment.directorate.name}\",#{payment.service.name},#{sprintf("%0.2f", payment.amount)}\n" | |||
| end | |||
| result | |||
| end | |||
| get '/suppliers/:id' do | |||
| @supplier = Supplier.get(params[:id]) | |||
| haml :supplier | |||
| end | |||
| get '/suppliers/?' do | |||
| @suppliers = Supplier.all( :order => ['name'] ) | |||
| haml :suppliers | |||
| end | |||
| get '/services/:id.csv' do | |||
| @service = Service.get(params[:id]) | |||
| headers "Content-Disposition" => "attachment;filename=service#{@service.id}.csv", | |||
| "Content-Type" => "application/octet-stream" | |||
| result = "Date,Trans No,Directorate,Supplier,Amount ex. VAT\n" | |||
| for payment in @service.payments | |||
| result += "#{payment.d.strftime("%d %b %Y")},#{payment.trans_no},\"#{payment.directorate.name}\",#{payment.supplier.name},#{sprintf("%0.2f", payment.amount)}\n" | |||
| end | |||
| result | |||
| end | |||
| get '/services/:id' do | |||
| @service = Service.get(params[:id]) | |||
| haml :service | |||
| end | |||
| get '/services/?' do | |||
| @services = Service.all( :order => ['name'] ) | |||
| haml :services | |||
| end | |||
| get '/wards/:slug/postcode/:postcode/?' do | |||
| @ward = Ward.first(:slug => params[:slug]) | |||
| @postcode = params[:postcode] | |||
| haml :wards | |||
| end | |||
| get '/wards/:slug/?' do | |||
| @ward = Ward.first(:slug => params[:slug]) | |||
| haml :wards | |||
| end | |||
| get '/error' do | |||
| haml :error | |||
| end | |||
| get '/about' do | |||
| haml :about | |||
| end | |||
| not_found do | |||
| haml :not_found | |||
| end | |||
| @@ -0,0 +1,45 @@ | |||
| require 'lib/models' | |||
| require 'csv' | |||
| count = 0 | |||
| CSV::Reader.parse(File.open('data/2009Q4.csv', 'rb')) do |row| | |||
| # 2009Q4 Columns: | |||
| # 0: Directorate | |||
| # 1: Updated | |||
| # 2: TransNo | |||
| # 3: Service | |||
| # 4: Cost Centre | |||
| # 5: Supplier Name | |||
| # 6: Amount excl vat | |||
| # 7: Type | |||
| count += 1 | |||
| if (count > 4) # skip first four lines that don't contain data | |||
| p row | |||
| directorate = Directorate.first_or_create(:name => row[0].strip) | |||
| service = Service.first_or_create(:name => row[3].strip) | |||
| supplier = Supplier.first_or_create(:name => row[5].strip) | |||
| payment = Payment.first_or_create( | |||
| 'trans_no' => row[2], | |||
| 'directorate' => directorate, | |||
| 'service' => service, | |||
| 'supplier' => supplier, | |||
| 'cost_centre' => row[4].strip, | |||
| 'amount' => row[6].strip.gsub(/,/, ''), | |||
| 'd' => row[1], | |||
| 'tyype' => row[7].strip | |||
| ) | |||
| unless payment.save | |||
| puts "ERROR: Failed to save payment" | |||
| payment.errors.each do |e| | |||
| puts e | |||
| end | |||
| end | |||
| end | |||
| end | |||
| @@ -0,0 +1,39 @@ | |||
| require 'lib/models' | |||
| require 'csv' | |||
| count = 0 | |||
| # 2010Q1: 0-Directorate,1-Updated,2-Service,3-Supplier Name,4-Amount excl vat £,5-Type | |||
| CSV::Reader.parse(File.open('data/2010Q1.csv', 'rb')) do |row| | |||
| count += 1 | |||
| if (count > 4) # skip first four lines that don't contain data | |||
| p row | |||
| directorate = Directorate.first_or_create(:name => row[0].strip) | |||
| service = Service.first_or_create(:name => row[2].strip) | |||
| supplier = Supplier.first_or_create(:name => row[3].strip) | |||
| dt = row[1].strip.split('/') | |||
| payment = Payment.first_or_create( | |||
| 'directorate' => directorate, | |||
| 'service' => service, | |||
| 'supplier' => supplier, | |||
| 'amount' => row[4].strip.gsub(/,/, ''), | |||
| 'd' => Date.new(dt[2].to_i, dt[1].to_i, dt[0].to_i), | |||
| 'tyype' => row[5].strip | |||
| ) | |||
| unless payment.save | |||
| puts "ERROR: Failed to save payment" | |||
| payment.errors.each do |e| | |||
| puts e | |||
| end | |||
| end | |||
| end | |||
| end | |||
| @@ -0,0 +1,58 @@ | |||
| require 'rubygems' | |||
| require 'dm-core' | |||
| require 'dm-validations' | |||
| require 'dm-timestamps' | |||
| require 'dm-aggregates' | |||
| class Payment | |||
| include DataMapper::Resource | |||
| property :id, Serial | |||
| property :trans_no, Integer, :required => false # "TransNo" in RBWM CSV files | |||
| property :directorate_id, Integer, :required => true | |||
| property :service_id, Integer, :required => true | |||
| property :supplier_id, Integer, :required => true | |||
| property :cost_centre, String, :required => false | |||
| property :amount, BigDecimal, :precision => 10, :scale => 2, :required => true # ex VAT | |||
| property :d, Date, :required => true # "Updated" in RBWM CSV files | |||
| property :tyype, String, :required => true # Capital or Revenue | |||
| belongs_to :directorate | |||
| belongs_to :service | |||
| belongs_to :supplier | |||
| end | |||
| class Directorate | |||
| include DataMapper::Resource | |||
| property :id, Serial | |||
| property :name, String, :length => 255, :required => true | |||
| has n, :payments, :order => ['d'] | |||
| end | |||
| class Service | |||
| include DataMapper::Resource | |||
| property :id, Serial | |||
| property :name, String, :length => 255, :required => true | |||
| has n, :payments, :order => ['d'] | |||
| end | |||
| class Supplier | |||
| include DataMapper::Resource | |||
| property :id, Serial | |||
| property :name, String, :length => 255, :required => true | |||
| has n, :payments, :order => ['d'] | |||
| # def self.slugify(name) | |||
| # name.gsub(/[^\w\s-]/, '').gsub(/\s+/, '-').downcase | |||
| # end | |||
| end | |||
| DataMapper.setup(:default, ENV['DATABASE_URL'] || "sqlite3://#{Dir.pwd}/db.sqlite3") | |||
| DataMapper.auto_upgrade! | |||
| @@ -0,0 +1,42 @@ | |||
| #breadcrumb { | |||
| font: 11px Arial, Helvetica, sans-serif; | |||
| background-image:url('/breadcrumb/bc_bg.gif'); | |||
| background-repeat:repeat-x; | |||
| height:30px; | |||
| line-height:30px; | |||
| color:#888; | |||
| border:solid 1px #cacaca; | |||
| width:100%; | |||
| overflow:hidden; | |||
| margin:0px; | |||
| padding:0px; | |||
| } | |||
| #breadcrumb li { | |||
| list-style-type:none; | |||
| padding-left:10px; | |||
| display:inline-block; | |||
| float:left; | |||
| } | |||
| #breadcrumb a { | |||
| display:inline-block; | |||
| background-image:url('/breadcrumb/bc_separator.gif'); | |||
| background-repeat:no-repeat; | |||
| background-position:right; | |||
| padding-right: 15px; | |||
| text-decoration: none; | |||
| color:#333333; | |||
| outline:none; | |||
| } | |||
| .home { | |||
| border:none; | |||
| margin: 7px 0px; | |||
| background-image:url('/breadcrumb/bc_separator.gif'); | |||
| } | |||
| #breadcrumb a:hover { | |||
| color:#35acc5; | |||
| } | |||
| @@ -0,0 +1,338 @@ | |||
| /* | |||
| Variable Grid System. | |||
| Learn more ~ http://www.spry-soft.com/grids/ | |||
| Based on 960 Grid System - http://960.gs/ | |||
| Licensed under GPL and MIT. | |||
| */ | |||
| /* Containers | |||
| ----------------------------------------------------------------------------------------------------*/ | |||
| .container_12 { | |||
| margin-left: auto; | |||
| margin-right: auto; | |||
| width: 960px; | |||
| } | |||
| /* Grid >> Global | |||
| ----------------------------------------------------------------------------------------------------*/ | |||
| .grid_1, | |||
| .grid_2, | |||
| .grid_3, | |||
| .grid_4, | |||
| .grid_5, | |||
| .grid_6, | |||
| .grid_7, | |||
| .grid_8, | |||
| .grid_9, | |||
| .grid_10, | |||
| .grid_11, | |||
| .grid_12 { | |||
| display:inline; | |||
| float: left; | |||
| position: relative; | |||
| margin-left: 15px; | |||
| margin-right: 15px; | |||
| } | |||
| /* Grid >> Children (Alpha ~ First, Omega ~ Last) | |||
| ----------------------------------------------------------------------------------------------------*/ | |||
| .alpha { | |||
| margin-left: 0; | |||
| } | |||
| .omega { | |||
| margin-right: 0; | |||
| } | |||
| /* Grid >> 12 Columns | |||
| ----------------------------------------------------------------------------------------------------*/ | |||
| .container_12 .grid_1 { | |||
| width:50px; | |||
| } | |||
| .container_12 .grid_2 { | |||
| width:130px; | |||
| } | |||
| .container_12 .grid_3 { | |||
| width:210px; | |||
| } | |||
| .container_12 .grid_4 { | |||
| width:290px; | |||
| } | |||
| .container_12 .grid_5 { | |||
| width:370px; | |||
| } | |||
| .container_12 .grid_6 { | |||
| width:450px; | |||
| } | |||
| .container_12 .grid_7 { | |||
| width:530px; | |||
| } | |||
| .container_12 .grid_8 { | |||
| width:610px; | |||
| } | |||
| .container_12 .grid_9 { | |||
| width:690px; | |||
| } | |||
| .container_12 .grid_10 { | |||
| width:770px; | |||
| } | |||
| .container_12 .grid_11 { | |||
| width:850px; | |||
| } | |||
| .container_12 .grid_12 { | |||
| width:930px; | |||
| } | |||
| /* Prefix Extra Space >> 12 Columns | |||
| ----------------------------------------------------------------------------------------------------*/ | |||
| .container_12 .prefix_1 { | |||
| padding-left:80px; | |||
| } | |||
| .container_12 .prefix_2 { | |||
| padding-left:160px; | |||
| } | |||
| .container_12 .prefix_3 { | |||
| padding-left:240px; | |||
| } | |||
| .container_12 .prefix_4 { | |||
| padding-left:320px; | |||
| } | |||
| .container_12 .prefix_5 { | |||
| padding-left:400px; | |||
| } | |||
| .container_12 .prefix_6 { | |||
| padding-left:480px; | |||
| } | |||
| .container_12 .prefix_7 { | |||
| padding-left:560px; | |||
| } | |||
| .container_12 .prefix_8 { | |||
| padding-left:640px; | |||
| } | |||
| .container_12 .prefix_9 { | |||
| padding-left:720px; | |||
| } | |||
| .container_12 .prefix_10 { | |||
| padding-left:800px; | |||
| } | |||
| .container_12 .prefix_11 { | |||
| padding-left:880px; | |||
| } | |||
| /* Suffix Extra Space >> 12 Columns | |||
| ----------------------------------------------------------------------------------------------------*/ | |||
| .container_12 .suffix_1 { | |||
| padding-right:80px; | |||
| } | |||
| .container_12 .suffix_2 { | |||
| padding-right:160px; | |||
| } | |||
| .container_12 .suffix_3 { | |||
| padding-right:240px; | |||
| } | |||
| .container_12 .suffix_4 { | |||
| padding-right:320px; | |||
| } | |||
| .container_12 .suffix_5 { | |||
| padding-right:400px; | |||
| } | |||
| .container_12 .suffix_6 { | |||
| padding-right:480px; | |||
| } | |||
| .container_12 .suffix_7 { | |||
| padding-right:560px; | |||
| } | |||
| .container_12 .suffix_8 { | |||
| padding-right:640px; | |||
| } | |||
| .container_12 .suffix_9 { | |||
| padding-right:720px; | |||
| } | |||
| .container_12 .suffix_10 { | |||
| padding-right:800px; | |||
| } | |||
| .container_12 .suffix_11 { | |||
| padding-right:880px; | |||
| } | |||
| /* Push Space >> 12 Columns | |||
| ----------------------------------------------------------------------------------------------------*/ | |||
| .container_12 .push_1 { | |||
| left:80px; | |||
| } | |||
| .container_12 .push_2 { | |||
| left:160px; | |||
| } | |||
| .container_12 .push_3 { | |||
| left:240px; | |||
| } | |||
| .container_12 .push_4 { | |||
| left:320px; | |||
| } | |||
| .container_12 .push_5 { | |||
| left:400px; | |||
| } | |||
| .container_12 .push_6 { | |||
| left:480px; | |||
| } | |||
| .container_12 .push_7 { | |||
| left:560px; | |||
| } | |||
| .container_12 .push_8 { | |||
| left:640px; | |||
| } | |||
| .container_12 .push_9 { | |||
| left:720px; | |||
| } | |||
| .container_12 .push_10 { | |||
| left:800px; | |||
| } | |||
| .container_12 .push_11 { | |||
| left:880px; | |||
| } | |||
| /* Pull Space >> 12 Columns | |||
| ----------------------------------------------------------------------------------------------------*/ | |||
| .container_12 .pull_1 { | |||
| left:-80px; | |||
| } | |||
| .container_12 .pull_2 { | |||
| left:-160px; | |||
| } | |||
| .container_12 .pull_3 { | |||
| left:-240px; | |||
| } | |||
| .container_12 .pull_4 { | |||
| left:-320px; | |||
| } | |||
| .container_12 .pull_5 { | |||
| left:-400px; | |||
| } | |||
| .container_12 .pull_6 { | |||
| left:-480px; | |||
| } | |||
| .container_12 .pull_7 { | |||
| left:-560px; | |||
| } | |||
| .container_12 .pull_8 { | |||
| left:-640px; | |||
| } | |||
| .container_12 .pull_9 { | |||
| left:-720px; | |||
| } | |||
| .container_12 .pull_10 { | |||
| left:-800px; | |||
| } | |||
| .container_12 .pull_11 { | |||
| left:-880px; | |||
| } | |||
| /* Clear Floated Elements | |||
| ----------------------------------------------------------------------------------------------------*/ | |||
| /* http://sonspring.com/journal/clearing-floats */ | |||
| .clear { | |||
| clear: both; | |||
| display: block; | |||
| overflow: hidden; | |||
| visibility: hidden; | |||
| width: 0; | |||
| height: 0; | |||
| } | |||
| /* http://perishablepress.com/press/2008/02/05/lessons-learned-concerning-the-clearfix-css-hack */ | |||
| .clearfix:after { | |||
| clear: both; | |||
| content: ' '; | |||
| display: block; | |||
| font-size: 0; | |||
| line-height: 0; | |||
| visibility: hidden; | |||
| width: 0; | |||
| height: 0; | |||
| } | |||
| .clearfix { | |||
| display: inline-block; | |||
| } | |||
| * html .clearfix { | |||
| height: 1%; | |||
| } | |||
| .clearfix { | |||
| display: block; | |||
| } | |||
| @@ -0,0 +1,9 @@ | |||
| .noprint, #footer, #breadcrumb | |||
| { | |||
| display: none; | |||
| } | |||
| body | |||
| { | |||
| margin: 0 auto; | |||
| } | |||
| @@ -0,0 +1,121 @@ | |||
| body | |||
| { | |||
| background-color: #fff; | |||
| color: #555; | |||
| font-family: Helvetica, Arial, sans-serif; | |||
| font-size: 100%; | |||
| line-height: 1.5em; | |||
| } | |||
| p | |||
| { | |||
| font-size: 110%; | |||
| } | |||
| input | |||
| { | |||
| font-size: 130%; | |||
| background-color: #fff; | |||
| } | |||
| #main | |||
| { | |||
| margin: 30px 0; | |||
| } | |||
| #footer | |||
| { | |||
| font-size: 100%; | |||
| background-color: #fff; | |||
| text-align: left; | |||
| margin: 40px 0 40px 0; | |||
| } | |||
| a | |||
| { | |||
| background-color: #dce9b0; | |||
| padding: 1px 4px; | |||
| color: #111; | |||
| text-decoration: none; | |||
| } | |||
| a:visited | |||
| { | |||
| background-color: #eee; | |||
| padding: 1px 4px; | |||
| color: #111; | |||
| text-decoration: none; | |||
| } | |||
| a:hover | |||
| { | |||
| background-color: #4f4f4f; | |||
| color: #fff; | |||
| } | |||
| h1 | |||
| { | |||
| margin-top: 20px; | |||
| line-height: 1.4em; | |||
| font-weight: bold; | |||
| color: #86a11d; | |||
| } | |||
| h2 | |||
| { | |||
| margin-top: 20px; | |||
| line-height: 1.5em; | |||
| font-weight: bold; | |||
| color: #86a11d; | |||
| } | |||
| form | |||
| { | |||
| font-size: 150%; | |||
| } | |||
| .highlight | |||
| { | |||
| background-color: #fff7c0; | |||
| padding: 5px; | |||
| } | |||
| strong | |||
| { | |||
| color: #000; | |||
| } | |||
| table | |||
| { | |||
| border-collapse: collapse; | |||
| } | |||
| td, th | |||
| { | |||
| padding: 6px; | |||
| } | |||
| th | |||
| { | |||
| text-align: left; | |||
| } | |||
| tr | |||
| { | |||
| border-bottom: 1px solid #eee; | |||
| } | |||
| .right | |||
| { | |||
| text-align: right; | |||
| } | |||
| .noborder | |||
| { | |||
| border: 0; | |||
| } | |||
| @@ -0,0 +1,55 @@ | |||
| .grid_9 | |||
| %h1= @page_title = "About this website" | |||
| %blockquote | |||
| The swift and simple changes we are calling for today [to encourage councils to publish spending data] will unleash an army of armchair auditors and quite rightly make those charged with doling out the pennies stop and think twice about whether they are getting value for money. | |||
| %p.right — Eric Pickles, Communities & Local Government Secretary, 5 June 2010 | |||
| <!-- http://news.bbc.co.uk/1/hi/politics/10241522.stm --> | |||
| %p.vcard | |||
| This website was designed and written by | |||
| %a.fn.url{ :href => 'http://adrianshort.co.uk' } Adrian Short | |||
| \. | |||
| You can contact me by email at | |||
| %a.email{ :href => "mailto:adrian.short@gmail.com" } adrian.short@gmail.com | |||
| and | |||
| %a.url{ :href => "http://twitter.com/adrianshort" } follow me on Twitter | |||
| \. | |||
| %p.highlight | |||
| This site is made with | |||
| %a{ :href => 'http://www.rbwm.gov.uk/web/finance_payments_to_suppliers.htm' } | |||
| the Royal Borough of Windsor and Maidenhead's spending data | |||
| and is entirely indepdendent of the council. The council did not commission or pay for this website. | |||
| %p Every page on this website prints beautifully. | |||
| %p | |||
| This site is written in | |||
| %a{ :href => "http://www.ruby-lang.org/en/" }Ruby | |||
| \ using the | |||
| %a{ :href => "http://www.sinatrarb.com/" }Sinatra framework. | |||
| %p | |||
| The code for this website is | |||
| %a{ :href => "http://github.com/adrianshort/Sutton-Elections" }open source and managed on Github. | |||
| It is hosted by | |||
| %a{ :href => "http://heroku.com/" }Heroku. | |||
| %p | |||
| The page templates use | |||
| %a{ :href => "http://haml-lang.com/" }Haml | |||
| and SprySoft's | |||
| %a{ :href => "http://www.spry-soft.com/grids/" }Variable Grid System | |||
| \. The database is | |||
| %a{ :href => "http://www.sqlite.org/" }SQLite | |||
| for development and | |||
| %a{ :href => "http://www.postgresql.org/" }PostgreSQL | |||
| for production, abstracted through | |||
| %a{ :href => "http://datamapper.org/" }DataMapper. | |||
| %p | |||
| Source control and deployment is done with | |||
| %a{ :href => "http://git-scm.com/" }Git. | |||
| @@ -0,0 +1,30 @@ | |||
| .grid_12 | |||
| %h2= @page_title = @directorate.name + " Directorate" | |||
| %ul#breadcrumb | |||
| %li.home | |||
| %a{ :href => '/'} Home | |||
| %li | |||
| %a{ :href => '/directorates' } Directorates | |||
| %li | |||
| = @directorate.name | |||
| %table | |||
| %tr | |||
| %th Date | |||
| %th Service | |||
| %th Supplier | |||
| %th £ | |||
| - for payment in @directorate.payments | |||
| %tr | |||
| %td= payment.d.strftime("%d %b %Y") | |||
| %td | |||
| %a{ :href => '/services/' + payment.service.id.to_s } | |||
| = payment.service.name | |||
| %td | |||
| %a{ :href => '/suppliers/' + payment.supplier.id.to_s } | |||
| = payment.supplier.name | |||
| %td.right= sprintf("%0d", payment.amount) | |||
| @@ -0,0 +1,5 @@ | |||
| .grid_12 | |||
| %h1 Invalid postcode | |||
| %p | |||
| %a{ :href => "/" }Please go back and try again | |||
| @@ -0,0 +1,11 @@ | |||
| .grid_12 | |||
| %ul#breadcrumb | |||
| %li.home | |||
| %h2 Directorates | |||
| - for directorate in @directorates | |||
| %p | |||
| %a{ :href=> "/directorates/#{directorate.id}" } | |||
| = directorate.name | |||
| @@ -0,0 +1,26 @@ | |||
| !!! XML | |||
| !!! | |||
| %html | |||
| %head | |||
| %title= @page_title ? @page_title + " - Armchair Auditor" : "Armchair Auditor" | |||
| %link{ :rel => 'stylesheet', :type => 'text/css', :href => '/style.css' } | |||
| %link{ :rel => 'stylesheet', :type => 'text/css', :href => '/breadcrumb/breadcrumb.css' } | |||
| %link{ :rel => 'stylesheet', :type => 'text/css', :href => '/print.css', :media => 'print' } | |||
| %link{ :rel => 'stylesheet', :type => 'text/css', :href => '/grid.css' } | |||
| %body | |||
| .container_12 | |||
| .grid_12 | |||
| %h1 Royal Borough of Windsor & Maidenhead Armchair Auditor | |||
| = yield | |||
| .clear | |||
| #footer | |||
| .grid_12 | |||
| %p | |||
| %a{ :href => '/' } Home | |||
| %p | |||
| %a{ :href => '/services' } Services | |||
| %p | |||
| %a{ :href => '/suppliers' } Suppliers | |||
| %p | |||
| %a{ :href => '/about' } About this website | |||
| @@ -0,0 +1,7 @@ | |||
| .grid_9 | |||
| %h1 Not Found | |||
| %p Oops, we can't find that page. | |||
| %p | |||
| %a{ :href => '/' }Go back to the home page | |||
| @@ -0,0 +1,33 @@ | |||
| .grid_12 | |||
| %h2= @page_title = @service.name + " (Service)" | |||
| %ul#breadcrumb | |||
| %li.home | |||
| %a{ :href => '/'} Home | |||
| %li | |||
| %a{ :href => '/services' } Services | |||
| %li | |||
| = @service.name | |||
| %p | |||
| %a{ :href => "/services/#{@service.id}.csv" } | |||
| Download data as CSV | |||
| %table | |||
| %tr | |||
| %th Date | |||
| %th Directorate | |||
| %th Supplier | |||
| %th £ | |||
| - for payment in @service.payments | |||
| %tr | |||
| %td= payment.d.strftime("%d %b %Y") | |||
| %td | |||
| %a{ :href => '/directorates/' + payment.directorate.id.to_s } | |||
| = payment.directorate.name | |||
| %td | |||
| %a{ :href => '/suppliers/' + payment.supplier.id.to_s } | |||
| = payment.supplier.name | |||
| %td.right= sprintf("%0d", payment.amount) | |||
| @@ -0,0 +1,13 @@ | |||
| .grid_12 | |||
| %h2 Services | |||
| %ul#breadcrumb | |||
| %li.home | |||
| %a{ :href => '/'} Home | |||
| %li | |||
| Services | |||
| - for service in @services | |||
| %p | |||
| %a{ :href=> "/services/#{service.id}" } | |||
| = service.name | |||
| @@ -0,0 +1,34 @@ | |||
| .grid_12 | |||
| %h2= @page_title = @supplier.name + " (Supplier)" | |||
| %ul#breadcrumb | |||
| %li.home | |||
| %a{ :href => '/'} Home | |||
| %li | |||
| %a{ :href => '/suppliers' } Suppliers | |||
| %li | |||
| = @supplier.name | |||
| %p.noprint | |||
| %a{ :href => "/suppliers/#{@supplier.id}.csv" } | |||
| Download data as CSV | |||
| %table | |||
| %tr | |||
| %th Date | |||
| %th Directorate | |||
| %th Service | |||
| %th £ | |||
| - for payment in @supplier.payments | |||
| %tr | |||
| %td= payment.d.strftime("%d %b %Y") | |||
| %td | |||
| %a{ :href => '/directorates/' + payment.directorate.id.to_s } | |||
| = payment.directorate.name | |||
| %td | |||
| %a{ :href => '/services/' + payment.service.id.to_s } | |||
| = payment.service.name | |||
| %td.right= sprintf("%0d", payment.amount) | |||
| @@ -0,0 +1,13 @@ | |||
| .grid_12 | |||
| %h2 Suppliers | |||
| %ul#breadcrumb | |||
| %li.home | |||
| %a{ :href => '/'} Home | |||
| %li | |||
| Suppliers | |||
| - for supplier in @suppliers | |||
| %p | |||
| %a{ :href=> "/suppliers/#{supplier.id}" } | |||
| = supplier.name | |||