appraisermetrics_report_service 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/.gitignore +17 -0
- data/Gemfile +3 -0
- data/README.md +78 -0
- data/Rakefile +2 -0
- data/appraisermetrics_report_service.gemspec +26 -0
- data/config/static_text.yml +44 -0
- data/lib/appraisermetrics_report_service.rb +8 -0
- data/lib/appraisermetrics_report_service/version.rb +3 -0
- data/lib/closed_sale.rb +706 -0
- data/lib/eval_report.rb +1192 -0
- data/lib/report_utils.rb +219 -0
- data/spec/lib/closed_sale_spec.rb +626 -0
- data/spec/lib/eval_report_spec.rb +799 -0
- data/spec/lib/report_utils_spec.rb +213 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/test_data/images/ag_sales.jpg +0 -0
- data/spec/test_data/images/profile1.png +0 -0
- data/spec/test_data/images/property_pic1.png +0 -0
- data/spec/test_data/images/property_pic2.png +0 -0
- data/spec/test_data/images/property_pic3.png +0 -0
- data/spec/test_data/images/property_pic4.png +0 -0
- data/spec/test_data/images/regional1.jpg +0 -0
- data/spec/test_data/images/regional2.jpg +0 -0
- data/spec/test_data/images/subject1.jpg +0 -0
- data/spec/test_data/images/subject2.jpg +0 -0
- data/spec/test_data/images/subject3.jpg +0 -0
- data/spec/test_data/images/subject4.jpg +0 -0
- data/spec/test_data/images/test_logo.png +0 -0
- data/spec/test_data/images/topo1.jpg +0 -0
- data/spec/test_data/images/topo2.jpg +0 -0
- data/spec/test_data/sampler.rb +1404 -0
- metadata +208 -0
data/lib/eval_report.rb
ADDED
@@ -0,0 +1,1192 @@
|
|
1
|
+
class EvalReport < Prawn::Document
|
2
|
+
require 'prawn'
|
3
|
+
require 'prawn/table'
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
include ReportUtils # utility methods used across reports
|
7
|
+
|
8
|
+
def initialize()
|
9
|
+
super()
|
10
|
+
end
|
11
|
+
|
12
|
+
def write_content(subject, comparables, images, logo) # main method to populate pdf
|
13
|
+
# variables used across instance methods
|
14
|
+
@logo = logo
|
15
|
+
@sub = subject
|
16
|
+
@comps = comparables
|
17
|
+
@images = images
|
18
|
+
@text_blocks = static_strings # Hash of text blocks loaded from .yml
|
19
|
+
@recon_primary_per_acre = [] # used for reconciliation for comparables
|
20
|
+
@recon_secondary_per_acre = [] # ""
|
21
|
+
|
22
|
+
# font defaults to Helvetica
|
23
|
+
font_size 11
|
24
|
+
|
25
|
+
office_logo
|
26
|
+
cover_page
|
27
|
+
letter_of_transmittal # table/text
|
28
|
+
subject_images #images with caption # 2 pages
|
29
|
+
table_of_contents #text
|
30
|
+
introduction #text and checkboxes
|
31
|
+
property_identification
|
32
|
+
regional_maps
|
33
|
+
topo_maps
|
34
|
+
property_description
|
35
|
+
property_features
|
36
|
+
value_intro
|
37
|
+
comp_methodology
|
38
|
+
property_comparison # landscape
|
39
|
+
discussion_of_sales # landscape
|
40
|
+
ag_sales_map
|
41
|
+
val_method_and_recon
|
42
|
+
assumptions_and_conditions
|
43
|
+
addenda_contents
|
44
|
+
addendum_a
|
45
|
+
addendum_b
|
46
|
+
end
|
47
|
+
|
48
|
+
def office_logo
|
49
|
+
move_down 550
|
50
|
+
image "#{@logo}", width: 200
|
51
|
+
end
|
52
|
+
|
53
|
+
def cover_page
|
54
|
+
bounding_box([220, 700], width: 320, height: 700) do
|
55
|
+
text 'EVALUATION OF REAL PROPERTY', size: 14
|
56
|
+
move_down 5
|
57
|
+
text "#{@sub[:primary_ag_use]}"
|
58
|
+
|
59
|
+
if @sub[:property_inclusions] && @sub[:property_inclusions].any?
|
60
|
+
move_down 3
|
61
|
+
text "#{@sub[:property_inclusions].join(', ')}"
|
62
|
+
end
|
63
|
+
|
64
|
+
move_down 10
|
65
|
+
|
66
|
+
text "#{@sub[:property_name]}"
|
67
|
+
move_down 3
|
68
|
+
text "#{@sub[:county_state]}".slice(0..-3)
|
69
|
+
move_down 3
|
70
|
+
text "#{@sub[:property_address_number]} " << "#{@sub[:street_or_road_name]}"
|
71
|
+
move_down 3
|
72
|
+
add_string = ""
|
73
|
+
add_string << "#{@sub[:city]}, "
|
74
|
+
|
75
|
+
if @sub[:county_state]
|
76
|
+
add_string << "#{@sub[:county_state].slice(-2..-1)} "
|
77
|
+
end
|
78
|
+
|
79
|
+
add_string << "#{@sub[:zip_code]}"
|
80
|
+
text add_string
|
81
|
+
move_down 25
|
82
|
+
|
83
|
+
text 'AGRICULTURAL REAL ESTATE EVALUATION', size: 14
|
84
|
+
move_down 10
|
85
|
+
text 'As of ' << "#{datemaker(@sub[:effvaluedateasis])}"
|
86
|
+
move_down 3
|
87
|
+
text 'Report Date: ' << "#{datemaker(@sub[:valreportdate])}"
|
88
|
+
move_down 15
|
89
|
+
|
90
|
+
text 'Prepared For:'
|
91
|
+
text "#{@sub[:clientid]}"
|
92
|
+
text "#{@sub[:clientaddress]}"
|
93
|
+
text "#{@sub[:clientcontact]}"
|
94
|
+
text "#{@sub[:clientrefnum]}"
|
95
|
+
move_down 10
|
96
|
+
text 'Prepared By:'
|
97
|
+
text "#{@sub[:record_created_by]}"
|
98
|
+
# "#{@sub[:tenant_name]}" # not found currently
|
99
|
+
# "#{@sub[:tenant_contact]}" # not found currently
|
100
|
+
end
|
101
|
+
|
102
|
+
stroke_bounds
|
103
|
+
start_new_page
|
104
|
+
end
|
105
|
+
|
106
|
+
def letter_of_transmittal
|
107
|
+
header("LETTER OF TRANSMITTAL")
|
108
|
+
move_down 10
|
109
|
+
text "#{datemaker(@sub[:valreportdate])}"
|
110
|
+
text "#{@sub[:clientid]}"
|
111
|
+
text "#{@sub[:clientaddress]}"
|
112
|
+
text "#{@sub[:clientcontact]}"
|
113
|
+
|
114
|
+
move_down 25
|
115
|
+
float do
|
116
|
+
text "Re:"
|
117
|
+
end
|
118
|
+
|
119
|
+
indent(30) do
|
120
|
+
taxes = @sub[:taxes]
|
121
|
+
if taxes && taxes.any?
|
122
|
+
t_s = taxes.inject("") {|memo_s, t| memo_s << "#{t[:tax_parcel_no]}, "; memo_s }
|
123
|
+
else
|
124
|
+
t_s = ""
|
125
|
+
end
|
126
|
+
|
127
|
+
parallel_text("Evaluation of Real Property", " ", 150)
|
128
|
+
parallel_text("Property Type:", "#{@sub[:primary_ag_use]}", 150)
|
129
|
+
parallel_text("Property Name:", "#{@sub[:property_name]}", 150)
|
130
|
+
parallel_text("Tax Parcel ID No.:", t_s , 150)
|
131
|
+
parallel_text("County:","#{@sub[:county_state]}".slice(0..-3), 150)
|
132
|
+
parallel_text("Street Address:", "#{@sub[:property_address_number]}" << "#{@sub[:street_or_road_name]}", 150)
|
133
|
+
parallel_text("City, State, Zip Code:", "#{@sub[:city]}" << "#{@sub[:county_state]}".chars.last(2).join(''), 150)
|
134
|
+
parallel_text("Client Assignment Ref. No.:", "#{@sub[:clientrefnum]}", 150)
|
135
|
+
parallel_text("Valuator's Internal File No.:", "#{@sub[:_id]}", 150)
|
136
|
+
end
|
137
|
+
|
138
|
+
move_cursor_to 450
|
139
|
+
text "Dear " << "#{@sub[:clientid]},"
|
140
|
+
text @text_blocks[:transmittal]
|
141
|
+
start_new_page
|
142
|
+
end
|
143
|
+
|
144
|
+
def subject_images
|
145
|
+
header("SUBJECT PHOTOGRAPHS")
|
146
|
+
move_down 10
|
147
|
+
if @images && @images[:subject_photos]
|
148
|
+
if @images[:subject_photos][0]
|
149
|
+
image_cap("")
|
150
|
+
image "#{@images[:subject_photos][0]}", width: 300, position: :center
|
151
|
+
move_down 2
|
152
|
+
text "Subject Property - Representative Image", align: :center
|
153
|
+
move_down 25
|
154
|
+
else
|
155
|
+
text "No Image", align: :center
|
156
|
+
move_cursor_to 350
|
157
|
+
end
|
158
|
+
|
159
|
+
if @images[:subject_photos][1]
|
160
|
+
image_cap("")
|
161
|
+
image "#{@images[:subject_photos][1]}", width: 300, position: :center
|
162
|
+
move_down 2
|
163
|
+
text "Subject Property - Representative Image", align: :center
|
164
|
+
move_down 25
|
165
|
+
else
|
166
|
+
text "No Image", align: :center
|
167
|
+
move_cursor_to 350
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
start_new_page
|
172
|
+
header("SUBJECT PHOTOGRAPHS")
|
173
|
+
move_down 10
|
174
|
+
if @images[:subject_photos][2]
|
175
|
+
image_cap("")
|
176
|
+
image "#{@images[:subject_photos][2]}", width: 300, position: :center
|
177
|
+
move_down 2
|
178
|
+
text "Subject Property - Representative Image", align: :center
|
179
|
+
move_down 25
|
180
|
+
else
|
181
|
+
text "No Image", align: :center
|
182
|
+
move_cursor_to 350
|
183
|
+
end
|
184
|
+
|
185
|
+
if @images[:subject_photos][3]
|
186
|
+
image_cap("")
|
187
|
+
image "#{@images[:subject_photos][3]}", width: 300, position: :center
|
188
|
+
move_down 2
|
189
|
+
text "Subject Property - Representative Image", align: :center
|
190
|
+
move_down 25
|
191
|
+
else
|
192
|
+
text "No Image", align: :center
|
193
|
+
move_cursor_to 350
|
194
|
+
end
|
195
|
+
else
|
196
|
+
text "No Image", align: :center
|
197
|
+
move_cursor_to 350
|
198
|
+
text "No Image", align: :center
|
199
|
+
move_cursor_to 350
|
200
|
+
start_new_page
|
201
|
+
text "No Image", align: :center
|
202
|
+
move_cursor_to 350
|
203
|
+
text "No Image", align: :center
|
204
|
+
move_cursor_to 350
|
205
|
+
end
|
206
|
+
|
207
|
+
start_new_page
|
208
|
+
end
|
209
|
+
|
210
|
+
def table_of_contents
|
211
|
+
header("TABLE OF CONTENTS")
|
212
|
+
move_down 25
|
213
|
+
text "Table of Contents", size: 14
|
214
|
+
move_down 25
|
215
|
+
|
216
|
+
contents = ["INTRODUCTION", "SCOPE OF WORK", "REGIONAL MAPS", "MAPS",
|
217
|
+
"PROPERTY DESCRIPTION, SURROUNDING LAND USES, REGIONAL ECONOMIC AND \nDEMOGRAPHIC OVERVIEW", "HIGHEST AND BEST USE",
|
218
|
+
"SALES COMPARISON APPROACH", "METHODOLOGY", "DISCUSSION OF SALES USED", "GLOSSARY OF TERMS & DEFINITIONS", "CASH EQUIVALENCE",
|
219
|
+
"ELLWOOD FORMULA", "EXPOSURE TIME","FEE SIMPLE ESTATE", "LEASED FEE INTEREST", "LEASEHOLD INTEREST", "MARKET RENT", "MARKET VALUE",
|
220
|
+
"ADDENDA CONTENTS"
|
221
|
+
]
|
222
|
+
|
223
|
+
contents.each do |c|
|
224
|
+
text "#{c}"
|
225
|
+
stroke_horizontal_rule
|
226
|
+
move_down 5
|
227
|
+
end
|
228
|
+
start_new_page
|
229
|
+
end
|
230
|
+
|
231
|
+
def introduction
|
232
|
+
header("INTRODUCTION")
|
233
|
+
move_down 25
|
234
|
+
text "INTRODUCTION", size: 14, style: :bold
|
235
|
+
move_down 10
|
236
|
+
text "SCOPE OF WORK", size: 14, style: :bold
|
237
|
+
text @text_blocks[:scope_of_work1]
|
238
|
+
move_down 10
|
239
|
+
|
240
|
+
if @sub[:research] && @sub[:research].any?
|
241
|
+
@sub[:research].each do |r|
|
242
|
+
float do # building a checkbox because there is no support for them in base 14 fonts
|
243
|
+
float do
|
244
|
+
rectangle [0, cursor], 12, 12
|
245
|
+
stroke
|
246
|
+
end
|
247
|
+
text 'X', size: 15
|
248
|
+
end
|
249
|
+
|
250
|
+
indent(50) do
|
251
|
+
text r
|
252
|
+
move_down 10
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
move_down 5
|
258
|
+
text @text_blocks[:scope_of_work3]
|
259
|
+
start_new_page
|
260
|
+
end
|
261
|
+
|
262
|
+
def property_identification
|
263
|
+
header("PROPERTY IDENTIFICATION")
|
264
|
+
move_down 25
|
265
|
+
|
266
|
+
parallel_text("Effective Date of Value", "#{datemaker(@sub[:effvaluedateasis])}", 150)
|
267
|
+
move_down 30
|
268
|
+
parallel_text("Report Date:", "#{datemaker(@sub[:valreportdate])}", 150)
|
269
|
+
move_down 30
|
270
|
+
parallel_text("Estate Valued:", "#{@sub[:property_rights]}", 150)
|
271
|
+
move_down 30
|
272
|
+
parallel_text("Intended Use:", no_nil_array(@sub[:intendeduse]).join(", "), 150)
|
273
|
+
move_down 30
|
274
|
+
parallel_text("Intended User:", "#{@sub[:intendeduser]}", 150)
|
275
|
+
move_down 30
|
276
|
+
parallel_text("Problem being solved:","#{@sub[:appproblem]}", 150)
|
277
|
+
move_down 30
|
278
|
+
|
279
|
+
text "CONFORMITY AND COMPLIANCE IDENTIFICATION FOR THIS EVALUATION ANALYSIS", size: 14, style: :bold
|
280
|
+
move_down 20
|
281
|
+
text "#{no_nil_array(@sub[:complianceid]).join(', ')}"
|
282
|
+
move_down 30
|
283
|
+
|
284
|
+
text "DEFINITION OF VALUE USED IN THIS EVALUATION:", size: 14, style: :bold
|
285
|
+
move_down 20
|
286
|
+
text "#{no_nil_array(@sub[:valuationvalues]).join(', ')}"
|
287
|
+
move_down 30
|
288
|
+
|
289
|
+
text "ASSUMPTIONS:", size: 14, style: :bold
|
290
|
+
move_down 20
|
291
|
+
text "#{(@sub[:extrassumptions])}"
|
292
|
+
move_down 30
|
293
|
+
|
294
|
+
text "EXPOSURE TIME:", size: 14, style: :bold
|
295
|
+
move_down 20
|
296
|
+
text "#{@sub[:exptimereasoning]}"
|
297
|
+
move_down 30
|
298
|
+
|
299
|
+
text "MARKETING TIME:", size: 14, style: :bold
|
300
|
+
move_down 20
|
301
|
+
text "#{@sub[:marketingtimereasoning]}"
|
302
|
+
move_down 30
|
303
|
+
|
304
|
+
start_new_page
|
305
|
+
end
|
306
|
+
|
307
|
+
def regional_maps
|
308
|
+
header("REGIONAL MAPS")
|
309
|
+
move_down 25
|
310
|
+
text "REGIONAL MAPS", size: 14, align: :center
|
311
|
+
if @images && @images[:regional_maps]
|
312
|
+
if @images[:regional_maps][0]
|
313
|
+
image_cap("STATE MAP")
|
314
|
+
image "#{@images[:regional_maps][0]}", width: 300, position: :center
|
315
|
+
move_down 25
|
316
|
+
else
|
317
|
+
text 'No Image', align: :center
|
318
|
+
move_cursor_to 350
|
319
|
+
end
|
320
|
+
|
321
|
+
if @images[:regional_maps][1]
|
322
|
+
image_cap("COUNTY MAP")
|
323
|
+
image "#{@images[:regional_maps][1]}", width: 300, position: :center
|
324
|
+
else
|
325
|
+
text 'No Image', align: :center
|
326
|
+
move_cursor_to 350
|
327
|
+
end
|
328
|
+
else
|
329
|
+
text 'No Image', align: :center
|
330
|
+
move_cursor_to 350
|
331
|
+
text 'No Image', align: :center
|
332
|
+
end
|
333
|
+
|
334
|
+
start_new_page
|
335
|
+
end
|
336
|
+
|
337
|
+
def topo_maps
|
338
|
+
header("LOCAL AREA MAP")
|
339
|
+
move_down 25
|
340
|
+
text "MAPS", size: 14, align: :center
|
341
|
+
|
342
|
+
if @images && @images[:topo_maps]
|
343
|
+
if @images[:topo_maps][0]
|
344
|
+
image_cap("TOPOGRAPHICAL MAPS")
|
345
|
+
image "#{@images[:topo_maps][0]}", width: 300, position: :center
|
346
|
+
move_down 25
|
347
|
+
else
|
348
|
+
text 'No Image', align: :center
|
349
|
+
move_cursor_to 350
|
350
|
+
end
|
351
|
+
|
352
|
+
|
353
|
+
if @images[:topo_maps][1]
|
354
|
+
image_cap("AERIAL FSA MAP")
|
355
|
+
image "#{@images[:topo_maps][1]}", width: 300, position: :center
|
356
|
+
else
|
357
|
+
text 'No Image', align: :center
|
358
|
+
end
|
359
|
+
else
|
360
|
+
text 'No Image', align: :center
|
361
|
+
move_cursor_to 350
|
362
|
+
text 'No Image', align: :center
|
363
|
+
end
|
364
|
+
start_new_page
|
365
|
+
end
|
366
|
+
|
367
|
+
def property_description
|
368
|
+
header("PROPERTY DESCRIPTION")
|
369
|
+
move_down 25
|
370
|
+
text "PROPERTY DESCRIPTION, SURROUNDING LAND USES, REGIONAL ECONOMIC AND DEMOGRAPHIC OVERVIEW", size: 14, style: :bold
|
371
|
+
font_size 6
|
372
|
+
bounding_box([0, 645], height: 300, width: 340) do
|
373
|
+
if @sub[:landclassifications] && @sub[:landclassifications].any?
|
374
|
+
@number_acres = @sub[:landclassifications].inject(0) {|memo, l| memo += no_nil_number(l[:numacres]); memo }
|
375
|
+
else
|
376
|
+
@number_acres = 0
|
377
|
+
end
|
378
|
+
|
379
|
+
general_data = [
|
380
|
+
[{content: "General Information", colspan:2}],
|
381
|
+
["Effective Date of Analysis:", @sub[:effvaluedateasis]],
|
382
|
+
["Property Rights Being Analyzed:", @sub[:property_rights]],
|
383
|
+
["Total No. Acres:", @number_acres]
|
384
|
+
]
|
385
|
+
|
386
|
+
table(general_data) do
|
387
|
+
columns(0..1).width = 170
|
388
|
+
cells.style(border_width: 0)
|
389
|
+
cells.padding = [1, 2.5]
|
390
|
+
column(0).style(font_style: :bold, align: :right)
|
391
|
+
row(0).style(align: :center, border_bottom_width: 0.5)
|
392
|
+
end
|
393
|
+
|
394
|
+
# construction of combo strings
|
395
|
+
street_address = "#{@sub[:property_address_number]} " << "#{@sub[:street_or_road_name]}"
|
396
|
+
lat_long_string = ""
|
397
|
+
lat_long_string << "#{@sub[:position][0]}/#{@sub[:position][1]}" unless @sub[:positioin] == nil
|
398
|
+
meridian_town_range = "#{@sub[:meridian]}, " << "#{@sub[:township]} " << "#{@sub[:range]}"
|
399
|
+
|
400
|
+
taxes = @sub[:taxes]
|
401
|
+
if taxes
|
402
|
+
parcel_nos = taxes.inject("") {|memo, t| memo << "#{t[:tax_parcel_no]}; "; memo}
|
403
|
+
else
|
404
|
+
parcel_nos = ""
|
405
|
+
end
|
406
|
+
|
407
|
+
re_tax_string = "#{@sub[:total_RET]} "
|
408
|
+
if @number_acres == 0
|
409
|
+
re_tax_string << "/ 0"
|
410
|
+
else
|
411
|
+
re_tax_string << "/ #{@sub[:total_RET].to_f / @number_acres}"
|
412
|
+
end
|
413
|
+
|
414
|
+
if @sub[:county_state]
|
415
|
+
state_string = "#{@sub[:county_state].slice(-2..-1)}"
|
416
|
+
else
|
417
|
+
state_string = ""
|
418
|
+
end
|
419
|
+
|
420
|
+
identification_data = [
|
421
|
+
[{content: "Property Identification", colspan: 2}],
|
422
|
+
["Property Owner:", @sub[:curr_owner]],
|
423
|
+
["Property Name:", @sub[:property_name]],
|
424
|
+
["Street Address:", street_address],
|
425
|
+
["City:", @sub[:city]],
|
426
|
+
["State:", state_string],
|
427
|
+
["Zip Code:", @sub[:zip_code]],
|
428
|
+
["Latitude/Longitude:", lat_long_string],
|
429
|
+
["Meridian/Township/Range:", meridian_town_range],
|
430
|
+
["Brief Legal:", @sub[:legal_description]],
|
431
|
+
["Tax Parcel ID(s):", parcel_nos],
|
432
|
+
["RE Taxes/ $/Acre:", re_tax_string],
|
433
|
+
["Assessed Value of Land:", @sub[:total_assess_value]],
|
434
|
+
["Current Real Estate Taxes", @sub[:total_RET]],
|
435
|
+
["Total Number of Acres:", @number_acres],
|
436
|
+
["Land Use Zone and Allowed Uses:", "#{@sub[:land_use_zone]}, #{@sub[:allowed_uses_and_limitations]}"],
|
437
|
+
["Does property conform to zoning?:", @sub[:conf_type]],
|
438
|
+
["Is Property located in Flood Zone/Wetland?:", "#{@sub[:flood_zone]} #{@sub[:wetlands]}"],
|
439
|
+
["Is Property currently listed, under contract? If property has sold in prior 3 years see Transaction History table below.", "#{@sub[:under_purchase_agr]}, #{@sub[:listed_for_sale]}"],
|
440
|
+
["Does Property have Legal Access? How?:", "#{@sub[:has_legal_access]} / #{@sub[:legal_access]}"],
|
441
|
+
["Does the property have Physical Access? How?:", "#{@sub[:has_physical_access]} / #{@sub[:physical_access]}"],
|
442
|
+
["Easements, ROW or Encroachments:", @sub[:easements_description]]
|
443
|
+
]
|
444
|
+
|
445
|
+
table(identification_data) do
|
446
|
+
columns(0..1).width = 170
|
447
|
+
cells.style(border_width: 0)
|
448
|
+
cells.padding = [1, 2.5]
|
449
|
+
row(0).style(align: :center, font_style: :bold, border_bottom_width: 0.5)
|
450
|
+
column(0).style(align: :right)
|
451
|
+
end
|
452
|
+
|
453
|
+
stroke_bounds
|
454
|
+
end
|
455
|
+
|
456
|
+
bounding_box([340, 645], height: 300, width: 200) do
|
457
|
+
neighborhood_data = [
|
458
|
+
[{content: "Neighborhood Information", colspan: 2}],
|
459
|
+
["Land Use North:", @sub[:north_land]],
|
460
|
+
["Land Use South:", @sub[:south_land]],
|
461
|
+
["Land Use East:", @sub[:east_land]],
|
462
|
+
["Land Use West:", @sub[:west_land]],
|
463
|
+
[{content: "Comments - Distance to Services, Farm to Market, etc.:", colspan: 2}],
|
464
|
+
[{content: "#{@sub[:SWOT_analysis1]}", colspan: 2}]
|
465
|
+
]
|
466
|
+
|
467
|
+
table(neighborhood_data) do
|
468
|
+
cells.style(border_width: 0)
|
469
|
+
cells.padding = [1, 2.5]
|
470
|
+
row(0).style(align: :center, font_style: :bold, border_bottom_width: 0.5)
|
471
|
+
column(0).style(border_right_width: 0.5)
|
472
|
+
column(0).width = 80
|
473
|
+
column(1).width = 120
|
474
|
+
end
|
475
|
+
|
476
|
+
stroke_horizontal_rule
|
477
|
+
text "Economics and Demographics", align: :center, style: :bold
|
478
|
+
stroke_horizontal_rule
|
479
|
+
move_down 3
|
480
|
+
text "Pertinent Local Economic Factors including a description of current supply and
|
481
|
+
demand of similar property types and commodities produced. Included influences on value."
|
482
|
+
stroke_horizontal_rule
|
483
|
+
move_down 3
|
484
|
+
text "#{@sub[:SWOT_analysis2]}"
|
485
|
+
|
486
|
+
stroke_bounds
|
487
|
+
end
|
488
|
+
|
489
|
+
# Property Description Table Header
|
490
|
+
move_down 4
|
491
|
+
text 'Property Description', align: :center, style: :bold
|
492
|
+
|
493
|
+
|
494
|
+
# bounding box for left table under property description section
|
495
|
+
bounding_box([0, 330], height: 230, width: 270) do
|
496
|
+
inclusions = @sub[:inclusions]
|
497
|
+
if inclusions
|
498
|
+
incl_string = inclusions.join(", ")
|
499
|
+
else
|
500
|
+
incl_string = ""
|
501
|
+
end
|
502
|
+
|
503
|
+
# getting primary and secondary land classes by index
|
504
|
+
if @sub[:landclassifications] && @sub[:landclassifications].any?
|
505
|
+
num_primary = no_nil_number(@sub[:landclassifications][0][:numacres])
|
506
|
+
|
507
|
+
if @sub[:landclassifications][1]
|
508
|
+
num_secondary = no_nil_number(@sub[:landclassifications][1][:numacres])
|
509
|
+
secondary_land_type = @sub[:landclassifications][1][:landclass]
|
510
|
+
else
|
511
|
+
num_secondary = 0
|
512
|
+
end
|
513
|
+
else
|
514
|
+
num_primary = 0
|
515
|
+
num_secondary = 0
|
516
|
+
end
|
517
|
+
|
518
|
+
# getting primary and secondary commodities by index
|
519
|
+
if @sub[:estimatedproductivity] && @sub[:estimatedproductivity].any?
|
520
|
+
primary_commodity = "#{@sub[:estimatedproductivity][0][:commodity]}"
|
521
|
+
commodity_num_primary = no_nil_number(@sub[:estimatedproductivity][0][:estmtdyield])
|
522
|
+
|
523
|
+
if @sub[:estimatedproductivity][1]
|
524
|
+
secondary_commodity = "#{@sub[:estimatedproductivity][1][:commodity]}"
|
525
|
+
commodity_num_secondary = no_nil_number(@sub[:estimatedproductivity][1][:estmtdyield])
|
526
|
+
else
|
527
|
+
commodity_num_secondary = 0
|
528
|
+
secondarycommodity = "None"
|
529
|
+
end
|
530
|
+
|
531
|
+
else
|
532
|
+
commodity_num_primary = 0
|
533
|
+
commodity_num_secondary = 0
|
534
|
+
secondary_commodity = "None"
|
535
|
+
primary_commodity = "None"
|
536
|
+
end
|
537
|
+
|
538
|
+
# conditional strings
|
539
|
+
is_encumbered = @sub[:occupancy] == "leased" || @sub[:occupancy] = "partially leased" ? "Yes" : "No"
|
540
|
+
end_of_lease = @sub[:lease_data] && @sub[:lease_data].any? ? @sub[:lease_data][0][:endLeaseDate] : "NA"
|
541
|
+
|
542
|
+
if @sub[:inclusions]
|
543
|
+
has_improvs = (@sub[:inclusions] & ["Improved with non-Ag Use Improvements",
|
544
|
+
"Improved with Ag Use Improvements",
|
545
|
+
"Improved with residence"]).present?
|
546
|
+
improvs_string = has_improvs ? "See Improvements Table" : "No"
|
547
|
+
else
|
548
|
+
improvs_string = "No"
|
549
|
+
end
|
550
|
+
|
551
|
+
# calculated strings
|
552
|
+
income = Money.new(no_nil_number(@sub[:eff_gross_income]) * 100, 'USD')
|
553
|
+
expense = Money.new(no_nil_number(@sub[:total_expenses]) * 100, 'USD')
|
554
|
+
noi = income - expense
|
555
|
+
noi_string = noi.format(no_cents: :true)
|
556
|
+
expense_ratio = "#{((expense / income) * 100).round(2)}" + "%"
|
557
|
+
|
558
|
+
description_data2 = [
|
559
|
+
["Effective Unit Size/Acres:", "#{@sub[:num_of_units]}"],
|
560
|
+
["Current Land Use", "See General Comments"],
|
561
|
+
["Historic Land Use:", "See General Comments"],
|
562
|
+
["Intended Future use by Borrower:", "#{@sub[:change_of_use]}"],
|
563
|
+
["Occupancy:", "#{@sub[:occupancy]}"],
|
564
|
+
["What does this property include?:", incl_string],
|
565
|
+
["Primary Agricultural Land Use:", "#{@sub[:primary_ag_use]}"],
|
566
|
+
["Primary Agricultural Land Use Acres:", num_primary],
|
567
|
+
["Primary Commodity:", primary_commodity],
|
568
|
+
["Primary Ag Commodity Est. Productivity Yield:", commodity_num_primary],
|
569
|
+
["Secondary Agricultural Land Class:", secondary_land_type],
|
570
|
+
["Secondary Agricultural Land Use Acres:", num_secondary],
|
571
|
+
["Secondary Commodity:", secondary_commodity],
|
572
|
+
["Secondary Ag Commodity Est. Productivity Yield:", commodity_num_secondary],
|
573
|
+
["Is subject encumbered by a current lease?:", is_encumbered],
|
574
|
+
["Lease Structure:", "#{@sub[:type_of_lease]}"],
|
575
|
+
["Lease Term:", end_of_lease],
|
576
|
+
["NOI Projected Income from Rent:", noi_string],
|
577
|
+
["Expense Ratio:", expense_ratio],
|
578
|
+
["Does the subject have Building Improvements?:", improvs_string]
|
579
|
+
]
|
580
|
+
|
581
|
+
table(description_data2) do
|
582
|
+
cells.style(border_width: 0)
|
583
|
+
cells.padding = [1, 2.5]
|
584
|
+
column(0).style(border_right_width: 0.5, align: :right)
|
585
|
+
column(0..1).width = 135
|
586
|
+
end
|
587
|
+
|
588
|
+
stroke_bounds
|
589
|
+
end
|
590
|
+
|
591
|
+
# bounding box for right table under property description section
|
592
|
+
bounding_box([270, 330], height: 230, width: 270) do
|
593
|
+
|
594
|
+
if @sub[:perm_plantings] && @sub[:perm_plantings].any?
|
595
|
+
has_perm_plants = "Yes"
|
596
|
+
else
|
597
|
+
has_perm_plants = "No"
|
598
|
+
end
|
599
|
+
|
600
|
+
if @sub[:crops] && @sub[:crops].any?
|
601
|
+
has_crops = "Yes"
|
602
|
+
else
|
603
|
+
has_crops = "No"
|
604
|
+
end
|
605
|
+
|
606
|
+
description_data = [
|
607
|
+
["Infrastructure-Farming Practice:", "#{@sub[:farming_practices]}"],
|
608
|
+
["Predominant Soils Types:", "See Comments Below"],
|
609
|
+
["Dominant Soils Capability Class:", "#{@sub[:soils]}"],
|
610
|
+
["Corn Suitability Rating (NRCS):", "#{@sub[:CSR2]}"],
|
611
|
+
["Average Annual Precipitation:", "#{@sub[:avg_precipitation]}"],
|
612
|
+
["Average Growing Season:", "#{@sub[:growing_season]}"],
|
613
|
+
["Elevation:", "#{@sub[:elevation]}"],
|
614
|
+
["Predominant Slope:", "#{@sub[:topography]}"],
|
615
|
+
["Does property have water rights?:", "#{@sub[:any_water_rights]}"],
|
616
|
+
["Annual Water Cost/Irrigated Acre:", "#{moneymaker(@sub[:irrig_cost_per_acre], false)}"],
|
617
|
+
["Does the property have a water distribution system?", "stubbed"],
|
618
|
+
["Annual Pumping Cost/Irrigated Acre:", "#{moneymaker(@sub[:pumping_cost_per_acre], false)}"],
|
619
|
+
["Does the property have Permanent Plantings?", has_perm_plants],
|
620
|
+
["Is a Crop Insurance Yield Report Available?", has_crops],
|
621
|
+
[{content: "Soils, Water, Distribution System, Permanent Planting Comments", colspan: 2}],
|
622
|
+
[{content: "#{@sub[:soils]} #{@sub[:accessibility]} #{@sub[:mineral_rights]} #{@sub[:water_rights_comment]} #{@sub[:water_distribution_comment]}", colspan: 2}]
|
623
|
+
]
|
624
|
+
|
625
|
+
table(description_data) do
|
626
|
+
cells.style(border_width: 0)
|
627
|
+
cells.padding = [1, 2.5]
|
628
|
+
column(0).style(border_right_width: 0.5, align: :right)
|
629
|
+
row(-2).style(align: :center, border_bottom_width: 0.5, border_top_width: 0.5)
|
630
|
+
row(-1).style(align: :right)
|
631
|
+
|
632
|
+
end
|
633
|
+
|
634
|
+
stroke_bounds
|
635
|
+
end
|
636
|
+
move_down 3
|
637
|
+
text "General Comments - Subject Property", align: :center, style: :bold
|
638
|
+
stroke_horizontal_rule
|
639
|
+
move_down 3
|
640
|
+
|
641
|
+
comment_proc = Proc.new do |k|
|
642
|
+
if k
|
643
|
+
text "#{k}"
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
647
|
+
comment_proc.call(@sub[:directions_or_ownership_comments])
|
648
|
+
comment_proc.call(@sub[:development_potential])
|
649
|
+
comment_proc.call(@sub[:general_comments])
|
650
|
+
comment_proc.call(@sub[:listing_comments])
|
651
|
+
comment_proc.call(@sub[:lease_comments])
|
652
|
+
comment_proc.call(@sub[:foo])
|
653
|
+
comment_proc.call(@sub[:foo])
|
654
|
+
comment_proc.call(@sub[:income_comments])
|
655
|
+
comment_proc.call(@sub[:problem_descr])
|
656
|
+
comment_proc.call(@sub[:hazard_descr])
|
657
|
+
comment_proc.call(@sub[:env_problem_descr])
|
658
|
+
comment_proc.call(@sub[:windgen_comment])
|
659
|
+
|
660
|
+
start_new_page
|
661
|
+
font_size 11 # change fontsize back to default
|
662
|
+
end
|
663
|
+
|
664
|
+
def property_features # container method to create various tables
|
665
|
+
font_size 6
|
666
|
+
transaction_history
|
667
|
+
utilities
|
668
|
+
improvements
|
669
|
+
water_rights
|
670
|
+
water_distribution
|
671
|
+
|
672
|
+
start_new_page
|
673
|
+
|
674
|
+
crop_yield
|
675
|
+
perm_plantings
|
676
|
+
externalities
|
677
|
+
|
678
|
+
start_new_page
|
679
|
+
font_size 11
|
680
|
+
end
|
681
|
+
|
682
|
+
|
683
|
+
def value_intro
|
684
|
+
header("VALUATION PROCESS")
|
685
|
+
move_down 25
|
686
|
+
text "VALUATION PROCESS", size: 14, style: :bold
|
687
|
+
move_down 20
|
688
|
+
text "#{@text_blocks[:valuation_process]}"
|
689
|
+
start_new_page
|
690
|
+
end
|
691
|
+
|
692
|
+
def comp_methodology
|
693
|
+
header("DIRECT COMPARISON METHODOLOGY")
|
694
|
+
move_down 25
|
695
|
+
text "ESTIMATE OF VALUE BY DIRECT COMPARISON METHODOLOGY", size: 14, style: :bold
|
696
|
+
move_down 20
|
697
|
+
text "#{@text_blocks[:comp_method]}"
|
698
|
+
start_new_page
|
699
|
+
end
|
700
|
+
|
701
|
+
def property_comparison
|
702
|
+
header("DIRECT COMPARISON ANALYSIS")
|
703
|
+
move_down 25
|
704
|
+
font_size 6
|
705
|
+
|
706
|
+
table(flip_comp_array) do
|
707
|
+
column(0).width = 85
|
708
|
+
columns(1..7).width = 65
|
709
|
+
cells.padding = [1, 2.5]
|
710
|
+
columns(1..7).style(align: :center)
|
711
|
+
end
|
712
|
+
start_new_page
|
713
|
+
font_size 11
|
714
|
+
end
|
715
|
+
|
716
|
+
def discussion_of_sales
|
717
|
+
header("DIRECT COMPARISON ANALYSIS")
|
718
|
+
|
719
|
+
discussion_data = [
|
720
|
+
["Subject", "Sale 1", "Sale 2", "Sale 3", "Sale 4", "Sale 5", "Sale 6"]
|
721
|
+
]
|
722
|
+
|
723
|
+
sale_discussions = ["N/A"]
|
724
|
+
@comps.each do |c|
|
725
|
+
c_string = "#{c[:directions_or_ownership_comments]}\n\n" << "#{c[:allowed_uses_and_limitations]}\n\n"
|
726
|
+
c_string << "#{c[:development_potential]}\n\n" << "#{c[:comments_on_floodways]}\n\n" << "#{c[:sale_adjustment_comments]}\n\n"
|
727
|
+
c_string << "#{c[:general_comments]}\n\n" << "#{c[:atmarket_comments]}\n\n" << "#{c[:listing_comments]}\n\n"
|
728
|
+
c_string << "#{c[:lease_comments]}\n\n" << "#{c[:change_of_use]}\n\n" << "#{c[:water_rights_comment]}\n\n"
|
729
|
+
c_string << "#{c[:water_distribution_comment]}\n\n" << "#{c[:accessibility]}\n\n" << "#{c[:easements_description]}\n\n"
|
730
|
+
c_string << "#{c[:elevation]}\n\n" << "#{c[:property_improvement_comments]}\n\n" << "#{c[:income_comments]}"
|
731
|
+
|
732
|
+
# build on sub-array
|
733
|
+
sale_discussions << c_string
|
734
|
+
end
|
735
|
+
|
736
|
+
# push subarray to main table array
|
737
|
+
discussion_data << sale_discussions
|
738
|
+
|
739
|
+
table(discussion_data) do
|
740
|
+
cells.padding = [1, 2.5]
|
741
|
+
columns(0..6).width = 77
|
742
|
+
row(0).style(align: :center, background_color: 'd7d7d7')
|
743
|
+
cells.style(border_width: 0)
|
744
|
+
columns(0..6).style(border_right_width: 0.5)
|
745
|
+
end
|
746
|
+
|
747
|
+
start_new_page
|
748
|
+
end
|
749
|
+
|
750
|
+
def ag_sales_map
|
751
|
+
header("AGRICULTURE SALES LOCATION MAP")
|
752
|
+
move_down 50
|
753
|
+
if @images && @images[:ag_sales_map]
|
754
|
+
image "#{@images[:ag_sales_map]}", width: 500, align: :center
|
755
|
+
else
|
756
|
+
text 'No Image'
|
757
|
+
end
|
758
|
+
|
759
|
+
start_new_page
|
760
|
+
end
|
761
|
+
|
762
|
+
def val_method_and_recon
|
763
|
+
header("FINAL VALUE INDICATION")
|
764
|
+
move_down 25
|
765
|
+
text "Valuation Methodology Review and Reconciliation", size: 14, style: :bold
|
766
|
+
move_down 20
|
767
|
+
text @text_blocks[:val_method]
|
768
|
+
move_down 10
|
769
|
+
text "The previous analysis indicated the following:"
|
770
|
+
move_down 10
|
771
|
+
|
772
|
+
parallel_text("Average Primary Land Value/Unit", "#{average_primary_land_val(@recon_primary_per_acre).format(no_cents: true)}", 200)
|
773
|
+
move_down 20
|
774
|
+
parallel_text("Median Primary Land Value/Unit", "#{median_primary_land_val(@recon_primary_per_acre).format(no_cents: true)}", 200)
|
775
|
+
move_down 20
|
776
|
+
parallel_text("Maximum Primary Land Value/Unit", "#{maximum_primary_land_val(@recon_primary_per_acre).format(no_cents: true)}", 200)
|
777
|
+
move_down 20
|
778
|
+
parallel_text("Minimum Primary Land Value/Unit", "#{minimum_primary_land_val(@recon_primary_per_acre).format(no_cents: true)}", 200)
|
779
|
+
move_down 20
|
780
|
+
parallel_text("Unit of Comparison", "$/Acre", 200)
|
781
|
+
move_down 20
|
782
|
+
parallel_text("Indicated Value per Unit", "stubbed", 200)
|
783
|
+
move_down 20
|
784
|
+
parallel_text("Indicated Primary Land Value/Unit", "stubbed", 200)
|
785
|
+
move_down 20
|
786
|
+
parallel_text("Indicated Secondary Land Value/Unit", "stubbed", 200)
|
787
|
+
move_down 20
|
788
|
+
parallel_text("Improvement Value Allocation", "stubbed", 200)
|
789
|
+
move_down 20
|
790
|
+
parallel_text("Overall Indicated Value", "stubbed", 200)
|
791
|
+
move_down 20
|
792
|
+
parallel_text("SAY", "stubbed", 200)
|
793
|
+
start_new_page
|
794
|
+
end
|
795
|
+
|
796
|
+
def assumptions_and_conditions
|
797
|
+
header("ASSUMPTIONS AND LIMITING CONDITIONS")
|
798
|
+
move_down 25
|
799
|
+
text "ASSUMPTIONS AND LIMITING CONDITIONS", size: 14, style: :bold
|
800
|
+
move_down 20
|
801
|
+
text "#{@text_blocks[:assumptions_conditions]}", style: :bold
|
802
|
+
move_down 20
|
803
|
+
text "Evaluators Associated with this Evaluation Report are identified as follows:"
|
804
|
+
text "#{@sub[:validentification]}"
|
805
|
+
start_new_page
|
806
|
+
end
|
807
|
+
|
808
|
+
def addenda_contents
|
809
|
+
header("ADDENDA CONTENTS")
|
810
|
+
move_down 25
|
811
|
+
text "ADDENDA CONTENTS", size: 14, style: :bold
|
812
|
+
start_new_page
|
813
|
+
end
|
814
|
+
|
815
|
+
def addendum_a
|
816
|
+
header("ENGAGEMENT LETTER")
|
817
|
+
move_down 25
|
818
|
+
text "ADDENDUM A", size: 14, style: :bold
|
819
|
+
start_new_page
|
820
|
+
end
|
821
|
+
|
822
|
+
def addendum_b
|
823
|
+
header("LEGAL DESCRIPTION")
|
824
|
+
move_down 25
|
825
|
+
text "ADDENDUM B", size: 14, style: :bold
|
826
|
+
# end of document
|
827
|
+
end
|
828
|
+
|
829
|
+
def header(page_title)
|
830
|
+
text "#{page_title} " << "#{page_count - 1}", align: :right
|
831
|
+
stroke_horizontal_rule
|
832
|
+
end
|
833
|
+
|
834
|
+
def flip_comp_array # necessary to produce 2D array of comps side by side
|
835
|
+
props = [@sub, @comps].compact.flatten
|
836
|
+
final_a = [
|
837
|
+
[{content: 'Valuation Analysis - Sales Comparison Approach', colspan: 8}], # [0]
|
838
|
+
['Characteristic', 'Subject', 'Sale 1', 'Sale 2', 'Sale 3', 'Sale 4', 'Sale 5', 'Sale 6'], # [1]
|
839
|
+
['Record No.'], ['Tax Parcel #(s)'], ['Address'], ['City'], ['State'], ['Zip Code'], ['Sale Date'], ['Sale Price'], # [2] -> [9]
|
840
|
+
['Conditions of Sale'], ['Adjusted Sale Price'], ['Property Rights Conveyed'], ['Unit of Comparison'], # [10 -> 13]
|
841
|
+
['Price/Unit'], ['Total Acres'], ['Primary Land Use'], ['No. Units - Acres'], ['$/Unit - Primary Land'], # [14 -> 18]
|
842
|
+
['Secondary Land Use'], ['No. Units - Acres'], ['$/Unit - Secondary Land'], # [19 -> 21]
|
843
|
+
['$/Unit Allocated to Improvements'], ['Physical Access'], ['Legal Access'], # [22 -> 24]
|
844
|
+
['Topography'], ['Rainfal'], ['Primary Crop'], ['Yield'], ['Cap Rate'], [''], # [25 -> 30]
|
845
|
+
['% Primary Land'], [''], ['Deed Instrument No.'] # [31 -> 33]
|
846
|
+
]
|
847
|
+
|
848
|
+
props.each do |p|
|
849
|
+
final_a[2].push(p[:sequence]) # record number
|
850
|
+
|
851
|
+
taxes = p[:taxes]
|
852
|
+
if taxes && taxes.any?
|
853
|
+
t_s = taxes.inject("") {|memo_s, t| memo_s << "#{t[:tax_parcel_no]}, "; memo_s }
|
854
|
+
else
|
855
|
+
t_s = ""
|
856
|
+
end
|
857
|
+
|
858
|
+
final_a[3].push(t_s) # tax parcels
|
859
|
+
final_a[4].push("#{p[:property_address_number]} " << "#{p[:street_or_road_name]}") # address
|
860
|
+
final_a[5].push(p[:city]) # city
|
861
|
+
final_a[6].push("#{p[:county_state]}".slice(-2..-1)) # state
|
862
|
+
final_a[7].push(p[:zip_code]) # zip
|
863
|
+
final_a[8].push(datemaker(p[:sale_date])) # sale date
|
864
|
+
final_a[9].push(moneymaker(p[:sale_price],false)) # sale price
|
865
|
+
final_a[10].push(moneymaker(p[:sale_adjustment],false)) # conditions of sale
|
866
|
+
final_a[11].push(moneymaker(p[:cesaleprice],false)) # adjusted sale price
|
867
|
+
final_a[12].push(p[:property_rights]) # property rights conveyed
|
868
|
+
final_a[13].push(p[:unit]) # unit of comparison
|
869
|
+
final_a[14].push(moneymaker(p[:cesaleunitprice],false)) # price/unit
|
870
|
+
final_a[15].push(p[:num_of_units]) # total acres
|
871
|
+
final_a[16].push(p[:primary_ag_use]) # primary land use
|
872
|
+
|
873
|
+
if p[:landclassifications] && p[:landclassifications].any?
|
874
|
+
units_primary = p[:landclassifications][0][:numacres]
|
875
|
+
units_secondary = p[:landclassifications][1][:numacres]
|
876
|
+
|
877
|
+
primary_per_acre = moneymaker(p[:landclassifications][0][:priceperacre], false)
|
878
|
+
if p[:landclassifications][1]
|
879
|
+
secondary_per_acre = moneymaker(p[:landclassifications][1][:priceperacre], false)
|
880
|
+
else
|
881
|
+
secondary_per_acre = 0
|
882
|
+
end
|
883
|
+
else
|
884
|
+
units_primary = 0
|
885
|
+
units_secondary = 0
|
886
|
+
end
|
887
|
+
|
888
|
+
@recon_primary_per_acre << primary_per_acre.to_f unless primary_per_acre == 0
|
889
|
+
|
890
|
+
percent_primary = p[:num_of_units] ? ((units_primary * 100) / p[:num_of_units]) : 0
|
891
|
+
|
892
|
+
final_a[17].push(units_primary) # no. units
|
893
|
+
final_a[18].push(primary_per_acre) # $/unit - primary
|
894
|
+
final_a[19].push(p[:secondary_ag_use]) # secondary land use
|
895
|
+
final_a[20].push(units_secondary) # no. units - acres
|
896
|
+
final_a[21].push(secondary_per_acre) # $/unit - secondary
|
897
|
+
|
898
|
+
|
899
|
+
expenses_per_unit = p[:num_of_units] ? (Money.new(no_nil_number(p[:total_expenses]) * 100, 'USD') / p[:num_of_units]).format(no_cents: true) : 0
|
900
|
+
|
901
|
+
final_a[22].push(expenses_per_unit) # $/unit allocated to improvements
|
902
|
+
final_a[23].push("#{p[:has_physical_access]} " << "#{p[:physical_access]}") # physical access
|
903
|
+
final_a[24].push("#{p[:has_legal_access]} " << "#{p[:legal_access]}") # legal access
|
904
|
+
final_a[25].push(p[:topography]) # topography
|
905
|
+
final_a[26].push(p[:avg_precipitation]) # rainfall
|
906
|
+
|
907
|
+
if p[:estimatedproductivity] && p[:estimatedproductivity].any?
|
908
|
+
primary_commodity = "#{p[:estimatedproductivity][0][:commodity]}"
|
909
|
+
commodity_num_primary = no_nil_number(p[:estimatedproductivity][0][:estmtdyield])
|
910
|
+
|
911
|
+
else
|
912
|
+
commodity_num_primary = 0
|
913
|
+
primary_commodity = "None"
|
914
|
+
end
|
915
|
+
|
916
|
+
final_a[27].push(primary_commodity) # primary crop
|
917
|
+
final_a[28].push(commodity_num_primary) # yield
|
918
|
+
final_a[29].push("#{p[:overall_capitalization_rate]}%") # cap rate
|
919
|
+
# [30] is a blank line
|
920
|
+
final_a[31].push("#{percent_primary}%") # % primary land
|
921
|
+
# [32] is a blank line
|
922
|
+
final_a[33].push(p[:public_rec_ref_number]) # deed instrument no.
|
923
|
+
end
|
924
|
+
|
925
|
+
return final_a
|
926
|
+
|
927
|
+
end
|
928
|
+
|
929
|
+
# table methods for the property_features_method
|
930
|
+
def transaction_history
|
931
|
+
bounding_box([0, 700], height: 135, width: 540) do
|
932
|
+
transaction_history_data = [
|
933
|
+
[{content: "Transaction History", colspan: 4}],
|
934
|
+
["Historic Transaction Type", "Transaction Description", "Date", "Sale Price, List Price, or List Price"]
|
935
|
+
]
|
936
|
+
|
937
|
+
transactions = @sub[:historyrecords]
|
938
|
+
|
939
|
+
if transactions # node could be nil
|
940
|
+
transactions.each do |t|
|
941
|
+
if t # array could be nil
|
942
|
+
transaction_history_data.push(
|
943
|
+
[t[:transType], t[:transDescr], datemaker(t[:transDate]), moneymaker(t[:price], true)]
|
944
|
+
)
|
945
|
+
end
|
946
|
+
end
|
947
|
+
end
|
948
|
+
|
949
|
+
table(transaction_history_data) do
|
950
|
+
columns(0..3).width = 135
|
951
|
+
columns(0..3).style(align: :right, font_style: :bold)
|
952
|
+
cells.padding = [1, 2.5]
|
953
|
+
cells.style(border_width: 0)
|
954
|
+
row(0).style(align: :center, background_color: 'd7d7d7', font_size: 8, font_style: :bold)
|
955
|
+
row(1).style(border_bottom_width: 0.5, font_style: nil)
|
956
|
+
end
|
957
|
+
stroke_bounds
|
958
|
+
end
|
959
|
+
end
|
960
|
+
|
961
|
+
def utilities
|
962
|
+
bounding_box([0, 565], height: 120, width: 540) do
|
963
|
+
utilities_data = [
|
964
|
+
[{content: "Description of Utilities", colspan: 4}],
|
965
|
+
["Utility Description", "Service Availability", "Service Provider", "Comments"]
|
966
|
+
]
|
967
|
+
|
968
|
+
utilities = @sub[:utilities]
|
969
|
+
if utilities # node could be nil
|
970
|
+
utilities.each do |u|
|
971
|
+
if u # array could be empty
|
972
|
+
utilities_data.push(
|
973
|
+
[u[:description], u[:availbility], u[:provider], u[:comments]]
|
974
|
+
)
|
975
|
+
end
|
976
|
+
end
|
977
|
+
end
|
978
|
+
|
979
|
+
table(utilities_data) do
|
980
|
+
columns(0..3).width = 135
|
981
|
+
columns(0..3).style(align: :right, font_style: :bold)
|
982
|
+
cells.padding = [1, 2.5]
|
983
|
+
cells.style(border_width: 0)
|
984
|
+
row(0).style(align: :center, background_color: 'd7d7d7', font_size: 8, font_style: :bold)
|
985
|
+
row(1).style(border_bottom_width: 0.5, font_style: nil)
|
986
|
+
end
|
987
|
+
stroke_bounds
|
988
|
+
end
|
989
|
+
# no new page
|
990
|
+
end
|
991
|
+
|
992
|
+
def improvements
|
993
|
+
bounding_box([0, 445], height: 220, width: 540) do
|
994
|
+
|
995
|
+
improvements_array = @sub[:improvements]
|
996
|
+
|
997
|
+
sorted_array = flip_improvements_array(improvements_array)
|
998
|
+
|
999
|
+
table(sorted_array) do
|
1000
|
+
columns(0..7).width = 67.5
|
1001
|
+
columns(1..7).style(font_style: :bold)
|
1002
|
+
row(0).style(align: :center, background_color: 'd7d7d7', font_size: 8, font_style: :bold)
|
1003
|
+
cells.padding = [1, 2.5]
|
1004
|
+
cells.style(border_width: 0, font_size: 6)
|
1005
|
+
row(1).style(border_bottom_width: 0.5, font_style: nil)
|
1006
|
+
end
|
1007
|
+
stroke_bounds
|
1008
|
+
end
|
1009
|
+
# no new page
|
1010
|
+
end
|
1011
|
+
|
1012
|
+
def water_rights
|
1013
|
+
bounding_box([0, 225], height: 115, width: 540) do
|
1014
|
+
|
1015
|
+
water_rights_data = [
|
1016
|
+
[{content: "Water Rights", colspan: 8}],
|
1017
|
+
["Water Right No.", "Water Right", "Water Source", "Priority Date", "Beneficial Use", "No. Acres Irrigated", "Annual Volume Ac-Ft", "Period of Use"]
|
1018
|
+
]
|
1019
|
+
|
1020
|
+
rights = @sub[:waterrights]
|
1021
|
+
if rights # node could be nil
|
1022
|
+
rights.each do |r|
|
1023
|
+
if r # array could be empty
|
1024
|
+
water_rights_data.push(
|
1025
|
+
[r[:waterrightNum], r[:waterRight], r[:waterSrc], datemaker(r[:priorityDate]), r[:purpose], r[:numIrrAcres], r[:annVolume]]
|
1026
|
+
)
|
1027
|
+
end
|
1028
|
+
end
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
table(water_rights_data) do
|
1032
|
+
columns(0..7).width = 67.5
|
1033
|
+
columns(0..7).style(font_style: :bold)
|
1034
|
+
row(0).style(align: :center, background_color: 'd7d7d7', font_size: 8, font_style: :bold)
|
1035
|
+
cells.padding = [1, 2.5]
|
1036
|
+
cells.style(border_width: 0)
|
1037
|
+
row(1).style(border_bottom_width: 0.5, font_style: nil)
|
1038
|
+
end
|
1039
|
+
|
1040
|
+
stroke_bounds
|
1041
|
+
end
|
1042
|
+
# no new page
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
def water_distribution
|
1046
|
+
bounding_box([0, 110], height: 110, width: 540) do
|
1047
|
+
|
1048
|
+
distribution_data = [
|
1049
|
+
[{content: "Water Distribution System", colspan: 8}],
|
1050
|
+
["Water Distrib. Equip.", "Manuf.", "Make/Brand", "Type", "Description", "Yr. Manufactured", "Remaining Ec. Life", "No. Acres Irrigated"]
|
1051
|
+
]
|
1052
|
+
|
1053
|
+
distributions = @sub[:waterdistributions]
|
1054
|
+
|
1055
|
+
if distributions # node could be nil
|
1056
|
+
distributions.each do |d|
|
1057
|
+
if d # array could be empty
|
1058
|
+
distribution_data.push(
|
1059
|
+
[d[:waterdistrEq], d[:manufacturer], d[:brand], d[:eqType], d[:descr], d[:yearManuf], d[:remainingEcLife], d[:irrAcres]]
|
1060
|
+
)
|
1061
|
+
end
|
1062
|
+
end
|
1063
|
+
end
|
1064
|
+
|
1065
|
+
table(distribution_data) do
|
1066
|
+
columns(0..7).width = 67.5
|
1067
|
+
columns(0..7).style(font_style: :bold)
|
1068
|
+
row(0).style(align: :center, background_color: 'd7d7d7', font_size: 8, font_style: :bold)
|
1069
|
+
cells.padding = [1, 2.5]
|
1070
|
+
cells.style(border_width: 0)
|
1071
|
+
row(1).style(border_bottom_width: 0.5, font_style: nil)
|
1072
|
+
end
|
1073
|
+
|
1074
|
+
stroke_bounds
|
1075
|
+
end
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
def crop_yield
|
1079
|
+
bounding_box([0, 700], height: 100, width: 540) do
|
1080
|
+
|
1081
|
+
crops = @sub[:crops]
|
1082
|
+
|
1083
|
+
crop_data = [
|
1084
|
+
[{content: "Crop Yield Summary", colspan: 7}],
|
1085
|
+
["Crop Year", "Commodity Identified", "Unit of Measure", "Average Yield", " ", " ", ", "]
|
1086
|
+
]
|
1087
|
+
|
1088
|
+
if crops # node could be nil
|
1089
|
+
crops.each do |c|
|
1090
|
+
if c # array could be empty
|
1091
|
+
crop_data.push(
|
1092
|
+
[c[:year], c[:commodity], c[:unit], c[:avgyield]]
|
1093
|
+
)
|
1094
|
+
end
|
1095
|
+
end
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
table(crop_data) do
|
1099
|
+
column(0).width = 135
|
1100
|
+
columns(1..6).width = 67.5
|
1101
|
+
columns(0..6).style(font_style: :bold)
|
1102
|
+
row(0).style(align: :center, background_color: 'd7d7d7', font_size: 8, font_style: :bold)
|
1103
|
+
cells.padding = [1, 2.5]
|
1104
|
+
cells.style(border_width: 0)
|
1105
|
+
row(1).style(border_bottom_width: 0.5, font_style: nil)
|
1106
|
+
end
|
1107
|
+
stroke_bounds
|
1108
|
+
end
|
1109
|
+
end
|
1110
|
+
|
1111
|
+
def perm_plantings
|
1112
|
+
bounding_box([0, 600], height: 150, width: 540) do
|
1113
|
+
planting_data = [
|
1114
|
+
[{content: "Permanent Plantings", colspan: 8}],
|
1115
|
+
["Planting", "Variety", "Ac. Type", "No. of Acres", "Average Age", "Plants/Acre", "Unit Description", "Average Yield"]
|
1116
|
+
]
|
1117
|
+
|
1118
|
+
plantings = @sub[:plantings]
|
1119
|
+
|
1120
|
+
if plantings # node could be nil
|
1121
|
+
plantings.each do |p|
|
1122
|
+
if p # array could be empty
|
1123
|
+
planting_data.push(
|
1124
|
+
[p[:planting], p[:variety], p[:acres], p[:numacres], p[:avgage], p[:plantsacre], p[:unitdescr1], p[:avgproduction]]
|
1125
|
+
)
|
1126
|
+
end
|
1127
|
+
end
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
table(planting_data) do
|
1131
|
+
columns(0..7).width = 67.5
|
1132
|
+
columns(0..7).style(font_style: :bold)
|
1133
|
+
row(0).style(align: :center, background_color: 'd7d7d7', font_size: 8, font_style: :bold)
|
1134
|
+
cells.padding = [1, 2.5]
|
1135
|
+
cells.style(border_width: 0)
|
1136
|
+
row(1).style(border_bottom_width: 0.5, font_style: nil)
|
1137
|
+
end
|
1138
|
+
|
1139
|
+
stroke_bounds
|
1140
|
+
end
|
1141
|
+
end
|
1142
|
+
|
1143
|
+
def externalities
|
1144
|
+
bounding_box([0, 450], height: 350, width: 540) do
|
1145
|
+
|
1146
|
+
extern_data = ReportUtils.conditional_externs_array(@sub) # instance method to populate dynamic array
|
1147
|
+
table(extern_data) do
|
1148
|
+
columns(0..3).width = 135
|
1149
|
+
columns([1, 3]).style(font_style: :bold)
|
1150
|
+
row(0).style(align: :center, background_color: 'd7d7d7', font_size: 8, font_style: :bold)
|
1151
|
+
cells.padding = [1, 2.5]
|
1152
|
+
cells.style(border_width: 0)
|
1153
|
+
end
|
1154
|
+
|
1155
|
+
stroke_bounds
|
1156
|
+
end
|
1157
|
+
end
|
1158
|
+
|
1159
|
+
def image_cap(title)
|
1160
|
+
float do
|
1161
|
+
fill_color '24478F'
|
1162
|
+
fill_rectangle [120, cursor], 300, 20
|
1163
|
+
fill_color '000000'
|
1164
|
+
end
|
1165
|
+
move_down 4
|
1166
|
+
text "#{title}", align: :center, color: 'ffffff'
|
1167
|
+
end
|
1168
|
+
|
1169
|
+
def indicated_value_per_unit
|
1170
|
+
# stubbed
|
1171
|
+
end
|
1172
|
+
|
1173
|
+
def indicated_primary_land_per_unit
|
1174
|
+
# stubbed
|
1175
|
+
end
|
1176
|
+
|
1177
|
+
def indicated_secondary_land_per_unit
|
1178
|
+
# stubbed
|
1179
|
+
end
|
1180
|
+
|
1181
|
+
def improvement_val_alloc
|
1182
|
+
# stubbed
|
1183
|
+
end
|
1184
|
+
|
1185
|
+
def overall_val
|
1186
|
+
# stubbed
|
1187
|
+
end
|
1188
|
+
|
1189
|
+
def say_value
|
1190
|
+
# stubbed
|
1191
|
+
end
|
1192
|
+
end
|