The payment method has an `order` column. I intended to add this feature initially to allow customers to prioritize their payment methods, so they can select a primary and a backup option. However, we haven't added it to the UI yet, so all `order` columns are currently nil. When a payment fails, customers simply log in to the console and add a new payment method while keeping the old one. When we try to charge the invoice, we start with the oldest method, which probably isn't working anymore. We should charge from the newest method to the oldest to reduce our payment failure rate.
70 lines
2.1 KiB
Ruby
70 lines
2.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require_relative "../model"
|
|
require "stripe"
|
|
require "countries"
|
|
require "excon"
|
|
|
|
class BillingInfo < Sequel::Model
|
|
one_to_many :payment_methods, order: Sequel.desc(:created_at)
|
|
one_to_one :project
|
|
|
|
include ResourceMethods
|
|
|
|
def stripe_data
|
|
if (Stripe.api_key = Config.stripe_secret_key)
|
|
@stripe_data ||= begin
|
|
data = Stripe::Customer.retrieve(stripe_id)
|
|
address = data["address"]
|
|
{
|
|
"name" => data["name"],
|
|
"email" => data["email"],
|
|
"address" => [address["line1"], address["line2"]].compact.join(" "),
|
|
"country" => address["country"],
|
|
"city" => address["city"],
|
|
"state" => address["state"],
|
|
"postal_code" => address["postal_code"],
|
|
"tax_id" => data["metadata"]["tax_id"],
|
|
"company_name" => data["metadata"]["company_name"]
|
|
}
|
|
end
|
|
end
|
|
end
|
|
|
|
def country
|
|
ISO3166::Country.new(stripe_data["country"])
|
|
end
|
|
|
|
def after_destroy
|
|
if (Stripe.api_key = Config.stripe_secret_key)
|
|
Stripe::Customer.delete(stripe_id)
|
|
end
|
|
super
|
|
end
|
|
|
|
def validate_vat
|
|
response = Excon.get("https://ec.europa.eu/taxation_customs/vies/rest-api/ms/#{stripe_data["country"]}/vat/#{stripe_data["tax_id"]}", expects: 200)
|
|
status = JSON.parse(response.body)["userError"]
|
|
if status == "VALID"
|
|
true
|
|
elsif status == "INVALID" || status == "INVALID_INPUT"
|
|
false
|
|
else
|
|
fail "Unexpected response from VAT service: #{status}"
|
|
end
|
|
end
|
|
end
|
|
|
|
# Table: billing_info
|
|
# Columns:
|
|
# id | uuid | PRIMARY KEY
|
|
# stripe_id | text | NOT NULL
|
|
# created_at | timestamp with time zone | NOT NULL DEFAULT now()
|
|
# valid_vat | boolean |
|
|
# Indexes:
|
|
# billing_info_pkey | PRIMARY KEY btree (id)
|
|
# billing_info_stripe_id_key | UNIQUE btree (stripe_id)
|
|
# Referenced By:
|
|
# payment_method | payment_method_billing_info_id_fkey | (billing_info_id) REFERENCES billing_info(id)
|
|
# project | project_billing_info_id_fkey | (billing_info_id) REFERENCES billing_info(id)
|