|
| 1 | +# Configures a Prawn PDF template for generating Donation receipts |
| 2 | +class DonationPdf |
| 3 | + include Prawn::View |
| 4 | + include ItemsHelper |
| 5 | + |
| 6 | + class DonorInfo |
| 7 | + attr_reader :name, :address, :email |
| 8 | + |
| 9 | + def initialize(donation) |
| 10 | + if donation.nil? |
| 11 | + raise "Must pass a Donation object" |
| 12 | + end |
| 13 | + case donation.source |
| 14 | + when Donation::SOURCES[:donation_site] |
| 15 | + @name = donation.donation_site.name |
| 16 | + @address = donation.donation_site.address |
| 17 | + @email = donation.donation_site.email |
| 18 | + when Donation::SOURCES[:manufacturer] |
| 19 | + @name = donation.manufacturer.name |
| 20 | + @address = nil |
| 21 | + @email = nil |
| 22 | + when Donation::SOURCES[:product_drive] |
| 23 | + @name = donation.product_drive_participant.business_name |
| 24 | + @address = donation.product_drive_participant.address |
| 25 | + @email = donation.product_drive_participant.email |
| 26 | + when Donation::SOURCES[:misc] |
| 27 | + @name = "Misc. Donation" |
| 28 | + @address = nil |
| 29 | + @email = nil |
| 30 | + end |
| 31 | + end |
| 32 | + end |
| 33 | + |
| 34 | + def initialize(organization, donation) |
| 35 | + @donation = Donation.includes(line_items: [:item]).find_by(id: donation.id) |
| 36 | + @organization = organization |
| 37 | + @donor = DonorInfo.new(@donation) |
| 38 | + end |
| 39 | + |
| 40 | + def compute_and_render |
| 41 | + font_families["OpenSans"] = PrawnRails.config["font_families"][:OpenSans] |
| 42 | + font "OpenSans" |
| 43 | + font_size 10 |
| 44 | + |
| 45 | + logo_image = if @organization.logo.attached? |
| 46 | + StringIO.open(@organization.logo.download) |
| 47 | + else |
| 48 | + Organization::DIAPER_APP_LOGO |
| 49 | + end |
| 50 | + |
| 51 | + footer_height = 35 |
| 52 | + |
| 53 | + # Bounding box containing non-footer elements |
| 54 | + bounding_box [bounds.left, bounds.top], width: bounds.width, height: bounds.height - footer_height do |
| 55 | + image logo_image, fit: [250, 85] |
| 56 | + |
| 57 | + bounding_box [bounds.right - 225, bounds.top], width: 225, height: 85 do |
| 58 | + text @organization.name, align: :right |
| 59 | + text @organization.address, align: :right |
| 60 | + text @organization.email, align: :right |
| 61 | + end |
| 62 | + |
| 63 | + font_size 12 |
| 64 | + text "Issued on:", style: :bold |
| 65 | + text @donation.issued_at.to_fs(:distribution_date) |
| 66 | + move_up 24 |
| 67 | + |
| 68 | + font_size 12 |
| 69 | + text "Donation from:", style: :bold, align: :right |
| 70 | + font_size 10 |
| 71 | + text @donor.name, align: :right |
| 72 | + text @donor.address, align: :right |
| 73 | + text @donor.email, align: :right |
| 74 | + move_down 10 |
| 75 | + # Get some additional vertical distance in left column if all donor info is nil |
| 76 | + if @donor.name.nil? && @donor.address.nil? && @donor.email.nil? |
| 77 | + move_down 10 |
| 78 | + end |
| 79 | + |
| 80 | + font_size 12 |
| 81 | + money_raised = "$0.00" |
| 82 | + if @donation.money_raised && @donation.money_raised > 0 |
| 83 | + money_raised = dollar_value(@donation.money_raised) |
| 84 | + end |
| 85 | + text "<strong>Money Raised In Dollars: </strong>#{money_raised}", inline_format: true |
| 86 | + |
| 87 | + move_down 10 |
| 88 | + font_size 12 |
| 89 | + text "Comments:", style: :bold |
| 90 | + text @donation.comment |
| 91 | + |
| 92 | + move_down 20 |
| 93 | + |
| 94 | + data = donation_data |
| 95 | + |
| 96 | + hide_columns(data) |
| 97 | + hidden_columns_length = column_names_to_hide.length |
| 98 | + |
| 99 | + font_size 11 |
| 100 | + |
| 101 | + # Line item table |
| 102 | + table(data) do |
| 103 | + self.header = true |
| 104 | + self.cell_style = { |
| 105 | + padding: [5, 20, 5, 20] |
| 106 | + } |
| 107 | + self.row_colors = %w[dddddd ffffff] |
| 108 | + |
| 109 | + cells.borders = [] |
| 110 | + |
| 111 | + # Header row |
| 112 | + row(0).borders = [:bottom] |
| 113 | + row(0).border_width = 2 |
| 114 | + row(0).font_style = :bold |
| 115 | + row(0).size = 9 |
| 116 | + row(0).column(1..-1).borders = %i[bottom left] |
| 117 | + |
| 118 | + # Total Items footer row |
| 119 | + row(-1).borders = [:top] |
| 120 | + row(-1).font_style = :bold |
| 121 | + row(-1).column(1..-1).borders = %i[top left] |
| 122 | + row(-1).column(1..-1).border_left_color = "aaaaaa" |
| 123 | + |
| 124 | + # Footer spacing row |
| 125 | + row(-2).borders = [:top] |
| 126 | + row(-2).padding = [2, 0, 2, 0] |
| 127 | + |
| 128 | + column(0).width = 190 + (hidden_columns_length * 60) |
| 129 | + |
| 130 | + # Quantity column |
| 131 | + column(1..-1).row(1..-3).borders = [:left] |
| 132 | + column(1..-1).row(1..-3).border_left_color = "aaaaaa" |
| 133 | + column(1).style align: :right |
| 134 | + end |
| 135 | + end |
| 136 | + |
| 137 | + number_pages "Page <page> of <total>", |
| 138 | + start_count_at: 1, |
| 139 | + at: [bounds.right - 130, 22], |
| 140 | + align: :right |
| 141 | + |
| 142 | + repeat :all do |
| 143 | + # Page footer |
| 144 | + bounding_box [bounds.left, bounds.bottom + footer_height], width: bounds.width do |
| 145 | + stroke_bounds |
| 146 | + font "OpenSans" |
| 147 | + font_size 9 |
| 148 | + stroke_horizontal_rule |
| 149 | + move_down(5) |
| 150 | + |
| 151 | + logo_offset = (bounds.width - 190) / 2 |
| 152 | + bounding_box([logo_offset, 0], width: 190, height: 33) do |
| 153 | + text "Lovingly created with", valign: :center |
| 154 | + image Organization::DIAPER_APP_LOGO, width: 75, vposition: :center, position: :right |
| 155 | + end |
| 156 | + end |
| 157 | + end |
| 158 | + |
| 159 | + render |
| 160 | + end |
| 161 | + |
| 162 | + def donation_data |
| 163 | + data = [["Items Received", |
| 164 | + "Value/item", |
| 165 | + "In-Kind Value", |
| 166 | + "Quantity"]] |
| 167 | + data += @donation.line_items.sorted.map do |c| |
| 168 | + [c.item.name, |
| 169 | + dollar_value(c.item.value_in_cents), |
| 170 | + dollar_value(c.value_per_line_item), |
| 171 | + c.quantity] |
| 172 | + end |
| 173 | + data + [["", "", "", ""], |
| 174 | + ["Total Items Received", |
| 175 | + "", |
| 176 | + dollar_value(@donation.value_per_itemizable), |
| 177 | + @donation.line_items.total]] |
| 178 | + end |
| 179 | + |
| 180 | + def hide_columns(data) |
| 181 | + column_names_to_hide.each do |col_name| |
| 182 | + col_index = data.first.find_index(col_name) |
| 183 | + data.each { |line| line.delete_at(col_index) } if col_index.present? |
| 184 | + end |
| 185 | + end |
| 186 | + |
| 187 | + private |
| 188 | + |
| 189 | + def column_names_to_hide |
| 190 | + in_kind_column_name = "In-Kind Value" |
| 191 | + columns_to_hide = [] |
| 192 | + columns_to_hide.push("Value/item", in_kind_column_name) if @organization.hide_value_columns_on_receipt |
| 193 | + columns_to_hide |
| 194 | + end |
| 195 | +end |
0 commit comments