Skip to content

Commit

Permalink
Migrate contact's metadata into native columns (#1670)
Browse files Browse the repository at this point in the history
  • Loading branch information
samnang authored Jan 8, 2025
1 parent 9d542d9 commit ab53653
Show file tree
Hide file tree
Showing 26 changed files with 200 additions and 69 deletions.
1 change: 1 addition & 0 deletions app/controllers/api/v1/addresses_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ def index
def create
validate_request_schema(
with: ::V1::BeneficiaryAddressRequestSchema,
schema_options: { beneficiary: },
location: ->(resource) { api_v1_beneficiary_address_path(beneficiary, resource) }
) do |permitted_params|
beneficiary.addresses.create!(permitted_params)
Expand Down
5 changes: 4 additions & 1 deletion app/controllers/api/v1/beneficiaries_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ def create
# TODO: can remove this once after we rename the model to beneficiary
location: ->(resource) { api_v1_beneficiary_path(resource) }
) do |permitted_params|
CreateBeneficiaryWithAddress.new(permitted_params).call
CreateBeneficiaryWithAddress.new(
account: current_account,
**permitted_params
).call
end
end

Expand Down
4 changes: 4 additions & 0 deletions app/models/beneficiary_address.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
class BeneficiaryAddress < ApplicationRecord
extend Enumerize

enumerize :iso_country_code, in: ISO3166::Country.codes.freeze

belongs_to :beneficiary, class_name: "Contact"
end
2 changes: 2 additions & 0 deletions app/models/call_flow_logic/ews_laos_registration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,10 @@ def update_contact
district = DISTRICTS.find { |d| d.code == phone_call_metadata(:district_code) }

contact.addresses.find_or_create_by!(
iso_country_code: "LA",
iso_region_code: district.province.iso3166,
administrative_division_level_2_code: district.code,
administrative_division_level_2_name: district.name_en,
)

registered_districts = contact.metadata.fetch("registered_districts", [])
Expand Down
5 changes: 4 additions & 1 deletion app/models/call_flow_logic/ews_registration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -369,9 +369,12 @@ def update_contact
commune = Pumi::Commune.find_by_id(phone_call_metadata(:commune_code))

contact.addresses.find_or_create_by!(
iso_country_code: "KH",
iso_region_code: commune.province.iso3166_2,
administrative_division_level_2_code: commune.district_id,
administrative_division_level_3_code: commune.id
administrative_division_level_2_name: commune.district.name_en,
administrative_division_level_3_code: commune.id,
administrative_division_level_3_name: commune.name_en,
)

commune_ids = contact.metadata.fetch("commune_ids", [])
Expand Down
13 changes: 9 additions & 4 deletions app/models/call_flow_logic/mama_info_registration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -425,17 +425,22 @@ def persist_unconfirmed_date_of_birth
end

def persist_date_of_birth
contact = phone_call.contact
date_of_birth = metadata(phone_call, :unconfirmed_date_of_birth)
update_metadata!(phone_call, date_of_birth: date_of_birth)
update_metadata!(phone_call.contact, date_of_birth: date_of_birth)
phone_call.contact.metadata.delete("deregistered_at")
phone_call.contact.save!
update_metadata!(contact, date_of_birth: date_of_birth)
contact.metadata.delete("deregistered_at")
contact.date_of_birth = date_of_birth
contact.status = :active
contact.save!
end

def persist_deregistered
contact = phone_call.contact
update_metadata!(phone_call.contact, deregistered_at: Time.current)
phone_call.contact.metadata.delete("date_of_birth")
phone_call.contact.save!
contact.status = :disabled
contact.save!
end

def play(filename, response)
Expand Down
16 changes: 3 additions & 13 deletions app/models/contact.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
class Contact < ApplicationRecord
extend Enumerize

COUNTRY_CODES = ISO3166::Country.codes.freeze

include MsisdnHelpers
include MetadataHelpers

enumerize :status, in: [ :active, :disabled ], scope: true
enumerize :gender, in: { male: "M", female: "F" }, scope: true
enumerize :iso_country_code, in: COUNTRY_CODES, scope: true
enumerize :status, in: [ :active, :disabled ], scope: :shallow
enumerize :gender, in: { male: "M", female: "F" }
enumerize :iso_country_code, in: ISO3166::Country.codes.freeze

belongs_to :account

Expand All @@ -30,15 +28,7 @@ class Contact < ApplicationRecord
to: :account,
allow_nil: true

before_create :assign_iso_country_code, unless: :iso_country_code?

def self.jsonapi_serializer_class
BeneficiarySerializer
end

private

def assign_iso_country_code
self.iso_country_code = PhonyRails.country_from_number(msisdn)
end
end
11 changes: 0 additions & 11 deletions app/request_schemas/v1/base_request_schema.rb

This file was deleted.

9 changes: 3 additions & 6 deletions app/request_schemas/v1/beneficiary_address_request_schema.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
module V1
class BeneficiaryAddressRequestSchema < BaseRequestSchema
class BeneficiaryAddressRequestSchema < JSONAPIRequestSchema
params do
required(:data).value(:hash).schema do
required(:type).filled(:str?, eql?: "address")
required(:attributes).value(:hash).schema do
required(:iso_region_code).maybe(:string)
required(:iso_country_code).filled(Types::UpcaseString, included_in?: Contact.iso_country_code.values)
required(:iso_region_code).filled(:string)
optional(:administrative_division_level_2_code).maybe(:string)
optional(:administrative_division_level_2_name).maybe(:string)
optional(:administrative_division_level_3_code).maybe(:string)
Expand All @@ -14,9 +15,5 @@ class BeneficiaryAddressRequestSchema < BaseRequestSchema
end
end
end

def output
super.except(:account)
end
end
end
5 changes: 3 additions & 2 deletions app/request_schemas/v1/beneficiary_request_schema.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module V1
class BeneficiaryRequestSchema < BaseRequestSchema
class BeneficiaryRequestSchema < JSONAPIRequestSchema
params do
required(:data).value(:hash).schema do
required(:type).filled(:str?, eql?: "beneficiary")
Expand All @@ -12,7 +12,8 @@ class BeneficiaryRequestSchema < BaseRequestSchema
optional(:metadata).value(:hash)

optional(:address).filled(:hash).schema do
required(:iso_region_code).maybe(:string)
required(:iso_country_code).filled(Types::UpcaseString, included_in?: Contact.iso_country_code.values)
required(:iso_region_code).filled(:string)
optional(:administrative_division_level_2_code).maybe(:string)
optional(:administrative_division_level_2_name).maybe(:string)
optional(:administrative_division_level_3_code).maybe(:string)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module V1
class UpdateBeneficiaryRequestSchema < BaseRequestSchema
class UpdateBeneficiaryRequestSchema < JSONAPIRequestSchema
params do
required(:data).value(:hash).schema do
required(:id).filled(:integer)
Expand Down
2 changes: 1 addition & 1 deletion app/serailizers/beneficiary_address_serializer.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
class BeneficiaryAddressSerializer < ResourceSerializer
set_type :address

attributes :iso_region_code,
attributes :iso_country_code, :iso_region_code,
:administrative_division_level_2_code,
:administrative_division_level_2_name,
:administrative_division_level_3_code,
Expand Down
21 changes: 20 additions & 1 deletion app/workflows/handle_phone_call_event.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
class HandlePhoneCallEvent < ApplicationWorkflow
attr_accessor :url, :params

ACCOUNT_COUNTRY_CODES = {
2 => "SO",
3 => "KH",
4 => "KH",
7 => "SL",
8 => "TH",
11 => "US",
45 => "MX",
77 => "EG",
110 => "ZM",
143 => "KH",
209 => "LA"
}


def initialize(url, params = {})
self.url = url
self.params = params
Expand Down Expand Up @@ -60,6 +75,10 @@ def create_or_find_phone_call!(event)

def create_or_find_contact!(platform_account_sid, msisdn)
account = Account.find_by_platform_account_sid(platform_account_sid)
Contact.find_or_create_by!(account: account, msisdn: PhonyRails.normalize_number(msisdn))
Contact.find_or_create_by!(
account: account,
msisdn: PhonyRails.normalize_number(msisdn),
iso_country_code: ACCOUNT_COUNTRY_CODES.fetch(account.id, "KH")
)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class AddIsoCountryCodeToBeneficiaryAddresses < ActiveRecord::Migration[8.0]
def change
change_column_null :beneficiary_addresses, :iso_region_code, false
add_column :beneficiary_addresses, :iso_country_code, :citext, null: false

remove_index :beneficiary_addresses, [ :iso_region_code, :administrative_division_level_2_code, :administrative_division_level_3_code, :administrative_division_level_4_code ]
remove_index :beneficiary_addresses, [ :iso_region_code, :administrative_division_level_2_name, :administrative_division_level_3_name, :administrative_division_level_4_name ]

add_index :beneficiary_addresses, [ :beneficiary_id, :iso_country_code, :iso_region_code, :administrative_division_level_2_code, :administrative_division_level_3_code, :administrative_division_level_4_code ]
add_index :beneficiary_addresses, [ :beneficiary_id, :iso_country_code, :iso_region_code, :administrative_division_level_2_name, :administrative_division_level_3_name, :administrative_division_level_4_name ]
end
end
9 changes: 5 additions & 4 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[8.0].define(version: 2024_12_11_092117) do
ActiveRecord::Schema[8.0].define(version: 2025_01_07_072933) do
# These are extensions that must be enabled in order to support this database
enable_extension "citext"
enable_extension "pg_catalog.plpgsql"
Expand Down Expand Up @@ -80,7 +80,7 @@

create_table "beneficiary_addresses", force: :cascade do |t|
t.bigint "beneficiary_id", null: false
t.citext "iso_region_code"
t.citext "iso_region_code", null: false
t.string "administrative_division_level_2_code"
t.string "administrative_division_level_2_name"
t.string "administrative_division_level_3_code"
Expand All @@ -89,9 +89,10 @@
t.string "administrative_division_level_4_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.citext "iso_country_code", null: false
t.index ["beneficiary_id", "iso_country_code", "iso_region_code", "administrative_division_level_2_code", "administrative_division_level_3_code", "administrative_division_level_4_code"], name: "idx_on_beneficiary_id_iso_country_code_iso_region_c_069288d0e5"
t.index ["beneficiary_id", "iso_country_code", "iso_region_code", "administrative_division_level_2_name", "administrative_division_level_3_name", "administrative_division_level_4_name"], name: "idx_on_beneficiary_id_iso_country_code_iso_region_c_e888f7dc18"
t.index ["beneficiary_id"], name: "index_beneficiary_addresses_on_beneficiary_id"
t.index ["iso_region_code", "administrative_division_level_2_code", "administrative_division_level_3_code", "administrative_division_level_4_code"], name: "idx_on_iso_region_code_administrative_division_leve_a5183cd2b4"
t.index ["iso_region_code", "administrative_division_level_2_name", "administrative_division_level_3_name", "administrative_division_level_4_name"], name: "idx_on_iso_region_code_administrative_division_leve_c76774f7b0"
end

create_table "callout_participations", force: :cascade do |t|
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
module Subdivisions
Province = Struct.new(:code, :iso3166, :name_en, keyword_init: true)

ZAMBIA_PROVINCES = [
Province.new(code: "ZM-02", iso3166: "ZM-02", name_en: "Central"),
Province.new(code: "ZM-08", iso3166: "ZM-08", name_en: "Copperbelt"),
Province.new(code: "ZM-03", iso3166: "ZM-03", name_en: "Eastern"),
Province.new(code: "ZM-04", iso3166: "ZM-04", name_en: "Luapula"),
Province.new(code: "ZM-09", iso3166: "ZM-09", name_en: "Lusaka"),
Province.new(code: "ZM-10", iso3166: "ZM-10", name_en: "Muchinga"),
Province.new(code: "ZM-06", iso3166: "ZM-06", name_en: "North-Western"),
Province.new(code: "ZM-05", iso3166: "ZM-05", name_en: "Northern"),
Province.new(code: "ZM-07", iso3166: "ZM-07", name_en: "Southern"),
Province.new(code: "ZM-01", iso3166: "ZM-01", name_en: "Western")
]
end

ACCOUNT_COUNTRY_CODES = {
2 => "SO",
3 => "KH",
4 => "KH",
7 => "SL",
8 => "TH",
11 => "US",
45 => "MX",
77 => "EG",
110 => "ZM",
143 => "KH",
209 => "LA"
}

cache = {}

namespace :data_migrations do
task migrate_contact_metadata_to_native_fields: :environment do
Account.find_each do |account|
puts "Migrating contacts for account: #{account.id}"

contacts = account.contacts.where(iso_country_code: nil)
contacts.find_each do |contact|
ApplicationRecord.transaction do
contact.update_columns(
iso_country_code: ACCOUNT_COUNTRY_CODES.fetch(account.id),
language_code: contact.metadata["language_code"],
date_of_birth: contact.metadata["date_of_birth"],
status: contact.metadata["deregistered_at"].present? ? :disabled : :active
)

# EWS Cambodia
Array(contact.metadata["commune_ids"]).each do | commune_id |
cache[commune_id] ||= Pumi::Commune.find_by_id(commune_id)
commune = cache[commune_id]
next if commune.blank?

contact.addresses.find_or_create_by!(
iso_country_code: "KH",
iso_region_code: commune.province.iso3166_2,
administrative_division_level_2_code: commune.district_id,
administrative_division_level_2_name: commune.district.name_en,
administrative_division_level_3_code: commune.id,
administrative_division_level_3_name: commune.name_en,
created_at: contact.updated_at,
updated_at: contact.updated_at
)
end

# EWS Laos
Array(contact.metadata["registered_districts"]).each do | district_code |
district = CallFlowLogic::EWSLaosRegistration::DISTRICTS.find { |d| d.code == district_code }
next if district.blank?

contact.addresses.find_or_create_by!(
iso_country_code: "LA",
iso_region_code: district.province.iso3166,
administrative_division_level_2_code: district.code,
administrative_division_level_2_name: district.name_en,
created_at: contact.updated_at,
updated_at: contact.updated_at
)
end

# PIN Zambia
if account.id == 110
province = Subdivisions::ZAMBIA_PROVINCES.find { |d| d.name_en == contact.metadata["province"] }
next if province.blank?

contact.addresses.find_or_create_by!(
iso_country_code: "ZM",
iso_region_code: province.iso3166,
administrative_division_level_2_name: contact.metadata["district"],
administrative_division_level_3_name: contact.metadata["facility"]
)
end
end
end
end
end
end
3 changes: 2 additions & 1 deletion spec/factories.rb
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,9 @@
association :audio_file, factory: :active_storage_attachment, filename: "test.mp3"
end

factory :address, class: "BeneficiaryAddress" do
factory :beneficiary_address do
beneficiary
iso_country_code { "KH" }
iso_region_code { "KH-1" }
end
end
1 change: 1 addition & 0 deletions spec/models/call_flow_logic/ews_laos_registration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ module CallFlowLogic
expect(contact.addresses.last).to have_attributes(
iso_region_code: "LA-CH",
administrative_division_level_2_code: "1604",
administrative_division_level_2_name: "Paksong",
)
assert_play("registration_successful-lao.mp3", response)
end
Expand Down
4 changes: 3 additions & 1 deletion spec/models/call_flow_logic/ews_registration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,9 @@
expect(contact.addresses.last).to have_attributes(
iso_region_code: "KH-1",
administrative_division_level_2_code: "0105",
administrative_division_level_3_code: "010505"
administrative_division_level_2_name: "Ou Chrov",
administrative_division_level_3_code: "010505",
administrative_division_level_3_name: "Samraong"
)
assert_play("registration_successful-krr.wav", response)
end
Expand Down
Loading

0 comments on commit ab53653

Please sign in to comment.