mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-07-27 17:19:39 +02:00
Add backend for property account details
This commit is contained in:
parent
4433488562
commit
5ea2fd5a23
17 changed files with 258 additions and 2 deletions
34
app/controllers/properties_controller.rb
Normal file
34
app/controllers/properties_controller.rb
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
class PropertiesController < ApplicationController
|
||||||
|
before_action :set_account, only: :update
|
||||||
|
|
||||||
|
def create
|
||||||
|
account = Current.family.accounts.create!(account_params)
|
||||||
|
account.sync_later
|
||||||
|
redirect_to account, notice: t(".success")
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@account.update!(account_params)
|
||||||
|
@account.sync_later
|
||||||
|
redirect_to @account, notice: t(".success")
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_account
|
||||||
|
@account = Current.family.accounts.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def account_params
|
||||||
|
params.require(:account)
|
||||||
|
.permit(
|
||||||
|
:name, :balance, :currency, :accountable_type,
|
||||||
|
accountable_attributes: [
|
||||||
|
:id,
|
||||||
|
:year_built,
|
||||||
|
:area,
|
||||||
|
address_attributes: [ :line1, :line2, :locality, :region, :country, :postal_code ]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
2
app/helpers/properties_helper.rb
Normal file
2
app/helpers/properties_helper.rb
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
module PropertiesHelper
|
||||||
|
end
|
|
@ -28,6 +28,8 @@ class Account < ApplicationRecord
|
||||||
|
|
||||||
delegated_type :accountable, types: Accountable::TYPES, dependent: :destroy
|
delegated_type :accountable, types: Accountable::TYPES, dependent: :destroy
|
||||||
|
|
||||||
|
accepts_nested_attributes_for :accountable
|
||||||
|
|
||||||
delegate :value, :series, to: :accountable
|
delegate :value, :series, to: :accountable
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
|
|
26
app/models/address.rb
Normal file
26
app/models/address.rb
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
class Address < ApplicationRecord
|
||||||
|
belongs_to :addressable, polymorphic: true
|
||||||
|
|
||||||
|
validates :line1, :locality, presence: true
|
||||||
|
validates :region, presence: true, format: { with: /\A[A-Z]{1,3}(-[A-Z\d]{1,3})?\z/, message: "must be a valid ISO3166-2 code" }
|
||||||
|
validates :country, presence: true, format: { with: /\A[A-Z]{2}\z/, message: "must be a valid ISO3166-1 Alpha-2 code" }
|
||||||
|
validates :postal_code, presence: true, if: :postal_code_required?
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
I18n.t("address.format",
|
||||||
|
line1: line1,
|
||||||
|
line2: line2,
|
||||||
|
county: county,
|
||||||
|
locality: locality,
|
||||||
|
region: region,
|
||||||
|
country: country,
|
||||||
|
postal_code: postal_code
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def postal_code_required?
|
||||||
|
country.in?(%w[US CA GB])
|
||||||
|
end
|
||||||
|
end
|
20
app/models/measurement.rb
Normal file
20
app/models/measurement.rb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
class Measurement
|
||||||
|
include ActiveModel::Validations
|
||||||
|
|
||||||
|
attr_reader :value, :unit
|
||||||
|
|
||||||
|
VALID_UNITS = %w[sqft sqm]
|
||||||
|
|
||||||
|
validates :unit, inclusion: { in: VALID_UNITS }
|
||||||
|
validates :value, presence: true
|
||||||
|
|
||||||
|
def initialize(value, unit)
|
||||||
|
@value = value.to_f
|
||||||
|
@unit = unit.to_s.downcase.strip
|
||||||
|
validate!
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"#{@value.to_i} #{@unit}"
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,3 +1,11 @@
|
||||||
class Property < ApplicationRecord
|
class Property < ApplicationRecord
|
||||||
include Accountable
|
include Accountable
|
||||||
|
|
||||||
|
has_one :address, as: :addressable, dependent: :destroy
|
||||||
|
|
||||||
|
accepts_nested_attributes_for :address
|
||||||
|
|
||||||
|
def area
|
||||||
|
Measurement.new(area_value, area_unit)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -29,3 +29,4 @@ ignore_unused:
|
||||||
- 'helpers.submit.*' # i18n-tasks does not detect used at forms
|
- 'helpers.submit.*' # i18n-tasks does not detect used at forms
|
||||||
- 'helpers.label.*' # i18n-tasks does not detect used at forms
|
- 'helpers.label.*' # i18n-tasks does not detect used at forms
|
||||||
- 'accounts.show.sync_message_*' # messages generated in the sync ActiveJob
|
- 'accounts.show.sync_message_*' # messages generated in the sync ActiveJob
|
||||||
|
- 'address.attributes.*'
|
||||||
|
|
15
config/locales/models/address/en.yml
Normal file
15
config/locales/models/address/en.yml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
en:
|
||||||
|
address:
|
||||||
|
attributes:
|
||||||
|
country: Country
|
||||||
|
line1: Address Line 1
|
||||||
|
line2: Address Line 2
|
||||||
|
locality: Locality
|
||||||
|
postal_code: Postal Code
|
||||||
|
region: Region
|
||||||
|
format: |-
|
||||||
|
%{line1}
|
||||||
|
%{line2}
|
||||||
|
%{locality}, %{region} %{postal_code}
|
||||||
|
%{country}
|
7
config/locales/views/properties/en.yml
Normal file
7
config/locales/views/properties/en.yml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
en:
|
||||||
|
properties:
|
||||||
|
create:
|
||||||
|
success: Property created successfully
|
||||||
|
update:
|
||||||
|
success: Property updated successfully
|
|
@ -89,6 +89,8 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
resources :properties, only: %i[ create update ]
|
||||||
|
|
||||||
resources :transactions, only: %i[ index new create ] do
|
resources :transactions, only: %i[ index new create ] do
|
||||||
collection do
|
collection do
|
||||||
post "bulk_delete"
|
post "bulk_delete"
|
||||||
|
|
16
db/migrate/20240822174006_create_addresses.rb
Normal file
16
db/migrate/20240822174006_create_addresses.rb
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
class CreateAddresses < ActiveRecord::Migration[7.2]
|
||||||
|
def change
|
||||||
|
create_table :addresses, id: :uuid do |t|
|
||||||
|
t.references :addressable, type: :uuid, polymorphic: true
|
||||||
|
t.string :line1
|
||||||
|
t.string :line2
|
||||||
|
t.string :county
|
||||||
|
t.string :locality
|
||||||
|
t.string :region
|
||||||
|
t.string :country
|
||||||
|
t.integer :postal_code
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
7
db/migrate/20240822180845_add_property_attributes.rb
Normal file
7
db/migrate/20240822180845_add_property_attributes.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
class AddPropertyAttributes < ActiveRecord::Migration[7.2]
|
||||||
|
def change
|
||||||
|
add_column :properties, :year_built, :integer
|
||||||
|
add_column :properties, :area_value, :integer
|
||||||
|
add_column :properties, :area_unit, :string
|
||||||
|
end
|
||||||
|
end
|
20
db/schema.rb
generated
20
db/schema.rb
generated
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[7.2].define(version: 2024_08_17_144454) do
|
ActiveRecord::Schema[7.2].define(version: 2024_08_22_180845) do
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "pgcrypto"
|
enable_extension "pgcrypto"
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -152,6 +152,21 @@ ActiveRecord::Schema[7.2].define(version: 2024_08_17_144454) do
|
||||||
t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
|
t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "addresses", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
|
||||||
|
t.string "addressable_type"
|
||||||
|
t.uuid "addressable_id"
|
||||||
|
t.string "line1"
|
||||||
|
t.string "line2"
|
||||||
|
t.string "county"
|
||||||
|
t.string "locality"
|
||||||
|
t.string "region"
|
||||||
|
t.string "country"
|
||||||
|
t.integer "postal_code"
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["addressable_type", "addressable_id"], name: "index_addresses_on_addressable"
|
||||||
|
end
|
||||||
|
|
||||||
create_table "categories", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
|
create_table "categories", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
|
||||||
t.string "name", null: false
|
t.string "name", null: false
|
||||||
t.string "color", default: "#6172F3", null: false
|
t.string "color", default: "#6172F3", null: false
|
||||||
|
@ -358,6 +373,9 @@ ActiveRecord::Schema[7.2].define(version: 2024_08_17_144454) do
|
||||||
create_table "properties", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
|
create_table "properties", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
|
t.integer "year_built"
|
||||||
|
t.integer "area_value"
|
||||||
|
t.string "area_unit"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "securities", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
|
create_table "securities", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
|
||||||
|
|
71
test/controllers/properties_controller_test.rb
Normal file
71
test/controllers/properties_controller_test.rb
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
require "test_helper"
|
||||||
|
|
||||||
|
class PropertiesControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
setup do
|
||||||
|
sign_in @user = users(:family_admin)
|
||||||
|
@account = accounts(:property)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "creates property" do
|
||||||
|
assert_difference [ "Account.count", "Property.count" ] do
|
||||||
|
post properties_path, params: {
|
||||||
|
account: {
|
||||||
|
name: "Property",
|
||||||
|
balance: 500000,
|
||||||
|
currency: "USD",
|
||||||
|
accountable_type: "Property",
|
||||||
|
accountable_attributes: {
|
||||||
|
year_built: 2002,
|
||||||
|
area_value: 1000,
|
||||||
|
area_unit: "sqft",
|
||||||
|
address_attributes: {
|
||||||
|
line1: "123 Main St",
|
||||||
|
line2: "Apt 1",
|
||||||
|
locality: "Los Angeles",
|
||||||
|
region: "CA", # ISO3166-2 code
|
||||||
|
country: "US", # ISO3166-1 Alpha-2 code
|
||||||
|
postal_code: "90001"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
created_account = Account.order(:created_at).last
|
||||||
|
|
||||||
|
assert_redirected_to account_path(created_account)
|
||||||
|
assert_equal "Property created successfully", flash[:notice]
|
||||||
|
assert_enqueued_with(job: AccountSyncJob)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "updates property" do
|
||||||
|
assert_no_difference [ "Account.count", "Property.count" ] do
|
||||||
|
patch property_path(@account), params: {
|
||||||
|
account: {
|
||||||
|
name: "Updated Property",
|
||||||
|
balance: 500000,
|
||||||
|
currency: "USD",
|
||||||
|
accountable_type: "Property",
|
||||||
|
accountable_attributes: {
|
||||||
|
id: @account.accountable_id,
|
||||||
|
year_built: 2002,
|
||||||
|
area_value: 1000,
|
||||||
|
area_unit: "sqft",
|
||||||
|
address_attributes: {
|
||||||
|
line1: "123 Main St",
|
||||||
|
line2: "Apt 1",
|
||||||
|
locality: "Los Angeles",
|
||||||
|
region: "CA", # ISO3166-2 code
|
||||||
|
country: "US", # ISO3166-1 Alpha-2 code
|
||||||
|
postal_code: "90001"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_redirected_to account_path(@account)
|
||||||
|
assert_equal "Property updated successfully", flash[:notice]
|
||||||
|
assert_enqueued_with(job: AccountSyncJob)
|
||||||
|
end
|
||||||
|
end
|
9
test/fixtures/addresses.yml
vendored
Normal file
9
test/fixtures/addresses.yml
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
one:
|
||||||
|
line1: 123 Main Street
|
||||||
|
line2: Apt 4B
|
||||||
|
locality: Los Angeles
|
||||||
|
region: CA
|
||||||
|
country: US
|
||||||
|
postal_code: 90001
|
||||||
|
addressable: one
|
||||||
|
addressable_type: Property
|
5
test/fixtures/properties.yml
vendored
5
test/fixtures/properties.yml
vendored
|
@ -1 +1,4 @@
|
||||||
one: { }
|
one:
|
||||||
|
year_built: 2002
|
||||||
|
area_value: 1000
|
||||||
|
area_unit: "sqft"
|
15
test/models/address_test.rb
Normal file
15
test/models/address_test.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
require "test_helper"
|
||||||
|
|
||||||
|
class AddressTest < ActiveSupport::TestCase
|
||||||
|
test "can print a formatted address" do
|
||||||
|
address = Address.new(
|
||||||
|
line1: "123 Main St",
|
||||||
|
locality: "San Francisco",
|
||||||
|
region: "CA",
|
||||||
|
country: "US",
|
||||||
|
postal_code: "94101"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert_equal "123 Main St\n\nSan Francisco, CA 94101\nUS", address.to_s
|
||||||
|
end
|
||||||
|
end
|
Loading…
Add table
Add a link
Reference in a new issue