We need to get billing information from user to charge them at end of the month. We decided to use Stripe as payment provider. It has lots of features. We can use low level APIs or some predefined UI from Stripe. We can keep some of the information on our database too or keep all data at Stripe and just keep Stripe identifier. I tried to find balance between them. Then decided to keep all personal data on Stripe and we only keep Stripe resource identifiers. It helps us to avoid GDPR issues. Also it helps to keep service secure, it prevent to leak confidential data in dump or logs. Stripe has two resources: customer and payment method. We need to save credit card information of users before they create any resource. Then we will charge them using these information. We have new two models: BillingInfo and PaymentMethod. BillingInfo is corresponding for customer on Stripe side. We keep stripe_id for both objects. Each project has a BillingInfo. BillingInfo can be shared by projects. So user can associate same BillingInfo with multiple project. But currently I designed UI and models as each BillingInfo attached to single project. We can relax it based on customer feedbacks. BillingInfo has invoice details such as name, address, country etc. at Stripe. PaymentMethod has metadata about credit card at Stripe. PaymentMethod has order column, users can set a priority for payment methods. We can try to charge them in order. We collect initial BillingInfo and PaymentMethod details on Stripe's UI. We tried to decrease friction for new users. We create Checkout session with setup mode. It's Stripe's UI for saving customer and credit card details. Stripe returns success url with session id. After creation we use our UI to update customer details. Stripe's Checkout session doesn't support updating customer details. If STRIPE_SECRET_KEY isn't provided, billing is disabled.
22 lines
633 B
Ruby
22 lines
633 B
Ruby
# frozen_string_literal: true
|
|
|
|
Sequel.migration do
|
|
change do
|
|
create_table(:billing_info) do
|
|
column :id, :uuid, primary_key: true, default: nil
|
|
column :stripe_id, :text, collate: '"C"', null: false, unique: true
|
|
end
|
|
|
|
create_table(:payment_method) do
|
|
column :id, :uuid, primary_key: true, default: nil
|
|
column :stripe_id, :text, collate: '"C"', null: false, unique: true
|
|
column :order, Integer
|
|
foreign_key :billing_info_id, :billing_info, type: :uuid
|
|
end
|
|
|
|
alter_table(:project) do
|
|
add_foreign_key :billing_info_id, :billing_info, type: :uuid, null: true
|
|
end
|
|
end
|
|
end
|