SumOfUs / Champaign

SumOfUs Online Campaign Platform.
MIT License
49 stars 21 forks source link

Refactoring the Braintree payment processor code #786

Open Tuuleh opened 7 years ago

Tuuleh commented 7 years ago

Refactoring the payment processor code a tad bit (Braintree)

1. Associations

Over time, we've cleaned up the associations and there isn't so much to do there any more, but I would still associate transactions with actions instead of pages.

Wai?

One-off donations are a kind of a type of action, and an action is always created when a one-off transaction is made, so the association is pretty clear. The order of creation also supports this as it is right now, in PaymentProcessor::Braintree::Transaction#transact:

def transact
        @result = ::Braintree::Transaction.sale(options)
        if @result.success?
          @action = ManageBraintreeDonation.create(params: @user.merge(page_id: @page_id), braintree_result: @result, is_subscription: false, store_in_vault: @store_in_vault)
          Payment::Braintree.write_transaction(@result, @page_id, @action.member_id, existing_customer, store_in_vault: @store_in_vault)
        else
          Payment::Braintree.write_transaction(@result, @page_id, nil, existing_customer, store_in_vault: @store_in_vault)
        end
      end

(ManageBraintreeDonation includes ActionBuilder and creates the action).

There are a classes/methods in handling BT transactions with mega long parameter lists and while just passing an action instead of page_id and member_id would simplify things, that isn't enough to trim things down.

Associating transactions with their actions and dropping the page_id column

Actions to be associated with a customer's transactions on a given page can be found through Action.where(page_id: transaction.page_id, member_id: transaction.customer.member_id). In most cases this'll net just one action, as people tend to make just one transaction on a given page. But in case it nets more than one action, they can be associated with the transactions on the page using their created_at field.

@osahyoun you mentioned that you wanted to have a simple way of getting the transactions of a page, e.g. page.transactions. This could be done with a method that calls Payment::Braintree::Transaction.find(action_id: self.actions.donation.pluck(:id)) or possibly something less hideous but with similar logic :) I'm not actually sure how we're doing this now because there isn't a has_many association from pages to transactions.

The code to associate transactions and subscriptions with actions instead of pages needs to go live first with the page_id column still present. Afterwards can then run the script to associate the existing transactions and subscriptions and drop the column.

2. Other stuff

osahyoun commented 7 years ago

Associating transactions with their actions

If we have the action then we also have the page, so it wouldn't be so hard to keep that association... it would make page.transactions a much less expensive operation to run when a page has a large set of transactions. What do you think?

osahyoun commented 7 years ago
  1. Other stuff

I agree with everything under this section. Would like to pair on this with you, if you fancy it. Perhaps when you're this side of the pond.