artisan-core 0.0.1
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.
- data/lib/artisan/activity/activity_interactor.rb +18 -0
- data/lib/artisan/activity/activity_presenter.rb +35 -0
- data/lib/artisan/activity/formatters/diff_changes.rb +41 -0
- data/lib/artisan/activity/formatters/name.rb +22 -0
- data/lib/artisan/activity/formatters/source.rb +16 -0
- data/lib/artisan/activity/formatters/temporal.rb +20 -0
- data/lib/artisan/activity/iteration_auditor.rb +44 -0
- data/lib/artisan/activity/project_auditor.rb +28 -0
- data/lib/artisan/activity/story_auditor.rb +42 -0
- data/lib/artisan/callbacks.rb +27 -0
- data/lib/artisan/crud_strategy.rb +23 -0
- data/lib/artisan/event_mailer.rb +22 -0
- data/lib/artisan/inviter.rb +36 -0
- data/lib/artisan/iterations/iteration_point_calculator.rb +28 -0
- data/lib/artisan/iterations/iteration_presenter.rb +20 -0
- data/lib/artisan/iterations/iteration_workflow_interactor.rb +60 -0
- data/lib/artisan/iterations/iteration_workflow_presenter.rb +11 -0
- data/lib/artisan/iterations/iterations.rb +47 -0
- data/lib/artisan/iterations/iterations_interactor.rb +48 -0
- data/lib/artisan/iterations/move_to_backlog.rb +28 -0
- data/lib/artisan/iterations/story_tags.rb +15 -0
- data/lib/artisan/member.rb +52 -0
- data/lib/artisan/no_op_callbacks.rb +6 -0
- data/lib/artisan/projects/api_key_generator.rb +26 -0
- data/lib/artisan/projects/archive_interactor.rb +29 -0
- data/lib/artisan/projects/completed_stories_presenter.rb +20 -0
- data/lib/artisan/projects/iteration_numberer.rb +15 -0
- data/lib/artisan/projects/project_creator.rb +51 -0
- data/lib/artisan/projects/projects_interactor.rb +58 -0
- data/lib/artisan/projects/projects_presenter.rb +46 -0
- data/lib/artisan/projects/story_point_summer.rb +16 -0
- data/lib/artisan/reports/average_stat_per_iteration_data.rb +55 -0
- data/lib/artisan/reports/burn_up_chart.rb +46 -0
- data/lib/artisan/reports/high_charts_data_retriever.rb +77 -0
- data/lib/artisan/reports/high_charts_interactor.rb +31 -0
- data/lib/artisan/reports/percentage_of_commitments_met_data.rb +47 -0
- data/lib/artisan/reports/signoff/pdf.rb +161 -0
- data/lib/artisan/reports/signoff/report.rb +120 -0
- data/lib/artisan/reports/velocity_report.rb +43 -0
- data/lib/artisan/repository.rb +51 -0
- data/lib/artisan/stories/pert_calculator.rb +62 -0
- data/lib/artisan/stories/stories_interactor.rb +78 -0
- data/lib/artisan/stories/story_collection.rb +66 -0
- data/lib/artisan/stories/story_exporter.rb +45 -0
- data/lib/artisan/stories/story_numberer.rb +15 -0
- data/lib/artisan/stories/story_presenter.rb +23 -0
- data/lib/artisan/stories/story_sorter.rb +37 -0
- data/lib/artisan/story_board.rb +45 -0
- data/lib/artisan/story_column_changer.rb +71 -0
- data/lib/artisan/story_exporter.rb +14 -0
- data/lib/artisan/team.rb +50 -0
- data/spec/crud_strategy_spec.rb +100 -0
- data/spec/event_mailer_spec.rb +86 -0
- data/spec/inviter_spec.rb +58 -0
- data/spec/member_spec.rb +58 -0
- data/spec/repository_spec.rb +32 -0
- data/spec/story_board_spec.rb +36 -0
- data/spec/story_collection_spec.rb +61 -0
- data/spec/story_column_changer_spec.rb +222 -0
- data/spec/story_exporter_spec.rb +25 -0
- data/spec/story_sorter_spec.rb +67 -0
- data/spec/team_spec.rb +107 -0
- metadata +128 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'artisan/repository'
|
2
|
+
require 'artisan/stories/story_collection'
|
3
|
+
|
4
|
+
module Artisan
|
5
|
+
module Projects
|
6
|
+
class ProjectsPresenter
|
7
|
+
|
8
|
+
def initialize(user)
|
9
|
+
@user = user
|
10
|
+
end
|
11
|
+
|
12
|
+
#TODO - PWP - optimize this method to use sql to create the returns rather than ruby
|
13
|
+
def archived
|
14
|
+
read_attributes_to_hash(@user.projects.archived)
|
15
|
+
end
|
16
|
+
|
17
|
+
#TODO - PWP - optimize this method to use sql to create the returns rather than ruby
|
18
|
+
def current
|
19
|
+
read_attributes_to_hash(@user.projects.unarchived)
|
20
|
+
end
|
21
|
+
|
22
|
+
def active_stories_by_project
|
23
|
+
active_stories.group_by(&:project)
|
24
|
+
end
|
25
|
+
|
26
|
+
def active_points
|
27
|
+
Stories::StoryCollection.new(active_stories).estimated_points
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
#TODO - PWP - optimize this method to use sql to create the returns rather than ruby
|
33
|
+
def active_stories
|
34
|
+
Repository.user.active_stories_for(@user).reject { |story| story.project.archived? }
|
35
|
+
end
|
36
|
+
|
37
|
+
def read_attributes_to_hash(scoped_projects)
|
38
|
+
projects = []
|
39
|
+
scoped_projects.each do |project|
|
40
|
+
projects << {:updated_at => project.updated_at, :name => project.name, :id => project.id}
|
41
|
+
end
|
42
|
+
return projects
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "artisan/stories/pert_calculator"
|
2
|
+
module Artisan
|
3
|
+
module Projects
|
4
|
+
class StoryPointSummer
|
5
|
+
|
6
|
+
def initialize(stories)
|
7
|
+
@stories = stories
|
8
|
+
end
|
9
|
+
|
10
|
+
def sum
|
11
|
+
total = @stories.inject(0){ |total, story| total + story.estimate }
|
12
|
+
return total.round(2)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "artisan/iterations/iterations"
|
2
|
+
|
3
|
+
module Artisan
|
4
|
+
module Reports
|
5
|
+
class AverageStatPerIterationData
|
6
|
+
def initialize(project)
|
7
|
+
@project = project
|
8
|
+
end
|
9
|
+
|
10
|
+
def average_of(stat)
|
11
|
+
average(stat)
|
12
|
+
end
|
13
|
+
|
14
|
+
def average_standard_deviation
|
15
|
+
average(:standard_deviation)
|
16
|
+
end
|
17
|
+
|
18
|
+
def average_story_size
|
19
|
+
average(:estimate)
|
20
|
+
end
|
21
|
+
|
22
|
+
def current_iteration?(iteration)
|
23
|
+
Iterations::Iterations.new(@project).current == iteration
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def average(stat_type)
|
29
|
+
@project.iterations.inject([]) do |average_story_size, iteration|
|
30
|
+
average_story_size << accumulate_average_standard_deviation_for(iteration, stat_type).round(2) unless current_iteration?(iteration)
|
31
|
+
average_story_size
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
NONE = 0
|
36
|
+
|
37
|
+
def accumulate_average_standard_deviation_for(iteration, stat_type)
|
38
|
+
if number_of_stories_in(iteration) == NONE
|
39
|
+
NONE
|
40
|
+
else
|
41
|
+
total_standard_deviation_in(iteration, stat_type) / number_of_stories_in(iteration)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def total_standard_deviation_in(iteration, stat_type)
|
46
|
+
iteration.stories.inject(0.0) {| sum, story| sum + story.send(stat_type)}
|
47
|
+
end
|
48
|
+
|
49
|
+
def number_of_stories_in(iteration)
|
50
|
+
iteration.stories.count
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Artisan
|
2
|
+
module Reports
|
3
|
+
|
4
|
+
class BurnUpChart
|
5
|
+
attr_accessor :project
|
6
|
+
def initialize(project)
|
7
|
+
@project = project
|
8
|
+
end
|
9
|
+
|
10
|
+
def project_size date
|
11
|
+
sum_of_stories_by project_query(date)
|
12
|
+
end
|
13
|
+
|
14
|
+
def completed_size date
|
15
|
+
sum_of_stories_by completed_query(date)
|
16
|
+
end
|
17
|
+
|
18
|
+
def project_data
|
19
|
+
accumulate_by(:project_size)
|
20
|
+
end
|
21
|
+
|
22
|
+
def completed_data
|
23
|
+
accumulate_by(:completed_size)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def accumulate_by(method)
|
29
|
+
Iterations::Iterations.new(@project).by_start_date.inject([]) {|acc, iteration| acc << send(method, iteration.start_date)}
|
30
|
+
end
|
31
|
+
|
32
|
+
def project_query(date)
|
33
|
+
["created_at <= ?", date]
|
34
|
+
end
|
35
|
+
|
36
|
+
def completed_query(date)
|
37
|
+
["created_at <= ? AND complete = ? ", date, true]
|
38
|
+
end
|
39
|
+
|
40
|
+
def sum_of_stories_by conditions
|
41
|
+
stories = @project.stories.find(:all, :conditions => conditions)
|
42
|
+
return stories.inject(0) {|acc, story| acc + story.estimate.to_f}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Artisan
|
2
|
+
module Reports
|
3
|
+
module HighChartsDataRetriever
|
4
|
+
def self.build_burn_up_chart(project)
|
5
|
+
chart_data = Artisan::Reports::BurnUpChart.new(project)
|
6
|
+
|
7
|
+
LazyHighCharts::HighChart.new do |f|
|
8
|
+
f.chart(:defaultSeriesType => 'line', :backgroundColor => nil, :margin => [0,0,0,0])
|
9
|
+
f.yAxis(:gridLineWidth => nil, :labels => 'none')
|
10
|
+
f.xAxis(:gridLineWidth => nil, :labels => false, :lineColor => 'transparent', :tickLength => nil)
|
11
|
+
f.tooltip(:shadow => false, :backgroundColor => 'rgba(0,0,0,0.7)', :borderWidth => 0, :style => { :color => '#ffffff', :padding => [7,7,7,7], :fontSize => 13 }, :crosshairs => { :color => '#999', :dashStyle => 'solid'})
|
12
|
+
f.title(:text => nil)
|
13
|
+
f.options[:legend][:enabled] = false
|
14
|
+
f.plotOptions(:line => { :lineWidth=> 1, :shadow => false, :marker => { :symbol => 'circle', :radius => 2, :states => { :hover => { :enabled => true, :fillColor => '#000000'} } } })
|
15
|
+
|
16
|
+
f.series(:data => chart_data.project_data.slice(0, chart_data.project_data.length-1), :color => '#b8be43')
|
17
|
+
f.series(:data => chart_data.completed_data.slice(0, chart_data.project_data.length-1), :color => '#800000')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.build_average_story_size_per_iteration_chart(project)
|
22
|
+
return build_iteration_chart(project, :estimate, '#2B65EC')
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.build_average_standard_deviation_per_iteration_chart(project)
|
26
|
+
return build_iteration_chart(project, :standard_deviation, '#F87217')
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.build_iteration_chart(project, stat, color)
|
30
|
+
chart_data = Artisan::Reports::AverageStatPerIterationData.new(project)
|
31
|
+
|
32
|
+
return LazyHighCharts::HighChart.new do |f|
|
33
|
+
f.chart(:defaultSeriesType => 'line', :backgroundColor => nil, :margin => [0,0,0,0])
|
34
|
+
f.yAxis(:gridLineWidth => nil, :labels => 'none')
|
35
|
+
f.xAxis(:gridLineWidth => nil, :labels => false, :lineColor => 'transparent', :tickLength => nil)
|
36
|
+
f.tooltip(:shadow => false, :backgroundColor => 'rgba(0,0,0,0.7)', :borderWidth => 0, :style => { :color => '#ffffff', :padding => [7,7,7,7], :fontSize => 13 }, :crosshairs => { :color => '#999', :dashStyle => 'solid'})
|
37
|
+
f.title(:text => nil)
|
38
|
+
f.options[:legend][:enabled] = false
|
39
|
+
f.plotOptions(:line => { :lineWidth=> 1, :shadow => false, :marker => { :symbol => 'circle', :radius => 2, :states => { :hover => { :enabled => true, :fillColor => '#000000'} } } })
|
40
|
+
|
41
|
+
f.series(:data => chart_data.average_of(stat), :color => color)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.build_percentage_of_commitments_met_chart(project)
|
46
|
+
chart_data = Artisan::Reports::PercentageOfCommitmentsMetData.new(project)
|
47
|
+
|
48
|
+
LazyHighCharts::HighChart.new do |f|
|
49
|
+
f.options[:chart][:backgroundColor] = 'transparent'
|
50
|
+
f.options[:chart][:defaultSeriesType] = 'pie'
|
51
|
+
f.series(:data=>[{y: go_no_higher_than_100(chart_data.percentage_of_commitments_met), color: 'green'}, {y: go_no_lower_than_0(chart_data.percentage_of_commitments_not_met), color: '#CCC'}], :innerSize => '65%')
|
52
|
+
f.tooltip(:enabled => false)
|
53
|
+
f.title(:text => '')
|
54
|
+
f.plotOptions(:series => {:stacking => true, :shadow => false, :dataLabels => { :enabled => false }})
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.percentage_of_commitments_met(project)
|
59
|
+
chart_data = Artisan::Reports::PercentageOfCommitmentsMetData.new(project)
|
60
|
+
chart_data.percentage_of_commitments_met.to_i
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.go_no_higher_than_100(number)
|
64
|
+
return 0 if number.nil?
|
65
|
+
number > 100 ? 100 : number
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.go_no_lower_than_0(number)
|
69
|
+
return 0 if number.nil?
|
70
|
+
number < 0 ? 0 : number
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Artisan
|
2
|
+
module Reports
|
3
|
+
class HighChartsInteractor
|
4
|
+
attr_reader :project
|
5
|
+
|
6
|
+
def initialize(project)
|
7
|
+
@project = project
|
8
|
+
end
|
9
|
+
|
10
|
+
def burn_up_chart
|
11
|
+
Artisan::Reports::HighChartsDataRetriever.build_burn_up_chart(@project)
|
12
|
+
end
|
13
|
+
|
14
|
+
def average_story_size_per_iteration_chart
|
15
|
+
Artisan::Reports::HighChartsDataRetriever.build_average_story_size_per_iteration_chart(@project)
|
16
|
+
end
|
17
|
+
|
18
|
+
def average_standard_deviation_per_iteration_chart
|
19
|
+
Artisan::Reports::HighChartsDataRetriever.build_average_standard_deviation_per_iteration_chart(@project)
|
20
|
+
end
|
21
|
+
|
22
|
+
def percentage_of_commitments_met_chart
|
23
|
+
Artisan::Reports::HighChartsDataRetriever.build_percentage_of_commitments_met_chart(@project)
|
24
|
+
end
|
25
|
+
|
26
|
+
def percentage_of_commitments_met
|
27
|
+
Artisan::Reports::HighChartsDataRetriever.percentage_of_commitments_met(@project)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "artisan/iterations/iterations"
|
2
|
+
|
3
|
+
module Artisan
|
4
|
+
module Reports
|
5
|
+
class PercentageOfCommitmentsMetData
|
6
|
+
def initialize(project)
|
7
|
+
@project = project
|
8
|
+
end
|
9
|
+
|
10
|
+
def percentages_of_commitments_met
|
11
|
+
@project.iterations.reverse.inject([]) do |percentages_of_commitments_met, iteration|
|
12
|
+
percentages_of_commitments_met << accumulate_percentage_of_commitments_met_for(iteration) unless current_iteration?(iteration)
|
13
|
+
percentages_of_commitments_met
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def percentage_of_commitments_met
|
18
|
+
unless percentages_of_commitments_met.compact.count == 0
|
19
|
+
((percentages_of_commitments_met.compact.inject(0, :+) / percentages_of_commitments_met.compact.count) * 100).round
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def percentage_of_commitments_not_met
|
24
|
+
100 - percentage_of_commitments_met unless percentage_of_commitments_met.nil?
|
25
|
+
end
|
26
|
+
|
27
|
+
def current_iteration?(iteration)
|
28
|
+
Iterations::Iterations.new(@project.id).current == iteration
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def accumulate_percentage_of_commitments_met_for(iteration)
|
34
|
+
if iteration.committed_points == 0 || iteration.committed_points.nil?
|
35
|
+
nil
|
36
|
+
else
|
37
|
+
total_billed_points_for(iteration) / iteration.committed_points
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def total_billed_points_for(iteration)
|
42
|
+
stories = iteration.stories.select { |story| story.complete? && !story.nonbillable? && story.estimate }
|
43
|
+
stories.inject(0.0) {|sum, story| sum + story.estimate}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'prawn'
|
2
|
+
require 'reports_helper'
|
3
|
+
|
4
|
+
module Signoff
|
5
|
+
class Pdf
|
6
|
+
def initialize(report)
|
7
|
+
@report = report
|
8
|
+
end
|
9
|
+
|
10
|
+
def render
|
11
|
+
to_document.render
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_document
|
15
|
+
@document = Prawn::Document.new
|
16
|
+
fonts
|
17
|
+
header
|
18
|
+
project_title
|
19
|
+
iteration_information
|
20
|
+
tables
|
21
|
+
committed_total
|
22
|
+
signature_box
|
23
|
+
@document
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def fonts
|
29
|
+
types_dir = Rails.root.join('public', 'types')
|
30
|
+
|
31
|
+
@document.font_families.update("ArvoRegular" => {
|
32
|
+
:normal => types_dir.join("Arvo-Regular-webfont.ttf").to_s,
|
33
|
+
:bold => types_dir.join("Arvo-Bold.ttf").to_s
|
34
|
+
})
|
35
|
+
@document.font_families.update("FrescoPlus" => {
|
36
|
+
:normal => types_dir.join("FrescoPlus-Normal.ttf").to_s,
|
37
|
+
:italic => types_dir.join("FrescoPlus-NormalItalic.ttf").to_s,
|
38
|
+
:bold => types_dir.join("FrescoPlus-Bold.ttf").to_s
|
39
|
+
})
|
40
|
+
@document.font_families.update("FrescoSansPlus" => {
|
41
|
+
:normal => types_dir.join("FrescoSansPlus-Normal.ttf").to_s,
|
42
|
+
:bold => types_dir.join("FrescoSansPlus-Bold.ttf").to_s
|
43
|
+
})
|
44
|
+
end
|
45
|
+
|
46
|
+
def header
|
47
|
+
header_height_1 = 88
|
48
|
+
|
49
|
+
@document.repeat :all do
|
50
|
+
@document.bounding_box( [0, 720], height: header_height_1, width: 540/2) do
|
51
|
+
@document.image Rails.root.join('public', 'images', 'sign_off_8th_light_black.jpg').to_s, :height => 50 , :width => 93.75, :at => [30, 76]
|
52
|
+
end
|
53
|
+
|
54
|
+
@document.bounding_box([(540/2)-30, 710], width: 540/2, height: header_height_1) do
|
55
|
+
@document.text "<font name='FrescoSansPlus' size='14'><b><color rgb='32a5f5'>8th</color> Light, Inc.</b></font>",
|
56
|
+
{
|
57
|
+
align: :right,
|
58
|
+
inline_format: true,
|
59
|
+
kerning: true,
|
60
|
+
leading: 12
|
61
|
+
}
|
62
|
+
|
63
|
+
@document.text "<font name='FrescoPlus' size='11'>" +
|
64
|
+
"1232 American Way" +
|
65
|
+
"\nLibertyville, IL 60048" +
|
66
|
+
"\n<i>tel</i> 877-407-4154" +
|
67
|
+
"\n<i>fax</i> 847-573-1748" +
|
68
|
+
"</font>",
|
69
|
+
{
|
70
|
+
align: :right,
|
71
|
+
inline_format: true,
|
72
|
+
kerning: true,
|
73
|
+
leading: 2
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def project_title
|
80
|
+
@document.fill_color = "3A66A7"
|
81
|
+
@document.font_size = 20
|
82
|
+
@document.text "Feature Set for #{@report.project_name}"
|
83
|
+
end
|
84
|
+
|
85
|
+
def iteration_information
|
86
|
+
@document.move_down @document.font.height
|
87
|
+
@document.font_size = 13
|
88
|
+
@document.fill_color = "000000"
|
89
|
+
@document.formatted_text [
|
90
|
+
{ :text => " #{@report.iteration_name} ", :styles => [:bold] },
|
91
|
+
{ :text => " from "},
|
92
|
+
{ :text => " #{@report.start_date.strftime("%m/%d/%Y")} ", :styles => [:bold] },
|
93
|
+
{ :text => " to "},
|
94
|
+
{ :text => " #{@report.finish_date.strftime("%m/%d/%Y")} ", :styles => [:bold] } ]
|
95
|
+
@document.move_down @document.font.height
|
96
|
+
@document.formatted_text [
|
97
|
+
{ :text => "Team Members: ", :styles => [:bold] },
|
98
|
+
{ :text => "#{@report.team_member_names}"} ]
|
99
|
+
@document.move_down @document.font.height
|
100
|
+
end
|
101
|
+
|
102
|
+
def tables
|
103
|
+
@report.tables.each do |table|
|
104
|
+
adjusted_table_data = @report.table_data[table.downcase]
|
105
|
+
@document.text table
|
106
|
+
@document.transparent(0.8) do
|
107
|
+
@document.table([@report.column_titles], :row_colors => ['bbbbbb'],
|
108
|
+
:column_widths => [60, 280, 100],
|
109
|
+
:cell_style => {:align => :center, :font_style => :bold} )
|
110
|
+
end
|
111
|
+
while !adjusted_table_data.empty? do
|
112
|
+
current_table = adjusted_table_data.slice!(0...1)
|
113
|
+
if start_new_page?(@document.cursor, 50)
|
114
|
+
@document.start_new_page
|
115
|
+
@document.move_down 120
|
116
|
+
@document.transparent(0.8) do
|
117
|
+
@document.table([@report.column_titles], :row_colors => ['bbbbbb'],
|
118
|
+
:column_widths => [60, 280, 100],
|
119
|
+
:cell_style => {:align => :center, :font_style => :bold} )
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
@document.table(current_table,
|
124
|
+
:column_widths => @report.column_widths,
|
125
|
+
:cell_style => {:align => :center}) do |table|
|
126
|
+
table.columns(1).align = :left
|
127
|
+
if adjusted_table_data.empty?
|
128
|
+
table.rows(table.row_length-1).style(:background_color => 'bbbbbb', :font_style => :bold)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
@document.move_down @document.font.height*2 if @document.cursor < 580
|
133
|
+
|
134
|
+
if start_new_page?(@document.cursor, 100)
|
135
|
+
@document.start_new_page
|
136
|
+
@document.move_down 120
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def committed_total
|
142
|
+
@document.formatted_text [
|
143
|
+
{ :text => "Completed Points / Committed Points: ", :styles => [:bold] },
|
144
|
+
{ :text => "#{@report.total_billed_points} / #{@report.committed_points_at_completion} "} ]
|
145
|
+
end
|
146
|
+
|
147
|
+
def signature_box
|
148
|
+
@document.font "Helvetica"
|
149
|
+
@document.font_size = 10
|
150
|
+
@document.draw_text "__________________________________________", :at => [0, @document.font.height*4.5+5]
|
151
|
+
@document.draw_text "Print Name", :at => [0, @document.font.height*3.5+5]
|
152
|
+
@document.draw_text "__________________________________________ ________________________", :at => [0, @document.font.height+5]
|
153
|
+
@document.draw_text "Signature", :at => [0, 5]
|
154
|
+
@document.draw_text "Date", :at => [265, 5]
|
155
|
+
end
|
156
|
+
|
157
|
+
def start_new_page?(cursor, height)
|
158
|
+
cursor < height
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|