unepwcmc/SAPI

View on GitHub
app/models/trade/shipment.rb

Summary

Maintainability
A
0 mins
Test Coverage
# == Schema Information
#
# Table name: trade_shipments
#
#  id                            :integer          not null, primary key
#  source_id                     :integer
#  unit_id                       :integer
#  purpose_id                    :integer
#  term_id                       :integer          not null
#  quantity                      :decimal(, )      not null
#  appendix                      :string(255)      not null
#  trade_annual_report_upload_id :integer
#  exporter_id                   :integer          not null
#  importer_id                   :integer          not null
#  country_of_origin_id          :integer
#  reported_by_exporter          :boolean          default(TRUE), not null
#  taxon_concept_id              :integer          not null
#  year                          :integer          not null
#  created_at                    :datetime         not null
#  updated_at                    :datetime         not null
#  sandbox_id                    :integer
#  reported_taxon_concept_id     :integer
#  import_permit_number          :text
#  export_permit_number          :text
#  origin_permit_number          :text
#  legacy_shipment_number        :integer
#  import_permits_ids            :string
#  export_permits_ids            :string
#  origin_permits_ids            :string
#  updated_by_id                 :integer
#  created_by_id                 :integer
#

class Trade::Shipment < ApplicationRecord
  include TrackWhoDoesIt
  # Not sure where using this.
  # attr_accessible :annual_report_upload_id, :appendix,
  #   :country_of_origin_id, :origin_permit_id,
  #   :exporter_id, :import_permit_id, :importer_id, :purpose_id,
  #   :quantity, :reporter_type, :reported_by_exporter,
  #   :source_id, :taxon_concept_id, :reported_taxon_concept_id,
  #   :term_id, :unit_id, :year,
  #   :import_permit_number, :export_permit_number, :origin_permit_number,
  #   :ignore_warnings, :created_by_id, :updated_by_id

  attr_accessor :reporter_type, :warnings, :ignore_warnings

  validates :quantity, :presence => true, :numericality => {
    :greater_than_or_equal_to => 0, :message => 'should be a positive number'
  }
  validates :appendix, :presence => true, :inclusion => {
    :in => ['I', 'II', 'III', 'N'], :message => 'should be one of I, II, III, N'
  }
  validates :year, :presence => true, :numericality => {
    :only_integer => true, :greater_than_or_equal_to => 1975, :less_than => 3000,
    :message => 'should be a 4 digit year'
  }
  validates :reporter_type, :presence => true, :inclusion => {
    :in => ['E', 'I'], :message => 'should be one of E, I'
  }
  validates_with Trade::ShipmentSecondaryErrorsValidator

  belongs_to :taxon_concept
  belongs_to :m_taxon_concept, :foreign_key => :taxon_concept_id, optional: true
  belongs_to :reported_taxon_concept, :class_name => 'TaxonConcept', optional: true
  belongs_to :purpose, :class_name => "TradeCode", optional: true
  belongs_to :source, :class_name => "TradeCode", optional: true
  belongs_to :term, :class_name => "TradeCode"
  belongs_to :unit, :class_name => "TradeCode", optional: true
  belongs_to :country_of_origin, :class_name => "GeoEntity", optional: true
  belongs_to :exporter, :class_name => "GeoEntity"
  belongs_to :importer, :class_name => "GeoEntity"

  before_save do
    @old_permits_ids = []
    [
      import_permits_ids_was,
      export_permits_ids_was,
      origin_permits_ids_was
    ].each do |permits_ids|
      @old_permits_ids += permits_ids ? permits_ids.dup : []
    end
    unless reported_taxon_concept_id
      self.reported_taxon_concept_id = taxon_concept_id
    end
  end
  before_destroy do
    @old_permits_ids = permits_ids.dup
  end
  after_commit :async_tasks_after_save, on: [:create, :update]
  after_commit :async_tasks_for_destroy, on: :destroy

  after_validation do
    unless self.errors.empty? && self.ignore_warnings
      # inject warnings here
      warnings.each { |w| self.errors[:warnings] << w }
    end
  end

  def self.reporter_type_to_reported_by_exporter(str)
    if str && str.upcase.strip == 'E'
      true
    elsif str && str.upcase.strip == 'I'
      false
    else
      nil
    end
  end

  def reporter_type
    return nil if reported_by_exporter.nil?
    reported_by_exporter ? 'E' : 'I'
  end

  def reporter_type=(str)
    self.reported_by_exporter = self.class.reporter_type_to_reported_by_exporter(str)
  end

  def import_permit_number=(str)
    set_permit_number('import', str)
  end

  def export_permit_number=(str)
    set_permit_number('export', str)
  end

  def origin_permit_number=(str)
    set_permit_number('origin', str)
  end

  def import_permits_ids
    read_attribute(:import_permits_ids) || []
  end

  def import_permits_ids=(ary)
    write_attribute(:import_permits_ids, "{#{ary && ary.join(',')}}")
  end

  def export_permits_ids
    read_attribute(:export_permits_ids) || []
  end

  def export_permits_ids=(ary)
    write_attribute(:export_permits_ids, "{#{ary && ary.join(',')}}")
  end

  def origin_permits_ids
    read_attribute(:origin_permits_ids) || []
  end

  def origin_permits_ids=(ary)
    write_attribute(:origin_permits_ids, "{#{ary && ary.join(',')}}")
  end

  def permits_ids
    (
      import_permits_ids + export_permits_ids + origin_permits_ids
    ).uniq.compact || []
  end

  private

  # note: this updates the precomputed fields
  # needs to be invoked via custom permit number setters
  # (import_permit_number=, export_permit_number=, origin_permit_number=)
  def set_permit_number(permit_type, str)
    permits = str && str.split(';').compact.map do |number|
      Trade::Permit.find_or_create_by(number: number.strip.upcase)
    end
    # save the concatenated permit numbers in the precomputed field
    write_attribute("#{permit_type}_permit_number", permits && permits.map(&:number).join(';'))
    # save the array of permit ids in the precomputed field
    send("#{permit_type}_permits_ids=", permits && permits.map(&:id))
  end

  def async_tasks_after_save
    DownloadsCacheCleanupWorker.perform_async('shipments')
    disconnected_permits_ids = @old_permits_ids - permits_ids
    PermitCleanupWorker.perform_async(disconnected_permits_ids)
  end

  def async_tasks_for_destroy
    DownloadsCacheCleanupWorker.perform_async('shipments')
    PermitCleanupWorker.perform_async(@old_permits_ids)
  end
end