feat: Add company model and API with tests (#12548)

# Pull Request Template

## Description

* add Company model with validations for name, domain, description and
  avatar
* Add database migration fo
* Implement endpoints for company CRUD operations
* Add optional company relationship for contacts
* Add test for models, controllers, factories and policies
* Add authorization policies restricting delete to admins
* support JSON API responses
Please include a summary of the change and issue(s) fixed. Also, mention
relevant motivation, context, and any dependencies that this change
requires.

Fixes #(cw-5650)

## Type of change

Please delete options that are not relevant.

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
- [ ] This change requires a documentation update

## How Has This Been Tested?

Tests are implemented using `RSpec`

```
$ bundle exec rails db:migrate
$ bundle exec rspec spec/models/company_spec.rb spec/controllers/api/v1/accounts/companies_controller_spec.rb
```

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
This commit is contained in:
Vinay Keerthi
2025-10-08 20:23:43 +05:30
committed by GitHub
parent 606adffeeb
commit 170ea7691f
23 changed files with 398 additions and 2 deletions

View File

@@ -0,0 +1,14 @@
class CreateCompanies < ActiveRecord::Migration[7.1]
def change
create_table :companies do |t|
t.string :name, null: false
t.string :domain
t.text :description
t.references :account, null: false
t.timestamps
end
add_index :companies, [:name, :account_id]
add_index :companies, [:domain, :account_id]
end
end

View File

@@ -0,0 +1,5 @@
class AddCompanyToContacts < ActiveRecord::Migration[7.1]
def change
add_reference :contacts, :company, null: true
end
end

View File

@@ -570,6 +570,18 @@ ActiveRecord::Schema[7.1].define(version: 2025_10_03_091242) do
t.index ["phone_number"], name: "index_channel_whatsapp_on_phone_number", unique: true
end
create_table "companies", force: :cascade do |t|
t.string "name", null: false
t.string "domain"
t.text "description"
t.bigint "account_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["account_id"], name: "index_companies_on_account_id"
t.index ["domain", "account_id"], name: "index_companies_on_domain_and_account_id"
t.index ["name", "account_id"], name: "index_companies_on_name_and_account_id"
end
create_table "contact_inboxes", force: :cascade do |t|
t.bigint "contact_id"
t.bigint "inbox_id"
@@ -602,6 +614,7 @@ ActiveRecord::Schema[7.1].define(version: 2025_10_03_091242) do
t.string "location", default: ""
t.string "country_code", default: ""
t.boolean "blocked", default: false, null: false
t.bigint "company_id"
t.index "lower((email)::text), account_id", name: "index_contacts_on_lower_email_account_id"
t.index ["account_id", "contact_type"], name: "index_contacts_on_account_id_and_contact_type"
t.index ["account_id", "email", "phone_number", "identifier"], name: "index_contacts_on_nonempty_fields", where: "(((email)::text <> ''::text) OR ((phone_number)::text <> ''::text) OR ((identifier)::text <> ''::text))"
@@ -609,6 +622,7 @@ ActiveRecord::Schema[7.1].define(version: 2025_10_03_091242) do
t.index ["account_id"], name: "index_contacts_on_account_id"
t.index ["account_id"], name: "index_resolved_contact_account_id", where: "(((email)::text <> ''::text) OR ((phone_number)::text <> ''::text) OR ((identifier)::text <> ''::text))"
t.index ["blocked"], name: "index_contacts_on_blocked"
t.index ["company_id"], name: "index_contacts_on_company_id"
t.index ["email", "account_id"], name: "uniq_email_per_account_contact", unique: true
t.index ["identifier", "account_id"], name: "uniq_identifier_per_account_contact", unique: true
t.index ["name", "email", "phone_number", "identifier"], name: "index_contacts_on_name_email_phone_number_identifier", opclass: :gin_trgm_ops, using: :gin