purchase 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/features/purchase_committees.feature +125 -10
- data/features/purchase_emissions.feature +24 -7
- data/features/step_definitions/committee_steps.rb +93 -0
- data/lib/purchase/carbon_model.rb +108 -31
- data/lib/purchase/characterization.rb +6 -7
- data/lib/purchase/data.rb +7 -4
- data/lib/test_support/db/schema.rb +3 -3
- data/lib/test_support/purchase_record.rb +6 -0
- metadata +41 -24
@@ -1,13 +1,128 @@
|
|
1
1
|
Feature: Purchase Committee Calculations
|
2
2
|
The purchase model should generate correct committee calculations
|
3
3
|
|
4
|
-
Scenario Outline:
|
5
|
-
Given a purchase
|
6
|
-
And
|
7
|
-
And
|
8
|
-
When
|
9
|
-
Then the
|
10
|
-
|
11
|
-
|
12
|
-
|
|
13
|
-
|
|
4
|
+
Scenario Outline: Adjusted cost committee from cost and date
|
5
|
+
Given a purchase emitter
|
6
|
+
And a characteristic "cost" of "<cost>"
|
7
|
+
And characteristic "date" of "<date>"
|
8
|
+
When the "adjusted_cost" committee is calculated
|
9
|
+
Then the committee should have used quorum "from cost and date"
|
10
|
+
And the conclusion of the committee should be "<adjusted_cost>"
|
11
|
+
Examples:
|
12
|
+
| cost | date | adjusted_cost |
|
13
|
+
| 831.23 | 2010-08-01 | 831.23 |
|
14
|
+
| 11.00 | 2005-07-14 | 11.0 |
|
15
|
+
|
16
|
+
Scenario Outline: Adjusted cost committee from purchase amount and date
|
17
|
+
Given a purchase emitter
|
18
|
+
And a characteristic "purchase_amount" of "<amount>"
|
19
|
+
And characteristic "date" of "<date>"
|
20
|
+
When the "adjusted_cost" committee is calculated
|
21
|
+
Then the committee should have used quorum "from purchase amount and date"
|
22
|
+
And the conclusion of the committee should be "<adjusted_cost>"
|
23
|
+
Examples:
|
24
|
+
| amount | date | adjusted_cost |
|
25
|
+
| 831.23 | 2010-08-01 | 748.107 |
|
26
|
+
| 11.00 | 2005-07-14 | 9.9 |
|
27
|
+
|
28
|
+
Scenario Outline: Merchant category committee from merchant
|
29
|
+
Given a purchase emitter
|
30
|
+
And a characteristic "merchant.id" of "<id>"
|
31
|
+
When the "merchant_category" committee is calculated
|
32
|
+
Then the conclusion of the committee should have "mcc" of "<mcc>"
|
33
|
+
Examples:
|
34
|
+
| id | mcc |
|
35
|
+
| 1 | 5111 |
|
36
|
+
| 2 | 5732 |
|
37
|
+
|
38
|
+
Scenario Outline: Industry shares committee
|
39
|
+
Given a purchase emitter
|
40
|
+
And a characteristic "merchant_category.mcc" of "<mcc>"
|
41
|
+
When the "industry_shares" committee is calculated
|
42
|
+
Then the conclusion of the committee should have a record identified with "naics_code" of "<naics>" and having "ratio" of "<ratio>"
|
43
|
+
Examples:
|
44
|
+
| mcc | naics | ratio |
|
45
|
+
| 5111 | 45321 | 1.0 |
|
46
|
+
| 5732 | 443112 | 1.0 |
|
47
|
+
| 5172 | 32411 | 0.8 |
|
48
|
+
| 5172 | 324121 | 0.05 |
|
49
|
+
| 5172 | 324122 | 0.05 |
|
50
|
+
| 5172 | 324191 | 0.05 |
|
51
|
+
| 5172 | 324199 | 0.05 |
|
52
|
+
|
53
|
+
Scenario Outline: Product line shares committee
|
54
|
+
Given a purchase emitter
|
55
|
+
And a characteristic "merchant_category.mcc" of "<mcc>"
|
56
|
+
When the "industry_shares" committee is calculated
|
57
|
+
And the "product_line_shares" committee is calculated
|
58
|
+
Then the conclusion of the committee should include a key of <ps_code> and value <ratio>
|
59
|
+
Examples:
|
60
|
+
| mcc | ps_code | ratio |
|
61
|
+
| 5111 | 20370 | 0.6 |
|
62
|
+
| 5732 | 20375 | 0.5 |
|
63
|
+
| 5172 | 30860 | 0.32 |
|
64
|
+
| 5172 | 30861 | 0.0225 |
|
65
|
+
| 5172 | 30862 | 0.0175 |
|
66
|
+
| 5172 | 30863 | 0.018 |
|
67
|
+
| 5172 | 30864 | 0.019 |
|
68
|
+
|
69
|
+
Scenario Outline: Sector shares committee from industry shares
|
70
|
+
Given a purchase emitter
|
71
|
+
And a characteristic "merchant_category.mcc" of "<mcc>"
|
72
|
+
When the "industry_shares" committee is calculated
|
73
|
+
And the "sector_shares" committee is calculated
|
74
|
+
Then the conclusion of the committee should include a key of "<io_code>" and subvalue "share" of "<share>" and subvalue "emission_factor" of "<emission_factor>"
|
75
|
+
Examples:
|
76
|
+
| mcc | io_code | emission_factor | share |
|
77
|
+
| 5111 | | | |
|
78
|
+
| 5732 | | | |
|
79
|
+
| 5172 | 324110 | 2.0 | 0.8 |
|
80
|
+
| 5172 | 324121 | 1.3 | 0.05 |
|
81
|
+
| 5172 | 324122 | 0.9 | 0.05 |
|
82
|
+
| 5172 | 324191 | 0.2 | 0.05 |
|
83
|
+
| 5172 | 324199 | 1.2 | 0.05 |
|
84
|
+
|
85
|
+
Scenario Outline: Sector shares committee from industry shares and product line shares
|
86
|
+
Given a purchase emitter
|
87
|
+
And a characteristic "merchant_category.mcc" of "<mcc>"
|
88
|
+
When the "industry_shares" committee is calculated
|
89
|
+
And the "product_line_shares" committee is calculated
|
90
|
+
And the "sector_shares" committee is calculated
|
91
|
+
Then the conclusion of the committee should include a key of "<io_code>" and subvalue "share" of "<share>" and subvalue "emission_factor" of "<emission_factor>"
|
92
|
+
Examples:
|
93
|
+
| mcc | io_code | emission_factor | share |
|
94
|
+
| 5111 | 334111 | 1.3 | 0.24 |
|
95
|
+
| 5111 | 33411A | 0.5 | 0.18 |
|
96
|
+
| 5111 | 511200 | 1.0 | 0.18 |
|
97
|
+
| 5111 | 339940 | 1.1 | 0.2 |
|
98
|
+
| 5111 | 322230 | 1.4 | 0.2 |
|
99
|
+
| 5732 | 33411A | 0.5 | 0.5 |
|
100
|
+
| 5732 | 334300 | 1.2 | 0.25 |
|
101
|
+
| 5732 | 334210 | 1.6 | 0.2 |
|
102
|
+
| 5172 | 324110 | 2.0 | 0.256 |
|
103
|
+
| 5172 | 324121 | 1.3 | 0.05 |
|
104
|
+
| 5172 | 324122 | 0.9 | 0.05 |
|
105
|
+
| 5172 | 324191 | 0.2 | 0.32 |
|
106
|
+
| 5172 | 324199 | 1.2 | 0.05 |
|
107
|
+
| 8225 | 722000 | 0.8 | 0.15 |
|
108
|
+
|
109
|
+
Scenario Outline: Emission factor from sector shares
|
110
|
+
Given a purchase emitter
|
111
|
+
And a characteristic "merchant_category.mcc" of "<mcc>"
|
112
|
+
When the "industry_shares" committee is calculated
|
113
|
+
And the "product_line_shares" committee is calculated
|
114
|
+
And the "sector_shares" committee is calculated
|
115
|
+
And the "emission_factor" committee is calculated
|
116
|
+
Then the conclusion of the committee should be "<emission_factor>"
|
117
|
+
Examples:
|
118
|
+
| mcc | emission_factor |
|
119
|
+
| 5111 | 1.082 |
|
120
|
+
| 5732 | 0.87 |
|
121
|
+
| 5172 | 0.799205 |
|
122
|
+
| 8225 | 0.12 |
|
123
|
+
|
124
|
+
Scenario Outline: Emission factor from default
|
125
|
+
Given a purchase emitter
|
126
|
+
And a characteristic "merchant_category.mcc" of "<mcc>"
|
127
|
+
When the "emission_factor" committee is calculated
|
128
|
+
Then the conclusion of the committee should be "100"
|
@@ -1,13 +1,30 @@
|
|
1
1
|
Feature: Purchase Emissions Calculations
|
2
2
|
The purchase model should generate correct emission calculations
|
3
|
-
|
4
|
-
Scenario Outline:
|
5
|
-
Given a purchase has "
|
6
|
-
And it has "
|
3
|
+
|
4
|
+
Scenario Outline: Calculations for a merchant
|
5
|
+
Given a purchase has "merchant.id" of "<id>"
|
6
|
+
And it has "cost" of "<cost>"
|
7
7
|
And it has "date" of "<date>"
|
8
8
|
When emissions are calculated
|
9
9
|
Then the emission value should be within 1 kgs of <emission>
|
10
10
|
Examples:
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
| id | cost | date | emission |
|
12
|
+
| 1 | 100.00 | 2010-07-28 | 108.2 |
|
13
|
+
| 2 | 100.00 | 2010-07-28 | 87.0 |
|
14
|
+
| 3 | 100.00 | 2010-07-28 | 80.0 |
|
15
|
+
| 4 | 100.00 | 2010-07-28 | 121.0 |
|
16
|
+
| 5 | 100.00 | 2010-07-28 | 79.9205 |
|
17
|
+
|
18
|
+
Scenario Outline: Calculations for a merchant category
|
19
|
+
Given a purchase has "merchant_category.mcc" of "<mcc>"
|
20
|
+
And it has "cost" of "<cost>"
|
21
|
+
And it has "date" of "<date>"
|
22
|
+
When emissions are calculated
|
23
|
+
Then the emission value should be within 1 kgs of <emission>
|
24
|
+
Examples:
|
25
|
+
| mcc | cost | date | emission |
|
26
|
+
| 5111 | 100.00 | 2010-07-28 | 108.2 |
|
27
|
+
| 5732 | 100.00 | 2010-07-28 | 87.0 |
|
28
|
+
| 5812 | 100.00 | 2010-07-28 | 80.0 |
|
29
|
+
| 3504 | 100.00 | 2010-07-28 | 121.0 |
|
30
|
+
| 5172 | 100.00 | 2010-07-28 | 79.9205 |
|
@@ -0,0 +1,93 @@
|
|
1
|
+
def coerce_value(value)
|
2
|
+
if value =~ /\d+\.\d+/
|
3
|
+
value.to_f
|
4
|
+
elsif value =~ /^\d+$/
|
5
|
+
value.to_i
|
6
|
+
else
|
7
|
+
value
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def compare_values(a, b)
|
12
|
+
if b =~ /\d+\.\d+/
|
13
|
+
b = b.to_f
|
14
|
+
a.should be_close(b, 0.00001)
|
15
|
+
elsif b =~ /^\d+$/
|
16
|
+
b = b.to_i
|
17
|
+
a.should == b
|
18
|
+
else
|
19
|
+
a.should == b
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
Given /^a purchase emitter$/ do
|
24
|
+
@activity = PurchaseRecord
|
25
|
+
end
|
26
|
+
|
27
|
+
Given /^(a )?characteristic "(.*)" of "(.*)"$/ do |_, name, value|
|
28
|
+
@characteristics ||= {}
|
29
|
+
|
30
|
+
if name =~ /\./
|
31
|
+
model_name, attribute = name.split /\./
|
32
|
+
model = model_name.singularize.camelize.constantize
|
33
|
+
value = model.send "find_by_#{attribute}", value
|
34
|
+
@characteristics[model_name.to_sym] = value
|
35
|
+
else
|
36
|
+
value = coerce_value(value)
|
37
|
+
@characteristics[name.to_sym] = value
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
When /^the "(.*)" committee is calculated$/ do |committee_name|
|
42
|
+
@decision ||= @activity.decisions[:emission]
|
43
|
+
@committee = @decision.committees.find { |c| c.name.to_s == committee_name }
|
44
|
+
@report = @committee.report(@characteristics, [])
|
45
|
+
@characteristics[committee_name.to_sym] = @report.conclusion
|
46
|
+
end
|
47
|
+
|
48
|
+
Then /^the committee should have used quorum "(.*)"$/ do |quorum|
|
49
|
+
@report.quorum.name.should == quorum
|
50
|
+
end
|
51
|
+
|
52
|
+
Then /^the conclusion of the committee should be "(.+)"$/ do |conclusion|
|
53
|
+
compare_values(@report.conclusion, conclusion)
|
54
|
+
end
|
55
|
+
|
56
|
+
Then /^the conclusion of the committee should include a key of (.*) and value (.*)$/ do |key, value|
|
57
|
+
if key.present?
|
58
|
+
@report.conclusion.keys.map(&:to_s).should include(key)
|
59
|
+
else
|
60
|
+
@report.conclusion.keys.map(&:to_s).should be_empty
|
61
|
+
end
|
62
|
+
|
63
|
+
if value.present?
|
64
|
+
@report.conclusion.each do |k, v|
|
65
|
+
@report.conclusion[k.to_s] == v
|
66
|
+
end
|
67
|
+
compare_values(@report.conclusion[key.to_s], value)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
Then /^the conclusion of the committee should have "(.*)" of "(.*)"$/ do |attribute, value|
|
72
|
+
report_value = coerce_value @report.conclusion.send(attribute)
|
73
|
+
report_value.should == coerce_value(value)
|
74
|
+
end
|
75
|
+
|
76
|
+
Then /^the conclusion of the committee should have a record identified with "(.*)" of "(.*)" and having "(.*)" of "(.*)"$/ do |id_field, id, field, value|
|
77
|
+
id_field = id_field.to_sym
|
78
|
+
records = @report.conclusion
|
79
|
+
record = records.send("find_by_#{id_field}", id)
|
80
|
+
coerce_value(record.send(field)).should == coerce_value(value)
|
81
|
+
end
|
82
|
+
|
83
|
+
Then /^the conclusion of the committee should include a key of "(.*)" and subvalue "(.*)" of "(.*)" and subvalue "(.*)" of "(.*)"$/ do |key, subkey1, subvalue1, subkey2, subvalue2|
|
84
|
+
if key.present?
|
85
|
+
@report.conclusion.keys.map(&:to_s).should include(key)
|
86
|
+
actual_subvalue1 = coerce_value(@report.conclusion[key.to_s][subkey1.to_sym].to_s)
|
87
|
+
compare_values(actual_subvalue1, subvalue1)
|
88
|
+
actual_subvalue2 = coerce_value(@report.conclusion[key.to_s][subkey2.to_sym].to_s)
|
89
|
+
compare_values(actual_subvalue2, subvalue2)
|
90
|
+
else
|
91
|
+
@report.conclusion.keys.map(&:to_s).should be_empty
|
92
|
+
end
|
93
|
+
end
|
@@ -4,67 +4,144 @@ require 'timeframe'
|
|
4
4
|
module BrighterPlanet
|
5
5
|
module Purchase
|
6
6
|
module CarbonModel
|
7
|
+
class MissingSectorForProductLineSector < Exception; end
|
8
|
+
class MissingEmissionFactor < Exception; end
|
9
|
+
|
7
10
|
def self.included(base)
|
8
11
|
base.extend ::Leap::Subject
|
9
12
|
base.extend FastTimestamp
|
10
13
|
base.decide :emission, :with => :characteristics do
|
11
|
-
committee :emission do
|
12
|
-
|
14
|
+
committee :emission do
|
15
|
+
quorum 'from emissions factor and adjusted cost', :needs => [:emission_factor, :adjusted_cost] do |characteristics|
|
13
16
|
# lbs CO2e / 2002 US $ 2002 US $
|
14
|
-
characteristics[:emission_factor] *
|
17
|
+
characteristics[:emission_factor] * characteristics[:adjusted_cost]
|
15
18
|
end
|
16
19
|
|
17
|
-
|
20
|
+
quorum 'default' do
|
18
21
|
raise "The purchase's default emission quorum should never be called"
|
19
22
|
end
|
20
23
|
end
|
21
24
|
|
22
|
-
committee :emission_factor do
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
committee :emission_factor do
|
26
|
+
quorum 'from sector_shares', :needs => [:sector_shares] do |characteristics|
|
27
|
+
characteristics[:sector_shares].inject(0) do |sum, (io_code, data)|
|
28
|
+
if data[:emission_factor].nil?
|
29
|
+
raise MissingEmissionFactor,
|
30
|
+
"Missing emission factor for sector #{io_code}"
|
31
|
+
end
|
32
|
+
sum + data[:emission_factor] * data[:share]
|
29
33
|
end
|
30
34
|
end
|
35
|
+
|
36
|
+
quorum 'default' do
|
37
|
+
# FIXME TODO figure out a real fallback emission factor
|
38
|
+
100
|
39
|
+
end
|
31
40
|
end
|
41
|
+
|
42
|
+
committee :sector_shares do
|
43
|
+
quorum 'from industry shares and product line shares', :needs => [:industry_shares, :product_line_shares] do |characteristics|
|
44
|
+
industry_sector_shares = sector_shares_from_industry_shares(characteristics[:industry_shares])
|
45
|
+
|
46
|
+
product_line_shares = characteristics[:product_line_shares]
|
47
|
+
product_lines_sectors = ProductLinesSectors.find :all,
|
48
|
+
:conditions => { :ps_code => product_line_shares.keys }
|
49
|
+
product_sector_shares = product_lines_sectors.inject({}) do |hash, product_line_sector|
|
50
|
+
io_code = product_line_sector.io_code
|
51
|
+
ps_code = product_line_sector.ps_code
|
52
|
+
product_line_share = product_line_shares[ps_code]
|
53
|
+
|
54
|
+
share = product_line_sector.ratio * product_line_share
|
55
|
+
sector = product_line_sector.sector
|
56
|
+
if sector.nil?
|
57
|
+
raise MissingSectorForProductLineSector,
|
58
|
+
"Missing a related sector for ProductLineSector #{product_line_sector.inspect}"
|
59
|
+
end
|
60
|
+
hash[io_code] = {
|
61
|
+
:share => share,
|
62
|
+
:emission_factor => sector.emission_factor
|
63
|
+
}
|
64
|
+
hash
|
65
|
+
end
|
66
|
+
|
67
|
+
industry_sector_shares.merge product_sector_shares
|
68
|
+
end
|
32
69
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
70
|
+
# TODO Do we need this?
|
71
|
+
quorum 'from industry shares', :needs => [:industry_shares] do |characteristics|
|
72
|
+
sector_shares_from_industry_shares(characteristics[:industry_shares])
|
73
|
+
end
|
74
|
+
|
75
|
+
quorum 'default' do
|
76
|
+
raise "We need a merchant, merchant category, industry, or product_line"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
committee :product_line_shares do
|
81
|
+
quorum 'from industry shares', :needs => [:industry_shares] do |characteristics|
|
82
|
+
industry_shares = characteristics[:industry_shares]
|
83
|
+
industries_product_lines = industry_shares.
|
84
|
+
map(&:industries_product_lines).flatten
|
85
|
+
|
86
|
+
industries_product_lines.inject({}) do |hash, industry_product_line|
|
87
|
+
ps_code = industry_product_line.ps_code
|
88
|
+
naics_code = industry_product_line.naics_code
|
89
|
+
industry_share = industry_shares.find_by_naics_code naics_code
|
90
|
+
hash[ps_code] =
|
91
|
+
industry_product_line.ratio * industry_share.ratio
|
92
|
+
hash
|
39
93
|
end
|
40
94
|
end
|
41
95
|
end
|
42
|
-
|
43
|
-
committee :
|
44
|
-
|
45
|
-
characteristics[:merchant_category].
|
96
|
+
|
97
|
+
committee :industry_shares do
|
98
|
+
quorum 'from merchant category', :needs => [:merchant_category] do |characteristics|
|
99
|
+
characteristics[:merchant_category].merchant_categories_industries
|
46
100
|
end
|
47
101
|
end
|
48
|
-
|
49
|
-
committee :merchant_category do
|
50
|
-
|
102
|
+
|
103
|
+
committee :merchant_category do
|
104
|
+
quorum 'from merchant', :needs => [:merchant] do |characteristics|
|
51
105
|
characteristics[:merchant].merchant_category
|
52
106
|
end
|
53
107
|
end
|
54
|
-
|
55
|
-
committee :adjusted_cost do
|
56
|
-
|
57
|
-
|
58
|
-
|
108
|
+
|
109
|
+
committee :adjusted_cost do
|
110
|
+
quorum 'from cost and date', :needs => [:cost, :date] do |characteristics|
|
111
|
+
# FIXME TODO convert cost to 2002 dollars based on date
|
112
|
+
characteristics[:cost]
|
59
113
|
end
|
60
114
|
|
61
|
-
|
62
|
-
#
|
115
|
+
quorum 'from purchase amount and date', :needs => [:purchase_amount, :date] do |characteristics|
|
116
|
+
# FIXME TODO take out tax, then convert to 2002 US $ based on date and cost
|
117
|
+
characteristics[:purchase_amount] * 0.9
|
118
|
+
end
|
119
|
+
|
120
|
+
quorum 'default' do
|
121
|
+
raise "We need either a cost or purchase amount"
|
63
122
|
end
|
64
123
|
end
|
65
124
|
end
|
66
125
|
# FIXME TODO make other committees to report emissions by gas, by io sector, etc.
|
67
126
|
end
|
127
|
+
|
128
|
+
def self.sector_shares_from_industry_shares(industry_shares)
|
129
|
+
industry_sectors = industry_shares.map(&:industries_sectors).flatten
|
130
|
+
industry_sectors.inject({}) do |hash, industry_sector|
|
131
|
+
io_code = industry_sector.io_code
|
132
|
+
unless ['420000','4A0000'].include?(io_code.to_s)
|
133
|
+
naics_code = industry_sector.naics_code
|
134
|
+
industry_share = industry_shares.find_by_naics_code naics_code
|
135
|
+
calculated_share = industry_share.ratio * industry_sector.ratio
|
136
|
+
sector = industry_sector.sector
|
137
|
+
hash[io_code] = {
|
138
|
+
:share => calculated_share,
|
139
|
+
:emission_factor => sector.emission_factor
|
140
|
+
}
|
141
|
+
end
|
142
|
+
hash
|
143
|
+
end
|
144
|
+
end
|
68
145
|
end
|
69
146
|
end
|
70
147
|
end
|
@@ -6,16 +6,15 @@ module BrighterPlanet
|
|
6
6
|
def self.included(base)
|
7
7
|
base.send :include, Characterizable
|
8
8
|
base.characterize do
|
9
|
-
has :merchant
|
10
|
-
|
11
|
-
|
12
|
-
has :
|
13
|
-
has :
|
14
|
-
has :io_sector
|
9
|
+
has :merchant
|
10
|
+
has :merchant_category
|
11
|
+
has :industry_shares
|
12
|
+
has :product_line_shares
|
13
|
+
has :sector_shares
|
15
14
|
has :purchase_amount # full purchase amount
|
16
15
|
has :tax # tax portion of purchase
|
17
16
|
has :cost # cost before tax
|
18
|
-
has :line_item
|
17
|
+
has :line_item # text describing what was purchased
|
19
18
|
has :customer_code
|
20
19
|
has :zip_code
|
21
20
|
has :date
|
data/lib/purchase/data.rb
CHANGED
@@ -6,14 +6,17 @@ module BrighterPlanet
|
|
6
6
|
def self.included(base)
|
7
7
|
base.data_miner do
|
8
8
|
schema do
|
9
|
-
|
9
|
+
string 'merchant_id'
|
10
10
|
string 'mcc'
|
11
|
-
string 'naics_code'
|
12
|
-
string '
|
13
|
-
string 'io_code'
|
11
|
+
string 'naics_code'
|
12
|
+
string 'ps_code'
|
13
|
+
string 'io_code'
|
14
14
|
float 'purchase_amount'
|
15
|
+
string 'purchase_amount_units'
|
15
16
|
float 'tax'
|
17
|
+
string 'tax_units'
|
16
18
|
float 'cost'
|
19
|
+
string 'cost_units'
|
17
20
|
string 'line_item'
|
18
21
|
string 'customer_code'
|
19
22
|
string 'zip_code_name'
|
@@ -4,9 +4,9 @@ Sniff::Database.define_schema do
|
|
4
4
|
create_table "purchase_records", :force => true do |t|
|
5
5
|
t.integer 'merchant_id'
|
6
6
|
t.string 'mcc'
|
7
|
-
t.string 'naics_code'
|
8
|
-
t.string '
|
9
|
-
t.string 'io_code'
|
7
|
+
t.string 'naics_code'
|
8
|
+
t.string 'ps_code'
|
9
|
+
t.string 'io_code'
|
10
10
|
t.float 'purchase_amount'
|
11
11
|
t.float 'tax'
|
12
12
|
t.float 'cost'
|
@@ -6,4 +6,10 @@ require 'sniff'
|
|
6
6
|
class PurchaseRecord < ActiveRecord::Base
|
7
7
|
include Sniff::Emitter
|
8
8
|
include BrighterPlanet::Purchase
|
9
|
+
|
10
|
+
belongs_to :merchant, :foreign_key => 'merchant_id'
|
11
|
+
belongs_to :merchant_category, :foreign_key => 'mcc'
|
12
|
+
# belongs_to :industry, :foreign_key => 'naics_code'
|
13
|
+
# belongs_to :product_line, :foreign_key => 'ps_code'
|
14
|
+
# belongs_to :sector, :foreign_key => 'io_code'
|
9
15
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: purchase
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Andy Rossmeissl
|
@@ -19,7 +19,7 @@ autorequire:
|
|
19
19
|
bindir: bin
|
20
20
|
cert_chain: []
|
21
21
|
|
22
|
-
date: 2010-
|
22
|
+
date: 2010-08-02 00:00:00 -04:00
|
23
23
|
default_executable:
|
24
24
|
dependencies:
|
25
25
|
- !ruby/object:Gem::Dependency
|
@@ -144,12 +144,12 @@ dependencies:
|
|
144
144
|
requirements:
|
145
145
|
- - "="
|
146
146
|
- !ruby/object:Gem::Version
|
147
|
-
hash:
|
147
|
+
hash: 57
|
148
148
|
segments:
|
149
149
|
- 0
|
150
150
|
- 0
|
151
|
-
-
|
152
|
-
version: 0.0.
|
151
|
+
- 19
|
152
|
+
version: 0.0.19
|
153
153
|
requirement: *id008
|
154
154
|
- !ruby/object:Gem::Dependency
|
155
155
|
type: :runtime
|
@@ -170,8 +170,23 @@ dependencies:
|
|
170
170
|
- !ruby/object:Gem::Dependency
|
171
171
|
type: :runtime
|
172
172
|
prerelease: false
|
173
|
-
name:
|
173
|
+
name: cohort_scope
|
174
174
|
version_requirements: &id010 !ruby/object:Gem::Requirement
|
175
|
+
none: false
|
176
|
+
requirements:
|
177
|
+
- - ~>
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
hash: 11
|
180
|
+
segments:
|
181
|
+
- 0
|
182
|
+
- 0
|
183
|
+
version: "0.0"
|
184
|
+
requirement: *id010
|
185
|
+
- !ruby/object:Gem::Dependency
|
186
|
+
type: :runtime
|
187
|
+
prerelease: false
|
188
|
+
name: data_miner
|
189
|
+
version_requirements: &id011 !ruby/object:Gem::Requirement
|
175
190
|
none: false
|
176
191
|
requirements:
|
177
192
|
- - "="
|
@@ -182,28 +197,28 @@ dependencies:
|
|
182
197
|
- 5
|
183
198
|
- 2
|
184
199
|
version: 0.5.2
|
185
|
-
requirement: *
|
200
|
+
requirement: *id011
|
186
201
|
- !ruby/object:Gem::Dependency
|
187
202
|
type: :runtime
|
188
203
|
prerelease: false
|
189
204
|
name: earth
|
190
|
-
version_requirements: &
|
205
|
+
version_requirements: &id012 !ruby/object:Gem::Requirement
|
191
206
|
none: false
|
192
207
|
requirements:
|
193
208
|
- - ">="
|
194
209
|
- !ruby/object:Gem::Version
|
195
|
-
hash:
|
210
|
+
hash: 61
|
196
211
|
segments:
|
197
212
|
- 0
|
198
213
|
- 0
|
199
|
-
-
|
200
|
-
version: 0.0.
|
201
|
-
requirement: *
|
214
|
+
- 17
|
215
|
+
version: 0.0.17
|
216
|
+
requirement: *id012
|
202
217
|
- !ruby/object:Gem::Dependency
|
203
218
|
type: :runtime
|
204
219
|
prerelease: false
|
205
220
|
name: falls_back_on
|
206
|
-
version_requirements: &
|
221
|
+
version_requirements: &id013 !ruby/object:Gem::Requirement
|
207
222
|
none: false
|
208
223
|
requirements:
|
209
224
|
- - "="
|
@@ -214,12 +229,12 @@ dependencies:
|
|
214
229
|
- 0
|
215
230
|
- 2
|
216
231
|
version: 0.0.2
|
217
|
-
requirement: *
|
232
|
+
requirement: *id013
|
218
233
|
- !ruby/object:Gem::Dependency
|
219
234
|
type: :runtime
|
220
235
|
prerelease: false
|
221
236
|
name: fast_timestamp
|
222
|
-
version_requirements: &
|
237
|
+
version_requirements: &id014 !ruby/object:Gem::Requirement
|
223
238
|
none: false
|
224
239
|
requirements:
|
225
240
|
- - "="
|
@@ -230,12 +245,12 @@ dependencies:
|
|
230
245
|
- 0
|
231
246
|
- 4
|
232
247
|
version: 0.0.4
|
233
|
-
requirement: *
|
248
|
+
requirement: *id014
|
234
249
|
- !ruby/object:Gem::Dependency
|
235
250
|
type: :runtime
|
236
251
|
prerelease: false
|
237
252
|
name: leap
|
238
|
-
version_requirements: &
|
253
|
+
version_requirements: &id015 !ruby/object:Gem::Requirement
|
239
254
|
none: false
|
240
255
|
requirements:
|
241
256
|
- - "="
|
@@ -246,12 +261,12 @@ dependencies:
|
|
246
261
|
- 4
|
247
262
|
- 1
|
248
263
|
version: 0.4.1
|
249
|
-
requirement: *
|
264
|
+
requirement: *id015
|
250
265
|
- !ruby/object:Gem::Dependency
|
251
266
|
type: :runtime
|
252
267
|
prerelease: false
|
253
268
|
name: summary_judgement
|
254
|
-
version_requirements: &
|
269
|
+
version_requirements: &id016 !ruby/object:Gem::Requirement
|
255
270
|
none: false
|
256
271
|
requirements:
|
257
272
|
- - "="
|
@@ -262,12 +277,12 @@ dependencies:
|
|
262
277
|
- 3
|
263
278
|
- 8
|
264
279
|
version: 1.3.8
|
265
|
-
requirement: *
|
280
|
+
requirement: *id016
|
266
281
|
- !ruby/object:Gem::Dependency
|
267
282
|
type: :runtime
|
268
283
|
prerelease: false
|
269
284
|
name: timeframe
|
270
|
-
version_requirements: &
|
285
|
+
version_requirements: &id017 !ruby/object:Gem::Requirement
|
271
286
|
none: false
|
272
287
|
requirements:
|
273
288
|
- - "="
|
@@ -278,7 +293,7 @@ dependencies:
|
|
278
293
|
- 0
|
279
294
|
- 8
|
280
295
|
version: 0.0.8
|
281
|
-
requirement: *
|
296
|
+
requirement: *id017
|
282
297
|
description: A software model in Ruby for the greenhouse gas emissions of a purchase
|
283
298
|
email: seamus@brighterplanet.com
|
284
299
|
executables: []
|
@@ -300,6 +315,7 @@ files:
|
|
300
315
|
- lib/test_support/db/schema.rb
|
301
316
|
- lib/test_support/purchase_record.rb
|
302
317
|
- README.html
|
318
|
+
- features/step_definitions/committee_steps.rb
|
303
319
|
- features/support/env.rb
|
304
320
|
- features/purchase_committees.feature
|
305
321
|
- features/purchase_emissions.feature
|
@@ -338,6 +354,7 @@ signing_key:
|
|
338
354
|
specification_version: 3
|
339
355
|
summary: A carbon model
|
340
356
|
test_files:
|
357
|
+
- features/step_definitions/committee_steps.rb
|
341
358
|
- features/support/env.rb
|
342
359
|
- features/purchase_committees.feature
|
343
360
|
- features/purchase_emissions.feature
|