|
| 1 | +# Payment seeds (dev-only) - run on their own via `rake db:seed:payments`, or |
| 2 | +# as part of `rake db:seed:dev`. |
| 3 | + |
| 4 | +puts "Seeding Payments, Allocations, and Refunds..." |
| 5 | + |
| 6 | +payment_ids_start = Payment.maximum(:id) || 0 |
| 7 | +allocation_ids_start = Allocation.maximum(:id) || 0 |
| 8 | +refund_ids_start = Refund.maximum(:id) || 0 |
| 9 | +event_reg_ids_start = EventRegistration.maximum(:id) || 0 |
| 10 | + |
| 11 | +Refund.where("id > ?", refund_ids_start).delete_all |
| 12 | +Allocation.where("id > ?", allocation_ids_start).delete_all |
| 13 | +Payment.where("id > ?", payment_ids_start).delete_all |
| 14 | +EventRegistration.where("id > ?", event_reg_ids_start).delete_all |
| 15 | + |
| 16 | +event_cost_cents = 150000 |
| 17 | + |
| 18 | +bob = Person.find_or_create_by!(email: "bob.payment@seed.example.com") do |p| |
| 19 | + p.first_name = "Bob" |
| 20 | + p.last_name = "Barker" |
| 21 | +end |
| 22 | + |
| 23 | +alice = Person.find_or_create_by!(email: "alice.payment@seed.example.com") do |p| |
| 24 | + p.first_name = "Alice" |
| 25 | + p.last_name = "Test" |
| 26 | +end |
| 27 | + |
| 28 | +charlie = Person.find_or_create_by!(email: "charlie.payment@seed.example.com") do |p| |
| 29 | + p.first_name = "Charlie" |
| 30 | + p.last_name = "Test" |
| 31 | +end |
| 32 | + |
| 33 | +diana = Person.find_or_create_by!(email: "diana.payment@seed.example.com") do |p| |
| 34 | + p.first_name = "Diana" |
| 35 | + p.last_name = "Test" |
| 36 | +end |
| 37 | + |
| 38 | +eve = Person.find_or_create_by!(email: "eve.payment@seed.example.com") do |p| |
| 39 | + p.first_name = "Eve" |
| 40 | + p.last_name = "Test" |
| 41 | +end |
| 42 | + |
| 43 | +frank = Person.find_or_create_by!(email: "frank.payment@seed.example.com") do |p| |
| 44 | + p.first_name = "Frank" |
| 45 | + p.last_name = "Test" |
| 46 | +end |
| 47 | + |
| 48 | +gary = Person.find_or_create_by!(email: "gary.payment@seed.example.com") do |p| |
| 49 | + p.first_name = "Gary" |
| 50 | + p.last_name = "Test" |
| 51 | +end |
| 52 | + |
| 53 | +holly = Person.find_or_create_by!(email: "holly.payment@seed.example.com") do |p| |
| 54 | + p.first_name = "Holly" |
| 55 | + p.last_name = "Test" |
| 56 | +end |
| 57 | + |
| 58 | +iris = Person.find_or_create_by!(email: "iris.payment@seed.example.com") do |p| |
| 59 | + p.first_name = "Iris" |
| 60 | + p.last_name = "Test" |
| 61 | +end |
| 62 | + |
| 63 | +event = Event.find_or_create_by!(title: "Test Payments Workshop") do |e| |
| 64 | + e.start_date = 1.month.from_now.to_date |
| 65 | + e.end_date = 1.month.from_now.to_date + 2.days |
| 66 | + e.published = true |
| 67 | + e.cost_cents = event_cost_cents |
| 68 | +end |
| 69 | +event.update!(start_date: 1.month.from_now.to_date, end_date: 1.month.from_now.to_date + 2.days, published: true, cost_cents: event_cost_cents) |
| 70 | + |
| 71 | +reg_bob = EventRegistration.find_or_create_by!(registrant: bob, event: event) |
| 72 | +reg_alice = EventRegistration.find_or_create_by!(registrant: alice, event: event) |
| 73 | +reg_charlie = EventRegistration.find_or_create_by!(registrant: charlie, event: event) |
| 74 | +reg_diana = EventRegistration.find_or_create_by!(registrant: diana, event: event) |
| 75 | +reg_eve = EventRegistration.find_or_create_by!(registrant: eve, event: event) |
| 76 | +reg_frank = EventRegistration.find_or_create_by!(registrant: frank, event: event) |
| 77 | +reg_gary = EventRegistration.find_or_create_by!(registrant: gary, event: event) |
| 78 | +reg_iris = EventRegistration.find_or_create_by!(registrant: iris, event: event) |
| 79 | + |
| 80 | +puts " Payment made but allocation reverted)" |
| 81 | +payment1 = CashPayment.find_or_create_by!( |
| 82 | + person: bob, |
| 83 | + amount_cents: event_cost_cents |
| 84 | +) do |p| |
| 85 | + p.created_at = 5.days.ago |
| 86 | +end |
| 87 | +original_allocation1 = Allocation.create!( |
| 88 | + source: payment1, |
| 89 | + allocatable: reg_bob, |
| 90 | + amount: event_cost_cents, |
| 91 | + created_at: 5.days.ago |
| 92 | +) |
| 93 | +reversal_allocation1 = Allocation.create!( |
| 94 | + source: payment1, |
| 95 | + allocatable: reg_bob, |
| 96 | + amount: -event_cost_cents, |
| 97 | + created_at: 4.days.ago |
| 98 | +) |
| 99 | +original_allocation1.update!(reverted_id: reversal_allocation1.id) |
| 100 | + |
| 101 | +puts " Overpayment with full allocation (Alice pays $6000, covers 4 people)" |
| 102 | +payment2 = CashPayment.find_or_create_by!( |
| 103 | + person: alice, |
| 104 | + amount_cents: 600000 |
| 105 | +) do |p| |
| 106 | + p.created_at = 4.days.ago |
| 107 | +end |
| 108 | +Allocation.find_or_create_by!(source: payment2, allocatable: reg_alice, amount: event_cost_cents) { |a| a.created_at = 4.days.ago } |
| 109 | +Allocation.find_or_create_by!(source: payment2, allocatable: reg_charlie, amount: event_cost_cents) { |a| a.created_at = 4.days.ago } |
| 110 | +Allocation.find_or_create_by!(source: payment2, allocatable: reg_diana, amount: event_cost_cents) { |a| a.created_at = 4.days.ago } |
| 111 | +Allocation.find_or_create_by!(source: payment2, allocatable: reg_eve, amount: event_cost_cents) { |a| a.created_at = 4.days.ago } |
| 112 | + |
| 113 | +puts " Payment with remaining available ($2000 payment, $1500 allocated, $500 remaining)" |
| 114 | +payment3 = CashPayment.find_or_create_by!( |
| 115 | + person: frank, |
| 116 | + amount_cents: 200000 |
| 117 | +) do |p| |
| 118 | + p.created_at = 3.days.ago |
| 119 | +end |
| 120 | +Allocation.find_or_create_by!( |
| 121 | + source: payment3, |
| 122 | + allocatable: reg_frank, |
| 123 | + amount: 150000 |
| 124 | +) do |a| |
| 125 | + a.created_at = 3.days.ago |
| 126 | +end |
| 127 | + |
| 128 | +puts " Full refund ($1500 payment, fully allocated, fully refunded)" |
| 129 | +payment4 = CashPayment.find_or_create_by!( |
| 130 | + person: gary, |
| 131 | + amount_cents: event_cost_cents |
| 132 | +) do |p| |
| 133 | + p.created_at = 2.days.ago |
| 134 | +end |
| 135 | +original_alloc = Allocation.create!( |
| 136 | + source: payment4, |
| 137 | + allocatable: reg_gary, |
| 138 | + amount: event_cost_cents, |
| 139 | + created_at: 2.days.ago |
| 140 | +) |
| 141 | +reversal_alloc = Allocation.create!( |
| 142 | + source: payment4, |
| 143 | + allocatable: reg_gary, |
| 144 | + amount: -event_cost_cents, |
| 145 | + created_at: 1.day.ago |
| 146 | +) |
| 147 | +original_alloc.update!(reverted_id: reversal_alloc.id) |
| 148 | +Refund.create!( |
| 149 | + refundable: payment4, |
| 150 | + recipient: gary, |
| 151 | + amount_cents: event_cost_cents, |
| 152 | + method: "check", |
| 153 | + created_at: 1.day.ago |
| 154 | +) |
| 155 | + |
| 156 | +puts " Creating Scenario 8: Payment with no allocations ($10000, full amount remaining)" |
| 157 | +CashPayment.find_or_create_by!( |
| 158 | + person: holly, |
| 159 | + amount_cents: 1000000 |
| 160 | +) do |p| |
| 161 | + p.created_at = 7.days.ago |
| 162 | +end |
| 163 | + |
| 164 | +puts " Partial payment" |
| 165 | +payment9 = CashPayment.find_or_create_by!( |
| 166 | + person: iris, |
| 167 | + amount_cents: 100000 |
| 168 | +) do |p| |
| 169 | + p.created_at = 3.days.ago |
| 170 | +end |
| 171 | +Allocation.find_or_create_by!( |
| 172 | + source: payment9, |
| 173 | + allocatable: reg_iris, |
| 174 | + amount: 100000 |
| 175 | +) do |a| |
| 176 | + a.created_at = 3.days.ago |
| 177 | +end |
| 178 | + |
| 179 | +puts "Creating Scholarships, Payments, and Allocations for dev events…" |
| 180 | +# Funds registrations on the paid dev events with real money + scholarship |
| 181 | +# records so the event overview dashboard (registrants / received / outstanding |
| 182 | +# / scholarships) shows meaningful numbers. The events, people, and registrations |
| 183 | +# are created in db/seeds/dev/dummy.rb, so this only fills in the financial side |
| 184 | +# when the dummy seeds have already run (e.g. via `rake db:seed:dev`); on its own |
| 185 | +# `rake db:seed:payments` simply skips events that aren't present. |
| 186 | +# |
| 187 | +# Each registration is funded at most once — the guard skips any registration |
| 188 | +# that already has allocations, so the section is safe to re-run. |
| 189 | + |
| 190 | +amy_person = User.find_by(email: "amy.user@example.com")&.person |
| 191 | +maria_j = Person.find_by(first_name: "Maria", last_name: "Johnson") |
| 192 | +anna_g = Person.find_by(first_name: "Anna", last_name: "Garcia") |
| 193 | +sarah_s = Person.find_by(first_name: "Sarah", last_name: "Smith") |
| 194 | +jessica_b = Person.find_by(first_name: "Jessica", last_name: "Brown") |
| 195 | +mario_j = Person.find_by(first_name: "Mario", last_name: "Johnson") |
| 196 | +angel_g = Person.find_by(first_name: "Angel", last_name: "Garcia") |
| 197 | + |
| 198 | +facilitator_training = Event.find_by(title: "AWBW Facilitator Training") |
| 199 | +trauma_training = Event.find_by(title: "Facilitator Training: Trauma-Informed Art Practices") |
| 200 | +mindful_art = Event.find_by(title: "Mindful Art for Survivors Workshop") |
| 201 | + |
| 202 | +org_payer = Organization.find_by(name: "Angel Step Inn") |
| 203 | + |
| 204 | +# Mirrors ScholarshipsController: build the scholarship with a $0 allocation, |
| 205 | +# then set the amount + tasks_completed so sync_allocation_amount funds the |
| 206 | +# allocation only when the recipient's tasks are complete. |
| 207 | +award_scholarship = ->(registration, amount_cents:, tasks_completed:) do |
| 208 | + scholarship = Scholarship.new(recipient: registration.registrant) |
| 209 | + scholarship.build_allocation(allocatable: registration, amount: 0) |
| 210 | + scholarship.save! |
| 211 | + scholarship.update!(amount_cents: amount_cents, tasks_completed: tasks_completed) |
| 212 | + scholarship |
| 213 | +end |
| 214 | + |
| 215 | +# payer is a Person or an Organization; kind is :cash or :check. |
| 216 | +record_payment = ->(registration, payer:, amount_cents:, kind: :cash) do |
| 217 | + payer_attrs = payer.is_a?(Organization) ? { organization: payer } : { person: payer } |
| 218 | + created_at = rand(3..30).days.ago |
| 219 | + payment = case kind |
| 220 | + when :check |
| 221 | + CheckPayment.create!(**payer_attrs, amount_cents: amount_cents, check_number: "CHK-#{rand(10_000..99_999)}", created_at: created_at) |
| 222 | + else |
| 223 | + CashPayment.create!(**payer_attrs, amount_cents: amount_cents, created_at: created_at) |
| 224 | + end |
| 225 | + Allocation.create!(source: payment, allocatable: registration, amount: amount_cents, created_at: created_at) |
| 226 | +end |
| 227 | + |
| 228 | +# Funds a registration once. `scholarship` and `payments` describe what to build. |
| 229 | +fund_registration = ->(event, person, scholarship: nil, payments: []) do |
| 230 | + return unless event && person |
| 231 | + registration = EventRegistration.find_by(event: event, registrant: person) |
| 232 | + return unless registration |
| 233 | + return if registration.allocations.exists? |
| 234 | + |
| 235 | + award_scholarship.(registration, **scholarship) if scholarship |
| 236 | + payments.each { |payment| record_payment.(registration, **payment) } |
| 237 | +end |
| 238 | + |
| 239 | +# --- AWBW Facilitator Training ($150) --- |
| 240 | +# Amy: pending scholarship (tasks incomplete → $0 allocated) + partial cash → still owes |
| 241 | +fund_registration.(facilitator_training, amy_person, |
| 242 | + scholarship: { amount_cents: 10_000, tasks_completed: false }, |
| 243 | + payments: [ { payer: amy_person, amount_cents: 5_000, kind: :cash } ]) |
| 244 | +# Maria: paid in full by cash |
| 245 | +fund_registration.(facilitator_training, maria_j, |
| 246 | + payments: [ { payer: maria_j, amount_cents: 15_000, kind: :cash } ]) |
| 247 | +# Anna: paid in full by check from her organization (org-payer scenario) |
| 248 | +fund_registration.(facilitator_training, anna_g, |
| 249 | + payments: [ { payer: org_payer || anna_g, amount_cents: 15_000, kind: :check } ]) |
| 250 | +# Mario: partial cash → still owes |
| 251 | +fund_registration.(facilitator_training, mario_j, |
| 252 | + payments: [ { payer: mario_j, amount_cents: 5_000, kind: :cash } ]) |
| 253 | + |
| 254 | +# --- Facilitator Training: Trauma-Informed Art Practices ($120) --- |
| 255 | +# Sarah: paid in full by check |
| 256 | +fund_registration.(trauma_training, sarah_s, |
| 257 | + payments: [ { payer: sarah_s, amount_cents: 12_000, kind: :check } ]) |
| 258 | +# Jessica: completed scholarship ($80) + cash for the remainder → paid in full |
| 259 | +fund_registration.(trauma_training, jessica_b, |
| 260 | + scholarship: { amount_cents: 8_000, tasks_completed: true }, |
| 261 | + payments: [ { payer: jessica_b, amount_cents: 4_000, kind: :cash } ]) |
| 262 | +# Angel: partial cash → still owes |
| 263 | +fund_registration.(trauma_training, angel_g, |
| 264 | + payments: [ { payer: angel_g, amount_cents: 6_000, kind: :cash } ]) |
| 265 | + |
| 266 | +# --- Mindful Art for Survivors Workshop ($50) --- |
| 267 | +# Amy: paid in full by cash |
| 268 | +fund_registration.(mindful_art, amy_person, |
| 269 | + payments: [ { payer: amy_person, amount_cents: 5_000, kind: :cash } ]) |
| 270 | + |
| 271 | +[ facilitator_training, trauma_training, mindful_art ].compact.each do |event| |
| 272 | + dashboard = EventDashboard.new(event) |
| 273 | + puts " #{event.title}: #{dashboard.registrant_count} registrants, " \ |
| 274 | + "received #{dashboard.received_cents / 100.0}, outstanding #{dashboard.outstanding_cents / 100.0}, " \ |
| 275 | + "scholarships #{dashboard.scholarship_total_cents / 100.0} (#{dashboard.scholarship_recipient_count})" |
| 276 | +end |
| 277 | + |
| 278 | +puts " Payment seeds complete!" |
0 commit comments