Initial Transaction and OfflineTransaction support

Co-authored-by: Clarissa Lima Borges <clarissa@commitchange.com>
This commit is contained in:
Eric Schultz 2021-04-07 16:43:58 -05:00 committed by Eric Schultz
parent fca3c7cd6a
commit 2e8821efdf
69 changed files with 1991 additions and 376 deletions

View file

@ -569,7 +569,6 @@ AllCops:
- 'spec/lib/format/dedication_spec.rb'
- 'spec/lib/insert/insert_refunds_spec.rb'
- 'spec/lib/insert/insert_recurring_donation_spec.rb'
- 'spec/lib/insert/insert_donation_spec.rb'
- 'spec/lib/insert/insert_charge_spec.rb'
- 'spec/lib/insert/insert_disputes_spec.rb'
- 'spec/lib/insert/insert_bank_account_spec.rb'
@ -745,3 +744,7 @@ Style/FrozenStringLiteralComment:
Style/PreferredHashMethods:
Enabled: false
Style/LambdaCall:
# jbuilder uses this a lot so we want it.
Enabled: false

9
Procfile.dev Normal file
View file

@ -0,0 +1,9 @@
# You can run these commands in separate shells
web: rails s -p 3000
# Next line runs a watch process with webpack to compile the changed files.
# When making frequent changes to client side assets, you will prefer building webpack assets
# upon saving rather than when you refresh your browser page.
# Note, if using React on Rails localization you will need to run
# `bundle exec rake react_on_rails:locale` before you run bin/webpack
client: sh -c 'rm -rf public/packs/* || true && bin/webpack -w'

26
Procfile.dev-hmr Normal file
View file

@ -0,0 +1,26 @@
# Procfile for development using HMR
web: rails s -p 3000
# Note, hot and live reloading don't work with the default generator setup on
# top of the rails/webpacker Webpack config with server rendering.
# If you have server rendering enabled (prerender is true), you either need to
# a. Ensure that you have dev_server.hmr and dev_server.inline BOTH set to false,
# and you have this option in your config/initializers/react_on_rails.rb:
# config.same_bundle_for_client_and_server = true
# If you have either config/webpacker.yml option set to true, you'll see errors like
# "ReferenceError: window is not defined" (if hmr is true)
# "TypeError: Cannot read property 'prototype' of undefined" (if inline is true)
# b. Skip using the webpack-dev-server. bin/webpack --watch is typically
fast enough.
# c. See the React on Rails README for a link to documentation for how to setup
# SSR with HMR and React hot loading using the webpack-dev-server only for the
# client bundles and a static file for the server bundle.
# Run the webpack-dev-server for client and maybe server files
webpack-dev-server: bin/webpack-dev-server
# Keep the JS fresh for server rendering. Remove if not server rendering.
# Especially if you have not configured generation of a server bundle without a hash.
# as that will conflict with the manifest created by the bin/webpack-dev-server
# rails-server-assets: SERVER_BUNDLE_ONLY=yes bin/webpack --watch

View file

@ -143,7 +143,7 @@ This will download the latest Houdini code. Change to the
`houdini` directory and we can set the rest of Houdini up.
Let's run the Houdini project setup and we'll be ready to go!
P
```bash
bin/setup
```

View file

@ -40,8 +40,6 @@ class Campaign < ApplicationRecord
# :reason_for_supporting,
# :default_reason_for_supporting
add_builder_expansion :nonprofit
validate :end_datetime_cannot_be_in_past, on: :create
validates :profile, presence: true
validates :nonprofit, presence: true
@ -202,6 +200,8 @@ class Campaign < ApplicationRecord
def to_builder(*expand)
init_builder(*expand) do |json|
json.(self, :name)
json.add_builder_expansion :nonprofit
end
end

View file

@ -30,8 +30,6 @@ class CampaignGiftOption < ApplicationRecord
after_update_commit :publish_updated
after_destroy_commit :publish_deleted
add_builder_expansion :campaign, :nonprofit
has_one :nonprofit, through: :campaign
@ -90,6 +88,8 @@ class CampaignGiftOption < ApplicationRecord
json.type desc[:recurrence][:type]
end if desc[:recurrence]
end
json.add_builder_expansion :campaign, :nonprofit
end
end

View file

@ -10,9 +10,6 @@ class CampaignGiftPurchase < ApplicationRecord
belongs_to :campaign
has_many :campaign_gifts, class_name: 'ModernCampaignGift'
add_builder_expansion :campaign
# TODO replace with Discard gem
define_model_callbacks :discard
@ -28,22 +25,28 @@ class CampaignGiftPurchase < ApplicationRecord
end
end
def to_id
::Jbuilder.new do |json|
json.id id
json.object 'campaign_gift_purchase'
json.type 'trx_assignment'
end
end
def to_builder(*expand)
init_builder(*expand) do |json|
json.(self, :deleted)
json.type 'trx_assignment'
json.amount do
json.cents amount
json.currency nonprofit.currency
end
if expand.include? :campaign_gifts
json.campaign_gifts campaign_gifts do |gift|
json.merge! gift.to_builder.attributes!
end
else
json.campaign_gifts campaign_gifts.pluck(:id)
end
json.add_builder_expansion :campaign, :nonprofit, :supporter
json.add_builder_expansion :trx, json_attribute: "transaction"
json.add_builder_expansion :campaign_gifts, enum_type: :expandable
end
end

View file

@ -0,0 +1,16 @@
# frozen_string_literal: true
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
module Model::CreatedTimeable
extend ActiveSupport::Concern
included do
after_initialize :set_created_if_needed
private
def set_created_if_needed
self[:created] = Time.current unless self[:created]
end
end
end

View file

@ -14,8 +14,8 @@ module Model::Eventable
end
end
end
def to_builder(*expand)
raise NotImplementedError.new("to_builder must be implemented in your model")
end
end

View file

@ -92,6 +92,15 @@ module Model::Jbuilder
def builder_expansions
@builder_expansions ||= BuilderExpansionSet.new
end
def init_builder(model, *expand)
JbuilderWithExpansions.new(model, *expand) do | json|
json.(model, :id)
json.object model.class.name.underscore
yield(json)
end
end
end
def to_id
@ -152,11 +161,18 @@ module Model::Jbuilder
return ->(model,be=self) {
value = be.get_attribute_value model
if be.expandable_enum?
value&.map{|i| i&.to_id}
value&.map do |i|
id_result = i&.to_id
if ::Jbuilder === id_result
id_result.attributes!
else
id_result
end
end
elsif be.flat_enum?
value
else
value&.to_id
value&.to_id
end
}
end
@ -165,7 +181,7 @@ module Model::Jbuilder
return ->(model,be=self) {
value = be.get_attribute_value model
if be.expandable_enum?
value&.map{|i| i&.to_builder}
value&.map{|i| i&.to_builder.attributes!}
elsif be.flat_enum?
value
else
@ -183,20 +199,32 @@ module Model::Jbuilder
end
end
def init_builder(*expand)
builder_expansions = self.class.builder_expansions
Jbuilder.new do | json|
json.(self, :id)
json.object self.class.name.underscore
def init_builder(*expand, &block)
self.class.init_builder(self, *expand, &block)
end
class JbuilderWithExpansions < ::Jbuilder
attr_reader :model, :expand
delegate_missing_to :@jbuilder
def initialize(model, *expand, &block)
@model = model
@expand = expand
super(&block)
end
def add_builder_expansion( ... )
builder_expansions = BuilderExpansionSet.new
builder_expansions.add_builder_expansion( ... )
builder_expansions.keys.each do |k|
if expand.include? k
json.set! builder_expansions.get_by_key(k).json_attribute, builder_expansions.get_by_key(k).to_builder.(self)
set! builder_expansions.get_by_key(k).json_attribute, builder_expansions.get_by_key(k).to_builder.(model)
else
json.set! builder_expansions.get_by_key(k).json_attribute, builder_expansions.get_by_key(k).to_id.(self)
set! builder_expansions.get_by_key(k).json_attribute, builder_expansions.get_by_key(k).to_id.(model)
end
end
yield(json)
end
end
end

View file

@ -0,0 +1,20 @@
# frozen_string_literal: true
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
module Model::Subtransactable
extend ActiveSupport::Concern
included do
include Model::Houidable
include Model::Jbuilder
include Model::Eventable
has_one :subtransaction, as: :subtransactable, dependent: :nullify
has_one :trx, through: :subtransaction
has_one :supporter, through: :trx
has_one :nonprofit, through: :trx
has_many :subtransaction_payments, through: :subtransaction
end
end

View file

@ -0,0 +1,20 @@
# frozen_string_literal: true
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
module Model::SubtransactionPaymentable
extend ActiveSupport::Concern
included do
include Model::Houidable
include Model::Jbuilder
include Model::Eventable
has_one :subtransaction_payment, as: :paymentable, touch: true, dependent: :destroy
has_one :trx, through: :subtransaction_payment
has_one :supporter, through: :subtransaction_payment
has_one :nonprofit, through: :subtransaction_payment
has_one :subtransaction, through: :subtransaction_payment
end
end

View file

@ -16,8 +16,8 @@ module Model::TrxAssignable
json_attribute: :transaction
has_one :transaction_assignment, as: :assignable
has_one :trx, through: :transaction_assignment
has_one :supporter, through: :trx
has_one :nonprofit, through: :supporter
has_one :trx, through: :transaction_assignment, class_name: 'Transaction', foreign_key: 'transaction_id'
has_one :supporter, through: :transaction_assignment
has_one :nonprofit, through: :transaction_assignment
end
end
end

View file

@ -14,8 +14,6 @@ class CustomFieldMaster < ApplicationRecord
scope :not_deleted, -> { where(deleted: false) }
add_builder_expansion :nonprofit
after_create_commit :publish_created
# TODO replace with Discard gem
@ -42,6 +40,8 @@ class CustomFieldMaster < ApplicationRecord
init_builder(*expand) do |json|
json.(self, :name, :deleted)
json.object 'custom_field_definition'
json.add_builder_expansion :nonprofit
end
end

View file

@ -5,7 +5,7 @@
class Event < ApplicationRecord
include Image::AttachmentExtensions
include Model::Jbuilder
add_builder_expansion :nonprofit
# :deleted, #bool for soft-delete
# :name, # str
# :tagline, # str
@ -102,6 +102,7 @@ class Event < ApplicationRecord
def to_builder(*expand)
init_builder(*expand) do |json|
json.(self, :name)
json.add_builder_expansion :nonprofit
end
end

View file

@ -6,7 +6,6 @@ class EventDiscount < ApplicationRecord
include Model::Eventable
include Model::Jbuilder
add_builder_expansion :nonprofit, :event
# :code,
# :event_id,
# :name,
@ -36,13 +35,16 @@ class EventDiscount < ApplicationRecord
json.percent percent
end
if expand.include? :ticket_levels
json.ticket_levels ticket_levels do |tl|
json.merge! tl.to_builder.attributes!
end
else
json.ticket_levels ticket_levels.pluck(:id)
end
json.add_builder_expansion :nonprofit, :event
json.add_builder_expansion :ticket_levels, enum_type: :expandable
# if expand.include? :ticket_levels
# json.ticket_levels ticket_levels do |tl|
# json.merge! tl.to_builder.attributes!
# end
# else
# json.ticket_levels ticket_levels.pluck(:id)
# end
end
end

View file

@ -7,10 +7,6 @@ class ModernCampaignGift < ApplicationRecord
include Model::Jbuilder
include Model::Eventable
setup_houid :cgift
add_builder_expansion :nonprofit, :supporter, :campaign, :campaign_gift_option, :campaign_gift_purchase
add_builder_expansion :trx,
json_attribute: :transaction
belongs_to :campaign_gift_purchase
belongs_to :legacy_campaign_gift, class_name: 'CampaignGift', foreign_key: :campaign_gift_id, inverse_of: :modern_campaign_gift
@ -42,6 +38,17 @@ class ModernCampaignGift < ApplicationRecord
init_builder(*expand) do |json|
json.(self, :deleted)
json.object 'campaign_gift'
json.add_builder_expansion :nonprofit, :supporter, :campaign, :campaign_gift_option
json.add_builder_expansion :trx,
json_attribute: :transaction
if (expand.include? :campaign_gift_purchase)
json.campaign_gift_purchase campaign_gift_purchase.to_builder
else
json.campaign_gift_purchase campaign_gift_purchase.id
end
json.amount do
json.cents amount
json.currency nonprofit.currency

View file

@ -11,10 +11,19 @@ class ModernDonation < ApplicationRecord
delegate :designation, :dedication, to: :legacy_donation
def to_id
::Jbuilder.new do |json|
json.id id
json.object 'donation'
json.type 'trx_assignment'
end
end
def to_builder(*expand)
init_builder(*expand) do |json|
json.(self, :designation)
json.object 'donation'
json.type 'trx_assignment'
json.dedication do
json.type dedication['type']
@ -32,14 +41,19 @@ class ModernDonation < ApplicationRecord
json.cents amount
json.currency nonprofit.currency
end
json.add_builder_expansion :nonprofit, :supporter
json.add_builder_expansion :trx, json_attribute: :transaction
end
end
def publish_created
Houdini.event_publisher.announce(:donation_created, to_event('donation.created', :nonprofit, :supporter, :trx).attributes!)
Houdini.event_publisher.announce(:trx_assignment_created, to_event('trx_assignment.created', :nonprofit, :supporter, :trx).attributes!)
end
def publish_updated
Houdini.event_publisher.announce(:donation_updated, to_event('donation.updated', :nonprofit, :supporter, :trx).attributes!)
Houdini.event_publisher.announce(:trx_assignment_updated, to_event('trx_assignment.updated', :nonprofit, :supporter, :trx).attributes!)
end
end

View file

@ -7,7 +7,7 @@ class Nonprofit < ApplicationRecord
Categories = ['Public Benefit', 'Human Services', 'Education', 'Civic Duty', 'Human Rights', 'Animals', 'Environment', 'Health', 'Arts, Culture, Humanities', 'International', 'Children', 'Religion', 'LGBTQ', "Women's Rights", 'Disaster Relief', 'Veterans'].freeze
include Image::AttachmentExtensions
include Model::Jbuilder
# :name, # str
# :stripe_account_id, # str
# :summary, # text: paragraph-sized organization summary
@ -260,9 +260,13 @@ class Nonprofit < ApplicationRecord
Houdini.intl.all_currencies[currency.downcase.to_sym][:symbol]
end
def to_builder(*expand)
init_builder(*expand) do |json|
json.(self, :name)
concerning :JBuilder do
include Model::Jbuilder
def to_builder(*expand)
init_builder(*expand) do |json|
json.(self, :id, :name)
end
end
end
@ -302,5 +306,8 @@ private
def user_is_valid
(user && user.is_a?(User)) || errors.add(:user_id, "is not a valid user")
end
end

View file

@ -0,0 +1,68 @@
# frozen_string_literal: true
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
# rubocop:disable Metrics/BlockLength, Metrics/AbcSize, Metrics/MethodLength
class OfflineTransaction < ApplicationRecord
include Model::Subtransactable
delegate :created, to: :subtransaction
def net_amount
subtransaction_payments.sum(&:net_amount)
end
concerning :JBuilder do
included do
setup_houid :offlinetrx
end
def to_builder(*expand)
init_builder(*expand) do |json|
json.type 'subtransaction'
json.created created.to_i
json.initial_amount do
json.cents amount || 0
json.currency nonprofit.currency
end
json.net_amount do
json.cents net_amount
json.currency nonprofit.currency
end
if expand.include? :payments
json.payments subtransaction_payments do |py|
json.merge! py.to_builder.attributes!
end
else
json.payments subtransaction_payments do |py|
json.merge! py.to_id.attributes!
end
end
json.add_builder_expansion :nonprofit, :supporter
json.add_builder_expansion(
:trx,
json_attribute: :transaction
)
end
end
def to_id
::Jbuilder.new do |json|
json.(self, :id)
json.object 'offline_transaction'
json.type 'subtransaction'
end
end
def publish_created
Houdini.event_publisher.announce(
:offline_transaction_created,
to_event('offline_transaction.created', :nonprofit, :trx, :supporter,
:payments).attributes!
)
end
end
end
# rubocop:enable all

View file

@ -0,0 +1,78 @@
# frozen_string_literal: true
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
# rubocop:disable Metrics/MethodLength, Metrics/BlockLength, Metrics/AbcSize
class OfflineTransactionCharge < ApplicationRecord
include Model::SubtransactionPaymentable
belongs_to :payment
delegate :gross_amount, :net_amount, :fee_total, to: :payment
delegate :currency, to: :nonprofit
concerning :JBuilder do
included do
setup_houid :offtrxchrg
end
def to_builder(*expand)
init_builder(*expand) do |json|
json.object 'offline_transaction_charge'
json.gross_amount do
json.cents gross_amount
json.currency currency
end
json.net_amount do
json.cents net_amount
json.currency currency
end
json.fee_total do
json.cents fee_total
json.currency currency
end
json.created payment.date.to_i
json.type 'payment'
json.add_builder_expansion :nonprofit, :supporter, :subtransaction
json.add_builder_expansion :trx, json_attribute: :transaction
end
end
def to_id
::Jbuilder.new do |json|
json.(self, :id)
json.object 'offline_transaction_charge'
json.type 'payment'
end
end
def publish_created
Houdini.event_publisher.announce(
:offline_transaction_charge_created,
to_event('offline_transaction_charge.created',
:nonprofit,
:trx,
:supporter,
:subtransaction).attributes!
)
Houdini.event_publisher.announce(
:payment_created,
to_event(
'payment.created',
:nonprofit,
:trx,
:supporter,
:subtransaction
).attributes!
)
end
end
end
# rubocop:enable all

View file

@ -7,12 +7,6 @@
# If connected to an offsite_payment, this is money the nonprofit is recording for convenience.
class Payment < ApplicationRecord
# :towards,
# :gross_amount,
# :refund_total,
# :fee_total,
# :kind,
# :date
belongs_to :supporter
belongs_to :nonprofit
@ -26,4 +20,10 @@ class Payment < ApplicationRecord
has_many :events, through: :tickets
has_many :payment_payouts
has_many :charges
has_one :subtransaction_payment
has_one :subtransaction, through: :subtransaction_payment
has_one :trx, through: :subtransaction_payment
end

View file

@ -0,0 +1,26 @@
# frozen_string_literal: true
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
class Subtransaction < ApplicationRecord
include Model::CreatedTimeable
concerning :JBuilder do
include Model::Houidable
included do
setup_houid :subtrx
end
end
belongs_to :trx, class_name: 'Transaction', foreign_key: 'transaction_id', inverse_of: :subtransactions
has_one :supporter, through: :trx
has_one :nonprofit, through: :trx
has_many :subtransaction_payments # rubocop:disable Rails/HasManyOrHasOneDependent
delegated_type :subtransactable, types: %w[OfflineTransaction]
scope :with_subtransactables, -> { includes(:subtransactable) }
delegate :to_builder, :to_event, :to_id, :publish_created, :publish_updated, :publish_deleted, to: :subtransactable
end

View file

@ -0,0 +1,28 @@
# frozen_string_literal: true
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
class SubtransactionPayment < ApplicationRecord
include Model::Houidable
include Model::CreatedTimeable
setup_houid :subtrxentity
belongs_to :subtransaction
has_one :trx, class_name: 'Transaction', foreign_key: 'transaction_id', through: :subtransaction
has_one :supporter, through: :subtransaction
has_one :nonprofit, through: :subtransaction
delegated_type :paymentable, types: ['OfflineTransactionCharge']
delegate :gross_amount, :fee_total, :net_amount, to: :paymentable
scope :with_entities, -> { includes(:paymentable) }
delegate :to_builder,
:to_event,
:to_id,
:publish_created,
:publish_updated,
:publish_deleted, to: :paymentable
end

View file

@ -54,7 +54,7 @@ class Supporter < ApplicationRecord
validates :nonprofit, presence: true
scope :not_deleted, -> { where(deleted: false) }
add_builder_expansion :nonprofit
# TODO replace with Discard gem
define_model_callbacks :discard
@ -86,47 +86,56 @@ class Supporter < ApplicationRecord
h
end
def to_builder(*expand)
supporter_addresses = [self]
init_builder(*expand) do |json|
json.(self, :name, :organization, :phone, :anonymous, :deleted)
if expand.include? :supporter_address
json.supporter_addresses supporter_addresses do |i|
json.merge! i.to_supporter_address_builder.attributes!
concerning :Jbuilder do
included do
def to_builder(*expand)
supporter_addresses = [self]
init_builder(*expand) do |json|
json.(self, :name, :organization, :phone, :anonymous, :deleted)
json.add_builder_expansion :nonprofit, :merged_into
if expand.include? :supporter_address
json.supporter_addresses supporter_addresses do |i|
json.merge! i.to_supporter_address_builder.attributes!
end
else
json.supporter_addresses [id]
end
# unless merged_into.nil?
# if expand.include? :merged_into
# json.merged_into merged_into.to_builder
# else
# json.merged_into merged_into.id
# end
# else
# json.merged_into nil
# end
end
else
json.supporter_addresses [id]
end
unless merged_into.nil?
if expand.include? :merged_into
json.merged_into merged_into.to_builder
else
json.merged_into merged_into.id
def to_supporter_address_builder(*expand)
init_builder(*expand) do |json|
json.(self, :address, :state_code, :city, :country, :zip_code, :deleted)
json.object 'supporter_address'
if expand.include? :supporter
json.supporter to_builder
else
json.supporter id
end
# if expand.include? :nonprofit
# json.nonprofit nonprofit.to_builder
# else
# json.nonprofit nonprofit.id
# end
json.add_builder_expansion :nonprofit
end
else
json.merged_into nil
end
end
end
def to_supporter_address_builder(*expand)
init_builder(*expand) do |json|
json.(self, :address, :state_code, :city, :country, :zip_code, :deleted)
json.object 'supporter_address'
if expand.include? :supporter
json.supporter to_builder
else
json.supporter id
end
if expand.include? :nonprofit
json.nonprofit nonprofit.to_builder
else
json.nonprofit nonprofit.id
end
end
end
def full_address
Format::Address.full_address(address, city, state_code)
@ -167,7 +176,7 @@ class Supporter < ApplicationRecord
# we do something custom here since Supporter and SupporterAddress are in the same model
def to_event(event_type, *expand)
Jbuilder.new do |event|
::Jbuilder.new do |event|
event.id "objevt_" + SecureRandom.alphanumeric(22)
event.object 'object_event'
event.type event_type

View file

@ -18,8 +18,6 @@ class SupporterNote < ApplicationRecord
validates :supporter_id, presence: true
# TODO replace with Discard gem
add_builder_expansion :supporter, :nonprofit, :user
define_model_callbacks :discard
after_discard :publish_deleted
@ -38,6 +36,8 @@ class SupporterNote < ApplicationRecord
def to_builder(*expand)
init_builder(*expand) do |json|
json.(self, :deleted, :content)
json.add_builder_expansion :supporter, :nonprofit, :user
end
end

View file

@ -6,7 +6,6 @@ class TagMaster < ApplicationRecord
include Model::Eventable
include Model::Jbuilder
add_builder_expansion :nonprofit
# TODO replace with Discard gem
define_model_callbacks :discard
@ -46,6 +45,8 @@ class TagMaster < ApplicationRecord
init_builder(*expand) do |json|
json.(self, :name, :deleted)
json.object 'tag_definition'
json.add_builder_expansion :nonprofit
end
end

View file

@ -15,9 +15,7 @@ class TicketLevel < ApplicationRecord
# :admin_only, #bool, only admins can create tickets for this level
# :limit, #int: for limiting the number of tickets to be sold
# :order #int: order in which to be displayed
add_builder_expansion :nonprofit, :event
# TODO replace with Discard gem
define_model_callbacks :discard
@ -67,13 +65,16 @@ class TicketLevel < ApplicationRecord
end
json.available_to admin_only ? 'admins' : 'everyone'
if expand.include? :event_discounts
json.event_discounts event_discounts do |disc|
json.merge! disc.to_builder.attributes!
end
else
json.event_discounts event_discounts.pluck(:id)
end
json.add_builder_expansion :nonprofit, :event
json.add_builder_expansion :event_discounts, enum_type: :expandable
# if expand.include? :event_discounts
# json.event_discounts event_discounts do |disc|
# json.merge! disc.to_builder.attributes!
# end
# else
# json.event_discounts event_discounts.pluck(:id)
# end
end
end

View file

@ -6,9 +6,6 @@ class TicketPurchase < ApplicationRecord
include Model::TrxAssignable
setup_houid :tktpur
add_builder_expansion :event, :event_discount
before_create :set_original_discount
belongs_to :event_discount
@ -18,8 +15,18 @@ class TicketPurchase < ApplicationRecord
validates :event, presence: true
def to_id
::Jbuilder.new do |json|
json.id id
json.object 'ticket_purchase'
json.type 'trx_assignment'
end
end
def to_builder(*expand)
init_builder(*expand) do |json|
json.type 'trx_assignment'
json.original_discount do
json.percent original_discount
end if original_discount
@ -29,19 +36,22 @@ class TicketPurchase < ApplicationRecord
json.currency nonprofit.currency
end
json.add_builder_expansion :event, :event_discount, :nonprofit, :supporter
json.add_builder_expansion :ticket_to_legacy_tickets, enum_type: :expandable, json_attribute: 'tickets'
json.add_builder_expansion :trx, json_attribute: :transaction
if expand.include? :tickets
json.tickets ticket_to_legacy_tickets do |i|
i.to_builder.attributes!
end
else
json.tickets ticket_to_legacy_tickets.pluck(:id)
end
# if expand.include? :tickets
# json.tickets ticket_to_legacy_tickets do |i|
# i.to_builder.attributes!
# end
# else
# json.tickets ticket_to_legacy_tickets.pluck(:id)
# end
end
end
def publish_created
Houdini.event_publisher.announce(:ticket_purchase_created, to_event('ticket_purchase.created', :event, :nonprofit, :supporter, :trx, :event_discount).attributes!)
Houdini.event_publisher.announce(:ticket_purchase_created, to_event('ticket_purchase.created', :event, :nonprofit, :supporter, :trx, :event_discount, :ticket_to_legacy_tickets).attributes!)
end
private

View file

@ -21,8 +21,6 @@ class TicketToLegacyTicket < ApplicationRecord
setup_houid :tkt
add_builder_expansion :ticket_purchase, :ticket_level, :supporter, :event, :nonprofit, :event_discount
def to_builder(*expand)
init_builder(*expand) do |json|
json.(self, :checked_in, :deleted, :note)
@ -38,6 +36,8 @@ class TicketToLegacyTicket < ApplicationRecord
json.percent original_discount
end
end
json.add_builder_expansion :ticket_purchase, :ticket_level, :supporter, :event, :nonprofit, :event_discount
end
end

View file

@ -3,36 +3,81 @@
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
class Transaction < ApplicationRecord
include Model::Houidable
include Model::Jbuilder
include Model::Eventable
setup_houid :trx
add_builder_expansion :nonprofit, :supporter
include Model::CreatedTimeable
belongs_to :supporter
has_one :nonprofit, through: :supporter
has_many :transaction_assignments
has_many :transaction_assignments, inverse_of: 'trx'
has_many :donations, through: :transaction_assignments, source: :assignable, source_type: 'ModernDonation'
has_many :ticket_purchases, through: :transaction_assignments, source: :assignable, source_type: 'TicketPurchase'
has_many :campaign_gift_purchases, through: :transaction_assignments, source: :assignable, source_type: 'CampaignGiftPurchase'
has_many :donations, through: :transaction_assignments, source: :assignable, source_type: 'ModernDonation', inverse_of: 'trx'
has_many :ticket_purchases, through: :transaction_assignments, source: :assignable, source_type: 'TicketPurchase', inverse_of: 'trx'
has_many :campaign_gift_purchases, through: :transaction_assignments, source: :assignable, source_type: 'CampaignGiftPurchase', inverse_of: 'trx'
has_one :subtransaction
has_many :subtransaction_payments, through: :subtransaction
validates :supporter, presence: true
concerning :JBuilder do
include Model::Houidable
include Model::Jbuilder
include Model::Eventable
def to_builder(*expand)
init_builder(*expand) do |json|
json.amount do
json.cents amount || 0
json.currency nonprofit.currency
end
included do
setup_houid :trx
end
def to_builder(*expand)
init_builder(*expand) do |json|
json.amount do
json.cents amount || 0
json.currency nonprofit.currency
end
json.created created.to_i
json.add_builder_expansion :nonprofit, :supporter, :subtransaction
json.add_builder_expansion :subtransaction_payments, enum_type: :expandable
json.add_builder_expansion :transaction_assignments, enum_type: :expandable
end
end
end
def publish_created
Houdini.event_publisher.announce(:transaction_created,
to_event('transaction.created', :nonprofit, :supporter).attributes!)
concerning :ObjectEvents do
include JBuilder
def publish_created
Houdini.event_publisher.announce(:transaction_created,
to_event('transaction.created', :nonprofit, :supporter, :subtransaction_payments, :transaction_assignments, :subtransaction).attributes!)
end
def publish_updated
Houdini.event_publisher.announce(:transaction_updated,
to_event('transaction.updated', :nonprofit, :supporter, :subtransaction_payments, :transaction_assignments, :subtransaction).attributes!)
end
def publish_refunded
Houdini.event_publisher.announce(:transaction_refunded,
to_event('transaction.refunded', :nonprofit, :supporter, :subtransaction_payments, :transaction_assignments, :subtransaction).attributes!)
end
def publish_disputed
Houdini.event_publisher.announce(:transaction_disputed,
to_event('transaction.refunded', :nonprofit, :supporter, :subtransaction_payments, :transaction_assignments).attributes!)
end
def publish_deleted
Houdini.event_publisher.announce(:transaction_deleted,
to_event('transaction.deleted', :nonprofit, :supporter, :subtransaction_payments, :transaction_assignments).attributes!)
end
end
private
def set_created_if_needed
write_attribute(:created, Time.now) unless read_attribute(:created)
end
end
ActiveSupport.run_load_hooks(:houdini_transaction, Transaction)

View file

@ -6,7 +6,16 @@ class TransactionAssignment < ApplicationRecord
include Model::Houidable
setup_houid :trxassign
belongs_to :assignable, polymorphic: true
delegated_type :assignable, types: ['ModernDonation', 'CampaignGiftPurchase', 'TicketPurchase']
delegate :to_id,
:to_builder,
:publish_created,
:publish_updated,
:publish_deleted, to: :assignable
belongs_to :trx, class_name: 'Transaction', foreign_key: "transaction_id"
has_one :supporter, through: :trx
has_one :nonprofit, through: :trx
end

View file

@ -0,0 +1,31 @@
# frozen_string_literal: true
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
class AddSubtransactionHierarchy < ActiveRecord::Migration[6.1]
def change
create_table :subtransactions, id: :string do |t|
t.references :transaction, foreign_key: true, type: :string, null: false
t.references :subtransactable, polymorphic: true, type: :string, null: false, index: {unique: true}
t.datetime "created", comment: 'the moment that the subtransaction was created. Could be earlier than created_at if the transaction was in the past.'
t.timestamps
end
create_table "offline_transactions", id: :string do |t|
t.integer "amount", null: false
t.timestamps
end
create_table :subtransaction_payments, id: :string do |t|
t.references :subtransaction, type: :string, foreign_key: true
t.references :paymentable, polymorphic: true, type: :string
t.datetime "created", comment: 'the moment that the subtransaction_payment was created. Could be earlier than created_at if the transaction was in the past.'
t.timestamps
end
create_table :offline_transaction_charges, id: :string do |t|
t.references :payment, foreign_key: true, null: false
t.timestamps
end
end
end

View file

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2021_02_23_204824) do
ActiveRecord::Schema.define(version: 2021_03_29_213633) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_stat_statements"
@ -599,6 +599,19 @@ ActiveRecord::Schema.define(version: 2021_02_23_204824) do
t.index ["nonprofit_id"], name: "index_object_event_hook_configs_on_nonprofit_id"
end
create_table "offline_transaction_charges", id: :string, force: :cascade do |t|
t.bigint "payment_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["payment_id"], name: "index_offline_transaction_charges_on_payment_id"
end
create_table "offline_transactions", id: :string, force: :cascade do |t|
t.integer "amount", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "offsite_payments", id: :serial, force: :cascade do |t|
t.integer "gross_amount"
t.string "kind", limit: 255
@ -769,6 +782,28 @@ ActiveRecord::Schema.define(version: 2021_02_23_204824) do
t.index ["tokenizable_id", "tokenizable_type"], name: "index_source_tokens_on_tokenizable_id_and_tokenizable_type"
end
create_table "subtransaction_payments", id: :string, force: :cascade do |t|
t.string "subtransaction_id"
t.string "paymentable_type"
t.string "paymentable_id"
t.datetime "created", comment: "the moment that the subtransaction_payment was created. Could be earlier than created_at if the transaction was in the past."
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["paymentable_type", "paymentable_id"], name: "index_subtransaction_payments_on_paymentable"
t.index ["subtransaction_id"], name: "index_subtransaction_payments_on_subtransaction_id"
end
create_table "subtransactions", id: :string, force: :cascade do |t|
t.string "transaction_id", null: false
t.string "subtransactable_type", null: false
t.string "subtransactable_id", null: false
t.datetime "created", comment: "the moment that the subtransaction was created. Could be earlier than created_at if the transaction was in the past."
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["subtransactable_type", "subtransactable_id"], name: "index_subtransactions_on_subtransactable", unique: true
t.index ["transaction_id"], name: "index_subtransactions_on_transaction_id"
end
create_table "supporter_notes", id: :serial, force: :cascade do |t|
t.text "content"
t.integer "supporter_id"
@ -925,6 +960,7 @@ ActiveRecord::Schema.define(version: 2021_02_23_204824) do
t.integer "amount"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.datetime "created", comment: "the moment that the offline_transaction was created. Could be earlier than created_at if the transaction was in the past."
t.index ["supporter_id"], name: "index_transactions_on_supporter_id"
end
@ -971,6 +1007,9 @@ ActiveRecord::Schema.define(version: 2021_02_23_204824) do
add_foreign_key "modern_campaign_gifts", "campaign_gift_purchases"
add_foreign_key "modern_campaign_gifts", "campaign_gifts"
add_foreign_key "object_event_hook_configs", "nonprofits"
add_foreign_key "offline_transaction_charges", "payments"
add_foreign_key "subtransaction_payments", "subtransactions"
add_foreign_key "subtransactions", "transactions"
add_foreign_key "ticket_purchases", "event_discounts"
add_foreign_key "ticket_purchases", "events"
add_foreign_key "ticket_to_legacy_tickets", "ticket_purchases"

View file

@ -1,9 +1,8 @@
// License: LGPL-3.0-or-later
import type { HouID, HoudiniObject, HoudiniEvent, Amount, IDType} from '../../common';
import type Nonprofit from '..';
import type Campaign from '.';
import type { CampaignGiftPurchase, CampaignGiftOption } from '.';
import type Supporter from '../Supporter';
import { TrxDescendent } from '../Transaction';
export interface TransactionAddress {
address: string;
@ -13,7 +12,7 @@ export interface TransactionAddress {
zip_code: string;
}
export interface CampaignGift extends HoudiniObject<HouID> {
export interface CampaignGift extends HoudiniObject<HouID>, TrxDescendent {
address?: TransactionAddress;
amount: Amount;
campaign: IDType | Campaign;
@ -21,9 +20,7 @@ export interface CampaignGift extends HoudiniObject<HouID> {
campaign_gift_purchase: IDType | CampaignGiftPurchase;
deleted: boolean;
event: IDType | Event;
nonprofit: IDType | Nonprofit;
object: 'campaign_gift';
supporter: IDType | Supporter;
}
export type CampaignGiftCreated = HoudiniEvent<'campaign_gift.created', CampaignGift>;

View file

@ -1,20 +1,16 @@
// License: LGPL-3.0-or-later
import type { HouID, HoudiniObject, HoudiniEvent, Amount, IDType} from '../../common';
import type { HouID, HoudiniEvent, Amount, IDType} from '../../common';
import type Nonprofit from '..';
import type Campaign from '.';
import type { CampaignGift } from '.';
import Supporter from '../Supporter';
import { Transaction } from '../Supporter';
import type { TrxAssignment } from '../Transaction';
export interface CampaignGiftPurchase extends HoudiniObject<HouID> {
export interface CampaignGiftPurchase extends TrxAssignment {