From 2afb0d20c1032a7dc8705d8e15a675620f7e5487 Mon Sep 17 00:00:00 2001 From: Zee Spencer <50284+zspencer@users.noreply.github.com> Date: Fri, 26 Jan 2024 23:22:27 -0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20`Payout#issue`=20creates=20`Payment?= =?UTF-8?q?`=20for=20`Trust#beneficiaries`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This sketches in the `Payout#issue` method's line-of-action, which is to iterate through the `Payout#trust#beneficiaries` and add a `Payment` to the set of `Payout#payments` for the per-beneficiary amount. That said, there's a few outstanding questions we'll probably want to add some tests to interrogate, especially around: 1. What happens if the method is ran twice with the same data? 2. What about if the set of `Payout#trust#beneficiaries` is changed between calls to `Payout#issue`? 3. What happens when the `Payout#payout_amount` doesn't divide evenly between the `Payout#beneficiaries? --- app/furniture/tobias.rb | 2 + app/furniture/tobias/beneficiary.rb | 9 +++++ app/furniture/tobias/payment.rb | 7 ++++ app/furniture/tobias/payout.rb | 19 ++++++++++ app/furniture/tobias/record.rb | 9 +++++ app/furniture/tobias/trust.rb | 8 ++++ .../20240127063826_create_tobias_payouts.rb | 27 +++++++++++++ db/schema.rb | 38 ++++++++++++++++++- spec/tobias/factories/beneficiary_factory.rb | 5 +++ spec/tobias/factories/payout_factory.rb | 7 ++++ spec/tobias/factories/trust_factory.rb | 5 +++ spec/{furniture => }/tobias/payout_spec.rb | 6 ++- 12 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 app/furniture/tobias.rb create mode 100644 app/furniture/tobias/beneficiary.rb create mode 100644 app/furniture/tobias/payment.rb create mode 100644 app/furniture/tobias/payout.rb create mode 100644 app/furniture/tobias/record.rb create mode 100644 app/furniture/tobias/trust.rb create mode 100644 db/migrate/20240127063826_create_tobias_payouts.rb create mode 100644 spec/tobias/factories/beneficiary_factory.rb create mode 100644 spec/tobias/factories/payout_factory.rb create mode 100644 spec/tobias/factories/trust_factory.rb rename spec/{furniture => }/tobias/payout_spec.rb (60%) diff --git a/app/furniture/tobias.rb b/app/furniture/tobias.rb new file mode 100644 index 000000000..0dd845ca6 --- /dev/null +++ b/app/furniture/tobias.rb @@ -0,0 +1,2 @@ +class Tobias +end diff --git a/app/furniture/tobias/beneficiary.rb b/app/furniture/tobias/beneficiary.rb new file mode 100644 index 000000000..44f7a35c3 --- /dev/null +++ b/app/furniture/tobias/beneficiary.rb @@ -0,0 +1,9 @@ +class Tobias + class Beneficiary < Record + self.table_name = "tobias_beneficiaries" + + belongs_to :trust + + has_many :payments + end +end diff --git a/app/furniture/tobias/payment.rb b/app/furniture/tobias/payment.rb new file mode 100644 index 000000000..db0b0d18b --- /dev/null +++ b/app/furniture/tobias/payment.rb @@ -0,0 +1,7 @@ +class Tobias + class Payment < Record + self.table_name = "tobias_payments" + + monetize :amount_cents + end +end diff --git a/app/furniture/tobias/payout.rb b/app/furniture/tobias/payout.rb new file mode 100644 index 000000000..d37aff9fd --- /dev/null +++ b/app/furniture/tobias/payout.rb @@ -0,0 +1,19 @@ +class Tobias + class Payout < ApplicationRecord + self.table_name = "tobias_payouts" + + belongs_to :trust + has_many :beneficiaries, through: :trust + has_many :payments + + monetize :payout_amount_cents + + def issue + per_beneficiary_amount = (payout_amount / beneficiaries.count) + beneficiaries.each do |beneficiary| + + payments.create_with(amount: per_beneficiary_amount).find_or_create_by(beneficiary_id: beneficiary.id) + end + end + end +end diff --git a/app/furniture/tobias/record.rb b/app/furniture/tobias/record.rb new file mode 100644 index 000000000..6763703c1 --- /dev/null +++ b/app/furniture/tobias/record.rb @@ -0,0 +1,9 @@ +class Tobias + class Record < ApplicationRecord + self.abstract_class = true + + def self.model_name + @_model_name ||= ActiveModel::Name.new(self, ::Tobias) + end + end +end diff --git a/app/furniture/tobias/trust.rb b/app/furniture/tobias/trust.rb new file mode 100644 index 000000000..74d13943a --- /dev/null +++ b/app/furniture/tobias/trust.rb @@ -0,0 +1,8 @@ +class Tobias + class Trust < Record + self.table_name = "tobias_trusts" + + has_many :beneficiaries + + end +end diff --git a/db/migrate/20240127063826_create_tobias_payouts.rb b/db/migrate/20240127063826_create_tobias_payouts.rb new file mode 100644 index 000000000..9ae921836 --- /dev/null +++ b/db/migrate/20240127063826_create_tobias_payouts.rb @@ -0,0 +1,27 @@ +class CreateTobiasPayouts < ActiveRecord::Migration[7.1] + def change + create_table :tobias_trusts, id: :uuid do |t| + t.timestamps + end + + create_table :tobias_beneficiaries, id: :uuid do |t| + t.references :trust, type: :uuid, foreign_key: {to_table: :tobias_trusts} + + t.timestamps + end + + create_table :tobias_payouts, id: :uuid do |t| + t.monetize :payout_amount + t.references :trust, type: :uuid, foreign_key: {to_table: :tobias_trusts} + t.timestamps + end + + create_table :tobias_payments, id: :uuid do |t| + t.references :payout, type: :uuid, foreign_key: {to_table: :tobias_payouts} + t.references :beneficiary, type: :uuid, foreign_key: {to_table: :tobias_beneficiaries} + t.monetize :amount + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index bf0be70ec..97d4ea151 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2023_12_21_025246) do +ActiveRecord::Schema[7.1].define(version: 2024_01_27_063826) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -289,6 +289,38 @@ t.index ["slug", "client_id"], name: "index_spaces_on_slug_and_client_id", unique: true end + create_table "tobias_beneficiaries", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.uuid "trust_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["trust_id"], name: "index_tobias_beneficiaries_on_trust_id" + end + + create_table "tobias_payments", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.uuid "payout_id" + t.uuid "beneficiary_id" + t.integer "amount_cents", default: 0, null: false + t.string "amount_currency", default: "USD", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["beneficiary_id"], name: "index_tobias_payments_on_beneficiary_id" + t.index ["payout_id"], name: "index_tobias_payments_on_payout_id" + end + + create_table "tobias_payouts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.integer "payout_amount_cents", default: 0, null: false + t.string "payout_amount_currency", default: "USD", null: false + t.uuid "trust_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["trust_id"], name: "index_tobias_payouts_on_trust_id" + end + + create_table "tobias_trusts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "utility_hookups", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.uuid "space_id" t.string "name", null: false @@ -319,4 +351,8 @@ add_foreign_key "memberships", "invitations" add_foreign_key "space_agreements", "spaces" add_foreign_key "spaces", "rooms", column: "entrance_id" + add_foreign_key "tobias_beneficiaries", "tobias_trusts", column: "trust_id" + add_foreign_key "tobias_payments", "tobias_beneficiaries", column: "beneficiary_id" + add_foreign_key "tobias_payments", "tobias_payouts", column: "payout_id" + add_foreign_key "tobias_payouts", "tobias_trusts", column: "trust_id" end diff --git a/spec/tobias/factories/beneficiary_factory.rb b/spec/tobias/factories/beneficiary_factory.rb new file mode 100644 index 000000000..b1206ba10 --- /dev/null +++ b/spec/tobias/factories/beneficiary_factory.rb @@ -0,0 +1,5 @@ +FactoryBot.define do + factory :tobias_beneficiary, class: "Tobias::Beneficiary" do + + end +end diff --git a/spec/tobias/factories/payout_factory.rb b/spec/tobias/factories/payout_factory.rb new file mode 100644 index 000000000..f027e7300 --- /dev/null +++ b/spec/tobias/factories/payout_factory.rb @@ -0,0 +1,7 @@ +require_relative "trust_factory" + +FactoryBot.define do + factory :tobias_payout, class: "Tobias::Payout" do + association(:trust, factory: :tobias_trust) + end +end diff --git a/spec/tobias/factories/trust_factory.rb b/spec/tobias/factories/trust_factory.rb new file mode 100644 index 000000000..4c1892065 --- /dev/null +++ b/spec/tobias/factories/trust_factory.rb @@ -0,0 +1,5 @@ +FactoryBot.define do + factory :tobias_trust, class: "Tobias::Trust" do + + end +end diff --git a/spec/furniture/tobias/payout_spec.rb b/spec/tobias/payout_spec.rb similarity index 60% rename from spec/furniture/tobias/payout_spec.rb rename to spec/tobias/payout_spec.rb index 31472ed93..ee3e52181 100644 --- a/spec/furniture/tobias/payout_spec.rb +++ b/spec/tobias/payout_spec.rb @@ -1,16 +1,18 @@ require "rails_helper" +require_relative "factories/payout_factory" +require_relative "factories/beneficiary_factory" RSpec.describe Tobias::Payout do describe "#issue" do it "issues a Payment to each Beneficiary for their share of the #payout_amount" do payout = create(:tobias_payout, payout_amount_cents: 150_00) - beneficiaries = create_list(10, :tobias_beneficiary, trust: payout.trust) + beneficiaries = create_list(:tobias_beneficiary, 10, trust: payout.trust) payout.issue beneficiaries.each do |beneficiary| - expect(beneficiary.payments).to exist(amount_cents: 15) + expect(beneficiary.payments).to exist(amount_cents: 15_00) end end end