Created
August 7, 2017 17:50
-
-
Save cored/17093d357a55093353a068c856fd2c66 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# == Schema Information | |
# | |
# Table name: warehouses | |
# | |
# id :integer not null, primary key | |
# name :string(255) | |
# address_id :integer | |
# supplier_id :integer | |
# manages_label_purchases :boolean | |
# scanner_api_token :string | |
# assignment_transit_day_handicap :integer default(0) | |
# assignment_tiebreak_priority :integer default(1) | |
# three_letter_code :string | |
# ups_account_id :string | |
# return_address_id :integer | |
# flexe_api_id :integer | |
# display_name :string default("Casper") | |
# flexe_v3_api_id :integer | |
# group :integer | |
# retired :boolean default(FALSE) | |
# created_at :datetime | |
# updated_at :datetime | |
# | |
class Warehouse < ActiveRecord::Base | |
DBS_WAREHOUSES = ['DB Schenker', 'DB Schenker France'].freeze | |
belongs_to :address | |
belongs_to :return_address, class_name: "Address" | |
has_many :shipments | |
has_many :bulk_shipments | |
has_many :warehouse_product_inventories | |
alias_attribute :product_inventories, :warehouse_product_inventories | |
has_many :warehouse_variation_inventories | |
alias_attribute :variation_inventories, :warehouse_variation_inventories | |
has_many :inventory_movements | |
has_many :shipment_batches | |
has_many :warehouse_carrier_service_options, dependent: :destroy | |
has_many :carrier_service_options, through: :warehouse_carrier_service_options | |
has_many :carriers, -> { distinct }, through: :carrier_service_options | |
has_many :warehouses_slots | |
has_many :courier_slots, through: :warehouses_slots | |
has_many :warehouse_products, dependent: :destroy | |
has_many :products, through: :warehouse_products | |
belongs_to :supplier | |
has_many :inventory_items, as: :location | |
has_many :shipment_batch_creation_options | |
has_many :warehouse_variations | |
has_many :stocked_warehouse_variations, -> { where(stocked_at_location: true) }, class_name: 'WarehouseVariation' | |
has_many :stocked_variations, through: :stocked_warehouse_variations, source: :variation | |
has_many :warehouse_trading_partner_variants | |
has_many :scheduled_shipment_batches, through: :shipment_batch_creation_options | |
has_many :recurring_shipment_batches, through: :shipment_batch_creation_options | |
has_many :cost_centers, dependent: :destroy | |
has_many :carrier_accounts, dependent: :destroy | |
has_many :pickups | |
after_initialize do | |
default_cost_center || | |
cost_centers.new(code: CostCenter::DEFAULT_CODE, products: products) | |
end | |
def default_cost_center | |
cost_centers.detect{|cc| cc.code == CostCenter::DEFAULT_CODE} | |
end | |
# This is kind of a tag, but going to avoid a tag gem until we need | |
# more than one per warehouse. | |
enum group: { | |
flexe_warehouse: 0, | |
} | |
validates_uniqueness_of :name | |
validate :no_unshipped_shipments_at_retired_warehouses | |
validate :no_inventory_at_retired_warehouses | |
accepts_nested_attributes_for :warehouse_products | |
scope :can_auto_assign_shipment, -> (shipment) { | |
sql = <<-SQL | |
WITH set_1 AS ( | |
#{can_auto_assign_based_on_products(shipment).to_sql} | |
), set_2 AS ( | |
#{can_fulfill_requested_variations(shipment).to_sql} | |
) SELECT warehouses.id | |
FROM warehouses | |
INNER JOIN set_1 | |
ON warehouses.id = set_1.id | |
INNER JOIN set_2 | |
ON warehouses.id = set_2.id | |
SQL | |
ids = connection.execute(sql).values.flatten | |
active.where(id: ids) | |
} | |
scope :can_auto_assign_based_on_products, -> (shipment) { | |
merge_scope = WarehouseProduct | |
.where(product: shipment.products) | |
.auto_assign_trading_partner(shipment.trading_partner_identifier) | |
joins(:warehouse_products) | |
.merge(merge_scope) | |
.group("warehouses.id") | |
.having("COUNT(*) = ?", shipment.products.uniq.size) | |
} | |
scope :can_fulfill_requested_variations, -> (shipment) { | |
variations = shipment.shipment_items.map(&:requested_variation).uniq.compact | |
return if variations.empty? | |
joins(:stocked_warehouse_variations).merge(WarehouseVariation.where(variation: variations)) | |
.group("warehouses.id") | |
.having("COUNT(*) = ?", variations.size) | |
} | |
scope :fosdick, -> { where("name ILIKE 'fosdick%'") } | |
scope :editable_by, -> (user) { | |
if user.role == 'supplier' | |
where(supplier: user.supplier) | |
elsif user.role == 'admin' | |
all | |
else | |
none | |
end | |
} | |
scope :active, -> { where(retired: false).order(:name) } | |
scope :retired, -> { where(retired: true).order(:name) } | |
NOT_ASSIGNED_ID = '-1' | |
# Arguments: | |
# either (x) where x is a Shipment | |
# or (shipment: x) where x is a Shipment | |
# or (items: x) where x is an array of hashes in the following format: | |
# [{sku: <string>, count: int}, {sku: <string>, count: int}, ...] | |
def has_inventory_to_ship?(s=nil, shipment: s, items: nil) | |
raise ArgumentError.new("implicit shipment parameter, or named shipment or named items parameter missing") unless shipment || items | |
raise ArgumentError.new("implicit parameter or named shipment parameter should be a Shipment") if shipment && !shipment.is_a?(Shipment) | |
if shipment | |
product_counts = shipment.products.group(:sku).count | |
else | |
product_counts = items.map{|item| [item[:sku], item[:count]] } | |
end | |
product_counts.all? do |product_sku, count| | |
product_inventory(Product.find_by_sku(product_sku)).sellable_count >= count | |
end | |
end | |
def display_warehouse_variations | |
variation_inventories | |
.joins(:variation) | |
.where(variations: { retired: false, sku: stocked_variations.pluck(:sku) }) | |
.includes(:product) | |
.sort_by { |wv| wv.variation.sku } | |
end | |
def create_pickup_for(bulk_shipments) | |
pickups.create(bulk_shipments: bulk_shipments) | |
end | |
def variations_by_trading_partner | |
variation_hash_by_partner = {} | |
TradingPartnerIdentifier.all.each { |tpi| variation_hash_by_partner[tpi] = [] } | |
require 'pry'; binding.pry | |
stocked_variations.not_retired.find_each do |v| | |
v.trading_partner_identifiers.compact.each do |partner| | |
variation_hash_by_partner[partner] << v | |
end | |
end | |
variation_hash_by_partner | |
end | |
def inventory_for_shipment?(shipment) | |
shipment.products.group(:id).count.all? do |id, count| | |
inventory_items | |
.open_to_trading_partner(shipment.trading_partner_identifier) | |
.is_product(id) | |
.not_reserved | |
.count > count | |
end | |
end | |
def product_inventories | |
warehouse_product_inventories.order(:sku) | |
end | |
def product_inventory(product) | |
product_inventories.where(sku: product.sku).first | |
end | |
def variation_inventory(variation) | |
variation_inventories.where(variation: variation).first | |
end | |
def timezone | |
address.timezone | |
end | |
def no_unshipped_shipments_at_retired_warehouses | |
if changes.include?(:retired) && retired && shipments.ready_or_pending.any? | |
errors.add(:retired, "cannot be set to true when unshipped shipments exist at the warehouse") | |
end | |
end | |
def no_inventory_at_retired_warehouses | |
if changes.include?(:retired) && retired && inventory_items.any? | |
errors.add(:retired, "cannot be set to true until inventory is zeroed out") | |
end | |
end | |
def dbs? | |
DBS_WAREHOUSES.include?(name) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment