From 615970612418fa6f640aa777752d139687002890 Mon Sep 17 00:00:00 2001 From: brunomiguelpinto Date: Mon, 9 Sep 2024 12:58:25 +0100 Subject: [PATCH] feat: Add customer_type to Customers (#2544) --- app/models/customer.rb | 22 ++++- ...add_firstname_and_lastname_to_customers.rb | 12 +++ ...06170048_add_customer_type_to_customers.rb | 13 +++ db/schema.rb | 6 +- spec/models/customer_spec.rb | 98 +++++++++++++++++++ 5 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20240906154644_add_firstname_and_lastname_to_customers.rb create mode 100644 db/migrate/20240906170048_add_customer_type_to_customers.rb diff --git a/app/models/customer.rb b/app/models/customer.rb index b841f7241e6..ca107eb1da4 100644 --- a/app/models/customer.rb +++ b/app/models/customer.rb @@ -15,8 +15,15 @@ class Customer < ApplicationRecord :finalize ].freeze - attribute :finalize_zero_amount_invoice, :integer # rails 7.1 check the field exists when defining enum and when running the migration first time is not there + CUSTOMER_TYPES = { + company: 'company', + individual: 'individual' + }.freeze + + attribute :finalize_zero_amount_invoice, :integer enum finalize_zero_amount_invoice: FINALIZE_ZERO_AMOUNT_INVOICE_OPTIONS, _prefix: :finalize_zero_amount_invoice + attribute :customer_type, :string + enum customer_type: CUSTOMER_TYPES, _prefix: :customer_type before_save :ensure_slug @@ -75,6 +82,16 @@ def self.ransackable_attributes(_auth_object = nil) %w[id name external_id email] end + def display_name + names = [legal_name.presence || name.presence] + if firstname.present? || lastname.present? + names << '-' if names.compact.present? + names << firstname + names << lastname + end + names.compact.join(' ') + end + def active_subscription subscriptions.active.order(started_at: :desc).first end @@ -179,11 +196,14 @@ def ensure_slug # city :string # country :string # currency :string +# customer_type :enum # deleted_at :datetime # document_locale :string # email :string # finalize_zero_amount_invoice :integer default("inherit"), not null +# firstname :string # invoice_grace_period :integer +# lastname :string # legal_name :string # legal_number :string # logo_url :string diff --git a/db/migrate/20240906154644_add_firstname_and_lastname_to_customers.rb b/db/migrate/20240906154644_add_firstname_and_lastname_to_customers.rb new file mode 100644 index 00000000000..d51c013450c --- /dev/null +++ b/db/migrate/20240906154644_add_firstname_and_lastname_to_customers.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class AddFirstnameAndLastnameToCustomers < ActiveRecord::Migration[7.1] + def change + safety_assured do + change_table :customers, bulk: true do |t| + t.string :firstname + t.string :lastname + end + end + end +end diff --git a/db/migrate/20240906170048_add_customer_type_to_customers.rb b/db/migrate/20240906170048_add_customer_type_to_customers.rb new file mode 100644 index 00000000000..507f5eb960f --- /dev/null +++ b/db/migrate/20240906170048_add_customer_type_to_customers.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class AddCustomerTypeToCustomers < ActiveRecord::Migration[7.1] + def change + create_enum :customer_type, %w[company individual] + + safety_assured do + change_table :customers do |t| + t.enum :customer_type, enum_type: 'customer_type', null: true + end + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 9f7d4db74d4..df5ce76e902 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: 2024_08_29_093425) do +ActiveRecord::Schema[7.1].define(version: 2024_09_06_170048) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -19,6 +19,7 @@ # Custom types defined in this database. # Note that some types may not work with other database engines. Be careful if changing database. create_enum "billable_metric_weighted_interval", ["seconds"] + create_enum "customer_type", ["company", "individual"] create_enum "subscription_invoicing_reason", ["subscription_starting", "subscription_periodic", "subscription_terminating", "in_advance_charge", "in_advance_charge_periodic", "progressive_billing"] create_table "active_storage_attachments", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| @@ -439,6 +440,9 @@ t.string "shipping_state" t.string "shipping_country" t.integer "finalize_zero_amount_invoice", default: 0, null: false + t.string "firstname" + t.string "lastname" + t.enum "customer_type", enum_type: "customer_type" t.index ["deleted_at"], name: "index_customers_on_deleted_at" t.index ["external_id", "organization_id"], name: "index_customers_on_external_id_and_organization_id", unique: true, where: "(deleted_at IS NULL)" t.index ["organization_id"], name: "index_customers_on_organization_id" diff --git a/spec/models/customer_spec.rb b/spec/models/customer_spec.rb index a15695fffc7..0b4fa2ed8d4 100644 --- a/spec/models/customer_spec.rb +++ b/spec/models/customer_spec.rb @@ -68,6 +68,104 @@ end end + describe '#display_name' do + subject(:customer) { build_stubbed(:customer, name:, legal_name:, firstname:, lastname:) } + + let(:name) { 'ACME Inc' } + let(:legal_name) { 'ACME International Corporation' } + let(:firstname) { 'Thomas' } + let(:lastname) { 'Anderson' } + + context 'when all fields are nil' do + let(:name) { nil } + let(:legal_name) { nil } + let(:firstname) { nil } + let(:lastname) { nil } + + it 'returns an empty string' do + expect(customer.display_name).to eq('') + end + end + + context 'when name and legal_name are nil' do + let(:name) { nil } + let(:legal_name) { nil } + + it 'returns only firstname and lastname if present' do + expect(customer.display_name).to eq('Thomas Anderson') + end + end + + context 'when firstname and lastname are nil' do + let(:firstname) { nil } + let(:lastname) { nil } + + it 'returns only the legal_name' do + expect(customer.display_name).to eq('ACME International Corporation') + end + + context 'when we dont have a legal_name' do + let(:legal_name) { nil } + + it 'returns only the name if present' do + expect(customer.display_name).to eq('ACME Inc') + end + end + end + + context 'when name is present and both firstname and lastname are present' do + let(:legal_name) { nil } + + it 'returns name with firstname and lastname' do + expect(customer.display_name).to eq('ACME Inc - Thomas Anderson') + end + end + + context 'when legal_name is present and both firstname and lastname are present' do + let(:name) { nil } + + it 'returns legal_name with firstname and lastname' do + expect(customer.display_name).to eq('ACME International Corporation - Thomas Anderson') + end + end + + context 'when all fields are present' do + it 'returns legal_name with firstname and lastname' do + expect(customer.display_name).to eq('ACME International Corporation - Thomas Anderson') + end + end + end + + describe 'customer_type enum' do + subject(:customer) { build_stubbed(:customer, customer_type:) } + + context 'when customer_type is company' do + let(:customer_type) { 'company' } + + it 'identifies the customer as a company' do + expect(customer.customer_type).to eq('company') + expect(customer.customer_type_company?).to be true + end + end + + context 'when customer_type is individual' do + let(:customer_type) { 'individual' } + + it 'identifies the customer as an individual' do + expect(customer.customer_type).to eq('individual') + expect(customer.customer_type_individual?).to be true + end + end + + context 'when customer_type is nil' do + subject(:customer) { build(:customer) } + + it 'defaults to nil for existing customers' do + expect(customer.customer_type).to be_nil + end + end + end + describe 'preferred_document_locale' do subject(:customer) do described_class.new(