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