Untitled
unknown
ruby
10 months ago
39 kB
10
Indexable
require_relative '../../../app/LA/entities/aggregator_value_vo' require_relative '../../lib/outbound_request_type_utility' require_relative '../factories/external_client_factory' class TransferListWsnLocationAggregation < TransferListWidLocationAggregation TRANSACTION_NAMESPACE_LIST = [StorageNamespaceEnum::SHIP_GROUPS, StorageNamespaceEnum::RESERVATIONS, StorageNamespaceEnum::INVENTORY_ITEMS] RESERVE_RESOURCE_LOCK_TTL = 300 RESERVE_RESOURCE_LOCK_WAIT_TIME = 1000 RESERVE_RESOURCE_LOCK_RETRY_COUNT = 3 RESERVE_RESHUFFLE_LIMIT = 500 INVENTORY_ITEM = "InventoryItem" def initialize(warehouse_id) @warehouse_id = warehouse_id end # request1 = {"wsn_to_pick" => 'wsn_entered', "partial_pick" => true, # 'source_loaction_id' => 'source_location'} def resolve_unpicked_items(pickable_items, transfer_list, picked_inventories = [], flow = nil) transfer_list_items = [] pickable_items = pickable_items.is_a?(Array) ? pickable_items : pickable_items.nil? ? [] : [pickable_items] tote_label_id_map = get_tote_label_id_map(pickable_items) movement_request_vo = movement_request_service.get_vos_by_ids([transfer_list.movement_request_id]).first outbound_request_type = (WorkFlowEntityType::OUTBOUND_REQUEST == movement_request_vo.group_type) transfer_list_items << pickable_items.collect do |pickable_item| list_items = [] wsn = pickable_item[:wsn_to_pick] if wsn wh_serial_number = wsn_service.validate_and_fetch_wsn(wsn) begin inventory_item = InventoryModuleDataService. get_inventory_item_by_wh_serial_number_id_and_quantity!(wh_serial_number.id, 1) rescue ActiveRecord::RecordNotFound => e inventory_item = nil end list_items << if inventory_item.present? validate_scanned_wsn_warehouse(inventory_item, transfer_list, wsn) validate_duplicate_wsn(inventory_item, transfer_list, wsn) item = transfer_list_service. get_transfer_list_item_by_transfer_list_id_and_inventory_item_id(transfer_list.id, inventory_item.id) picked_inventories << item[:inventory_item_id] if item.present? item.present? ? item : validate_picked_item_and_swap(pickable_item, transfer_list, wsn, inventory_item, outbound_request_type, picked_inventories, flow) else # change incoming payload swap_wsns(wsn, pickable_item[:source_loaction_id], transfer_list, picked_inventories, flow) end else wid = pickable_item[:wid] product_detail_vo = get_product_details_by_wid(wid) product_detail_id = product_detail_vo[0][:id] imei_array = pickable_item[:imei] quantity = pickable_item[:quantity].to_i tote = pickable_item[:tote] shelf = pickable_item[:source_loaction_id] logger.debug("Processing WID: #{wid},Product Detail ID: #{product_detail_id} , Quantity: #{quantity},TOTE: #{tote}, Shelf : #{shelf} IMEI_Array, :#{imei_array}") wsn_vos = [] if imei_array.present? imei_array.each do |imei| next if imei.nil? wsn_vo = wh_serial_number_data_service.get_wsn_vos_by_attribute_name_and_attribute_values_and_product(WhSerialNumberAttributeNameEnum::SERIAL_NUMBER, imei, product_detail_id) unless wsn_vo.empty? wsn_vos += wsn_vo end end end missing_quantity = quantity - wsn_vos.size new_wsns = [] if missing_quantity > 0 # Creating missing WSNs in a single API call idempotence_key = "#{product_detail_id}_#{tote}_#{shelf}_#{transfer_list.id}_#{missing_quantity}" payload = { product_detail_id: product_detail_id, idempotence_key: idempotence_key, quantity: missing_quantity } begin new_wsn_vos = b2b_warehouse_client.create_wsn_v1(payload) if new_wsn_vos.is_a?(Array) && new_wsn_vos.any? new_wsns = new_wsn_vos.map { |vo| vo['display_id'] } else logger.error("Unexpected wsn_vo response structure or empty response: #{new_wsn_vos.inspect}") raise "WSN creation failed due to invalid response structure" end rescue StandardError => e logger.error("Failed to create WSN VOs for payload: #{payload}. Error: #{e.message}") raise "WSN creation failed : #{e.message}" end end all_wsns = (wsn_vos.map { |vo| vo.display_id } + new_wsns).take(quantity) all_wsns.each_with_index do |wsn, i| wh_serial_number = wsn_service.validate_and_fetch_wsn(wsn) begin inventory_item = InventoryModuleDataService. get_inventory_item_by_wh_serial_number_id_and_quantity!(wh_serial_number.id, 1) rescue ActiveRecord::RecordNotFound => e inventory_item = nil end list_items << if inventory_item.present? validate_scanned_wsn_warehouse(inventory_item, transfer_list, wsn) validate_duplicate_wsn(inventory_item, transfer_list, wsn) item = transfer_list_service. get_transfer_list_item_by_transfer_list_id_and_inventory_item_id(transfer_list.id, inventory_item.id) picked_inventories << item[:inventory_item_id] if item.present? item.present? ? item : validate_picked_item_and_swap(pickable_item, transfer_list, wsn, inventory_item, outbound_request_type, picked_inventories, flow) else # change incoming payload swap_wsns(wsn, pickable_item[:source_loaction_id], transfer_list, picked_inventories, flow) end end end list_items.flatten! if pickable_item[:imei].present? list_items.each_with_index do |item_taken, i| item_taken[:imei] = i < pickable_item[:imei].length ? pickable_item[:imei][i] : nil end end list_items.each do |item| item[:tote_id] = tote_label_id_map[pickable_item[:tote]] unless pickable_item[:tote].nil? end list_items end transfer_list_items.flatten end # request1 = {"wsn_to_put" => 'wsn_entered', "partial_pick" => true, # 'destination_location_id' => 'destination_location'} def resolve_putable_items(putable_items, transfer_list, puted_inventories=[]) transfer_list_items = [] putable_items = putable_items.is_a?(Array) ? putable_items : putable_items.nil? ? [] : [putable_items] tote_label_id_map = get_tote_label_id_map(putable_items) transfer_list_items << putable_items.collect do |putable_item| list_items = [] wsn = putable_item[:wsn_to_put] tote_label = putable_item[:tote] unless tote_label_id_map.nil? wh_serial_number = wsn_service.validate_and_fetch_wsn(wsn) inventory_item = InventoryModuleDataService. get_inventory_item_by_warehouse_id_and_wh_serial_number_id(transfer_list.warehouse_id, wh_serial_number.id) raise SupplyChainError.new(:message => "Inventory item with wsn: #{wsn} is not found") if inventory_item.blank? item = transfer_list_service.get_transfer_list_item_by_transfer_list_id_and_inventory_item_id(transfer_list.id, inventory_item.id) raise SupplyChainError.new(:message => "Wsn #{wsn} does not belong to this TL") if item.blank? if (!tote_label.nil? && item[:tote_id] != tote_label_id_map[tote_label]) raise SupplyChainError.new(:message => "Wsn #{wsn} does not belong to tote #{tote_label}") end item[:destination_location_id] = get_and_validate_destination_location(putable_item[:destination_location_id], transfer_list.destination_area, @warehouse_id).id list_items << item puted_inventories << item[:inventory_item_id] list_items.flatten end transfer_list_items.flatten end # return inventory item ids corresponding to wsn def validate_and_resolve_inventory_item_to_pack(transfer_list, input, input_type) wsns = input.collect { |items| items[input_type] }.flatten wsn_id_map = Hash[wsns.map { |wsn| [wsn_service.get_wsn_vo_by_display_id(wsn).id, wsn] }] inventory_item_id_maps = Hash[wsn_id_map.keys.map { |wh_serial_number_id| [inventory_service.get_vo_by_wsn_id(wh_serial_number_id).id, wh_serial_number_id] }] inventory_items_in_tl = transfer_list_service.get_inventory_items_by_transfer_list_id(transfer_list.id).collect { |item| item[:inventory_item_id] } inventory_items_not_in_tl = inventory_item_id_maps.keys - inventory_items_in_tl if inventory_items_not_in_tl.present? wsns_not_in_tl = inventory_items_not_in_tl.collect do |inventory_item_id| wsn_id_map[inventory_item_id_maps[inventory_item_id]] end raise WsnNotPartOfPicklistError.new(wsns_not_in_tl) end movement_request = movement_request_service.get_vos_by_ids([transfer_list.movement_request_id]).first outbound_request_items_for_tl = outbound_request_service.get_item_vos_by_outbound_request_id_inventory_item_ids(movement_request.group_id, inventory_items_in_tl).select { |item| item.status == OutboundRequestItemStatusEnum::IN_CONSIGNMENT } inventory_item_ids = outbound_request_items_for_tl.collect(&:inventory_item_id) unpacked_inventory_item_ids = inventory_item_ids - inventory_item_id_maps.keys [inventory_item_id_maps.keys, unpacked_inventory_item_ids] end def item_aggregator_fields ['aggregator_value_id', 'status', 'source_location_id', 'destination_location_id', 'tote_id'] end def putable_items_aggregator_fields ['tote_id', 'aggregator_value_id', 'status'] end def is_serialized false end def is_inv_swap_enabled_for_flow(outbound_request_type) outbound_request_type = OutboundRequestTypeUtility.get_outbound_request_type(outbound_request_type) config_hash = WarehouseService.settings.inventory_swapping_allowed_flows if config_hash['ALL'].present? && (config_hash['ALL'].include?('ALL') || config_hash['ALL'].include?(outbound_request_type)) true else config_hash[@warehouse_id].present? && (config_hash[@warehouse_id].include?('ALL') || config_hash[@warehouse_id].include?(outbound_request_type)) end end def is_inv_swap_enabled_for_area(source_area) storage_areas = WarehouseService.settings.inventory_swapping_restricted_areas return storage_areas.none?{ |area| area == source_area } end private def get_ready_to_pick_and_relabel_needed_inv_items(transfer_list_id) ready_to_pick_tl_items = transfer_list_service.get_inventory_item_id_and_transfer_list_item_by_transfer_list_id_and_item_status( transfer_list_id, TransferListStatusEnum::READY_TO_PICK) raise TransferListItemNotFoundError.new('No pickable items in this TL') if ready_to_pick_tl_items.empty? inventory_service .get_relabelling_required_map_for_inventory_item_ids(ready_to_pick_tl_items.collect{ |tli| tli[:inventory_item_id] }) .select{ |_k, v| v }.keys end def swap_inventories(wsn, storage_location, transfer_list, picked_inventories, picked_inv_item_vo, flow = nil) # method to swap inventories for a outbound request wid = wsn_service.get_wid_for_wsn(wsn) is_relabeled = false # get reserved inventory reserved_inv_item_vo, transfer_list_items_map = if storage_location.present? begin get_inventory_item_vo_using_aggregator(wsn, storage_location.first, transfer_list, wid, picked_inventories, is_relabeled) rescue TransferListItemNotFoundError seller_wid = wid_seller_mapping_data_service.get_fki_to_seller_wids_hash([wid])[wid] raise TransferListItemNotFoundError.new("WSN : #{wsn} , Storage_location: #{storage_location} not available to pick") if seller_wid.nil? is_relabeled = true get_inventory_item_vo_using_aggregator(wsn, storage_location.first, transfer_list, seller_wid, picked_inventories, is_relabeled) end else get_inventory_item_vo(wsn, transfer_list, wid, picked_inventories) end fetch_and_swap_inventories(transfer_list, picked_inv_item_vo, reserved_inv_item_vo, transfer_list_items_map, flow) [transfer_list_items_map] end def fetch_and_swap_inventories(transfer_list, picked_inv_item_vo, reserved_inv_item_vo, transfer_list_items_map, flow = nil) # method to fetch and swap inventory items logger.info("Starting inventory swap - inventory id #{reserved_inv_item_vo.id} with #{picked_inv_item_vo.id}") ResourceLock.hold!(ResourceLockNamespaceEnum::RESHUFFLE_RESOURCE_LOCK_NAME, {:warehouse_id => @warehouse_id}, nil, RESERVE_RESOURCE_LOCK_TTL, RESERVE_RESOURCE_LOCK_WAIT_TIME, RESERVE_RESOURCE_LOCK_RETRY_COUNT) do shard_manager.using_transaction(TRANSACTION_NAMESPACE_LIST) do shard_manager.using_shard_for_warehouse_id(@warehouse_id) do # picked and reserved inventory are in different storage location if reserved_inv_item_vo.storage_location_id != picked_inv_item_vo.storage_location_id update_aggregator_value(picked_inv_item_vo, reserved_inv_item_vo, transfer_list) end if picked_inv_item_vo.atp == 1 swap_if_inventory_is_promisable(picked_inv_item_vo, reserved_inv_item_vo, flow) else swap_if_inventory_is_not_promisable(picked_inv_item_vo, reserved_inv_item_vo) end # update in_transit info for inventory items inventory_service.update_in_transit(reserved_inv_item_vo.id, 0, flow) inventory_service.update_in_transit(picked_inv_item_vo.id, 1, flow) # update inventory in return object transfer_list_items_map[:inventory_item_id] = picked_inv_item_vo.id end end end logger.info("Completed inventory swap - inventory id #{reserved_inv_item_vo.id} with #{picked_inv_item_vo.id}") transfer_list_items_map end def swap_if_inventory_is_promisable(picked_inv_item_vo, reserved_inv_item_vo, flow = nil) # swapping inventory if picked inventory atp = 1 # update atp for inventory item inventory_service.change_atp(picked_inv_item_vo.id, -1, flow) inventory_service.change_atp(reserved_inv_item_vo.id, 1, flow) # update outbound request item, movement request item and transfer list item for reserved inventory update_inventory_in_reservations(picked_inv_item_vo, reserved_inv_item_vo) end def swap_if_inventory_is_not_promisable(picked_inv_item_vo, reserved_inv_item_vo) # get outbound request item for picked inventory picked_inv_outbound_request_item_vo = outbound_request_service.get_by_inventory_item_id(picked_inv_item_vo.id). find { |item| ![OutboundRequestItemStatusEnum::CANCELLED, OutboundRequestItemStatusEnum::COMPLETED, OutboundRequestItemStatusEnum::LOST].include? item.status} if picked_inv_outbound_request_item_vo.present? # update outbound request item for picked inventory update_inventory_in_outbound_request_item(picked_inv_outbound_request_item_vo, reserved_inv_item_vo) # update movement request / task for picked inventory update_picked_inventory_reservation(picked_inv_item_vo, reserved_inv_item_vo, picked_inv_outbound_request_item_vo.outbound_request_id) else # get transfer request item for picked inventory picked_inv_transfer_request_item_vo = transfer_request_service.get_item_vo_by_inventory_item_id(picked_inv_item_vo.id). find { |item| ![TransferRequestItemStatusEnum::CANCELLED, TransferRequestItemStatusEnum::COMPLETED, TransferRequestItemStatusEnum::LOST].include? item.status} if picked_inv_transfer_request_item_vo.present? # update transfer request item for picked inventory update_inventory_in_transfer_request_item(picked_inv_transfer_request_item_vo, reserved_inv_item_vo) # update movement request / task for picked inventory update_picked_inventory_reservation(picked_inv_item_vo, reserved_inv_item_vo, picked_inv_transfer_request_item_vo.transfer_request_id) else raise InvalidInputError.new("Picked inventory #{picked_inv_item_vo.id} is reserved for flow other than Outbound/Transfer") end end # update outbound and movement request item for reserved inventory update_inventory_in_reservations(picked_inv_item_vo, reserved_inv_item_vo) end def update_inventory_in_reservations(picked_inv_item_vo, reserved_inv_item_vo) # method to update picked inv in outbound request, movement request and transfer list tables reserved_inv_outbound_request_item_vo = outbound_request_service.get_by_inventory_item_id(reserved_inv_item_vo.id). find { |item| ![OutboundRequestItemStatusEnum::CANCELLED, OutboundRequestItemStatusEnum::COMPLETED, OutboundRequestItemStatusEnum::LOST].include? item.status} reserved_inv_movement_request_item_vo = movement_request_service.get_movement_request_item_vos_by_inventory_item_ids([reserved_inv_item_vo.id]). find { |item| ![MovementRequestItemStatusEnum::CANCELLED, MovementRequestItemStatusEnum::COMPLETED, MovementRequestItemStatusEnum::LOST].include? item.status} reserved_inv_transfer_list_item_vo = transfer_list_service.get_transfer_list_items_by_movement_request_item_ids([reserved_inv_movement_request_item_vo.id]).first update_inventory_in_outbound_request_item(reserved_inv_outbound_request_item_vo, picked_inv_item_vo) update_inventory_in_movement_request_item(reserved_inv_movement_request_item_vo, picked_inv_item_vo) update_details_in_transfer_list_item(reserved_inv_transfer_list_item_vo, picked_inv_item_vo) end def update_aggregator_value(picked_inv_item_vo, reserved_inv_item_vo, transfer_list) # update aggregator_value in transfer list reserved_inv_transfer_list_item_hash = transfer_list_service.get_transfer_list_item_by_transfer_list_id_and_inventory_item_id(transfer_list.id, reserved_inv_item_vo.id) aggregator_value_hash = add_new_aggregator_value(transfer_list.id, picked_inv_item_vo.wid, picked_inv_item_vo.storage_location_id) update_hash = {:aggregator_value_id => aggregator_value_hash[:id]} transfer_list_service.update_transfer_list_item(reserved_inv_transfer_list_item_hash[:id], update_hash) end def add_new_aggregator_value(transfer_list_id, wid, storage_location_id) # add new aggregator_value for picked inventory storage_location_vo = storage_location_service.get_vos_by_ids([storage_location_id]).first value = "#{storage_location_vo.label}|#{wid}" insert_hash = { :transfer_list_id => transfer_list_id, :value => value } aggregator_value_dao.bulk_insert([insert_hash]) aggregator_value_dao.get_record_by_transfer_list_id_and_value(transfer_list_id, value) end def update_picked_inventory_reservation(picked_inv_item_vo, reserved_inv_item_vo, reservation_id) # method to update movement request item / task for picked inventory item # get movement request item for picked inv picked_inv_movement_request_item_vo = movement_request_service.get_movement_request_item_vos_by_inventory_item_ids([picked_inv_item_vo.id]). find { |item| ![MovementRequestItemStatusEnum::CANCELLED, MovementRequestItemStatusEnum::COMPLETED, MovementRequestItemStatusEnum::LOST].include? item.status} if picked_inv_movement_request_item_vo.present? # update movement request item for reserved inv update_inventory_in_movement_request_item(picked_inv_movement_request_item_vo, reserved_inv_item_vo) begin # check if transfer list present for picked inventory. (If not present do nothing) picked_inv_transfer_list_item_vo = transfer_list_service.get_transfer_list_items_by_movement_request_item_ids([picked_inv_movement_request_item_vo.id]).first if picked_inv_transfer_list_item_vo.present? update_details_in_transfer_list_item(picked_inv_transfer_list_item_vo, reserved_inv_item_vo) end rescue nil end else # get task item for picked inventory picked_inv_task_item_vo = TaskModuleDataService::Task.where(:group_id => reservation_id, :work_item_id => picked_inv_item_vo.id, :work_item_type => INVENTORY_ITEM) if picked_inv_task_item_vo.present? # update task item for picked inventory update_inventory_in_tasks(picked_inv_task_item_vo, reserved_inv_item_vo) end end end def update_inventory_in_outbound_request_item(outbound_request_item_vo, inventory_item_vo) # update inventory in outbound request item update_item_hash = {:inventory_item_id => inventory_item_vo.id, :source_storage_location_id => inventory_item_vo.storage_location_id} outbound_request_service.update_outbound_request_item(outbound_request_item_vo.id, update_item_hash) end def update_inventory_in_transfer_request_item(transfer_request_item_vo, inventory_item_vo) # update inventory in transfer request item update_item_hash = {:inventory_item_id => inventory_item_vo.id, :from_storage_location_id => inventory_item_vo.storage_location_id} transfer_request_service.update_items_by_ids(transfer_request_item_vo.id, update_item_hash) end def update_inventory_in_movement_request_item(movement_request_item_vo, inventory_item_vo) # update inventory in movement request item update_item_hash = {:inventory_item_id => inventory_item_vo.id, :source_storage_location_id => inventory_item_vo.storage_location_id} movement_request_service.update_items_by_ids(movement_request_item_vo.id, update_item_hash) end def update_details_in_transfer_list_item(transfer_list_item_vo, inventory_item_vo) # update inventory in transfer list item update_item_hash = {:source_location_id => inventory_item_vo.storage_location_id} transfer_list_service.update_transfer_list_item(transfer_list_item_vo.id, update_item_hash) end def update_inventory_in_tasks(tasks_vos, inventory_item_vo) # update inventory in tasks update_item_hash = {:work_item_id => inventory_item_vo.id} for tasks_vo in tasks_vos TaskModuleDataService::Task.where(:id => tasks_vo.id).first.update_attributes!(update_item_hash) transfer_task_data_vo = TaskModuleDataService::TransferTaskData.where(:task_id => tasks_vo.id).first if transfer_task_data_vo.present? if transfer_task_data_vo.source_location_id.present? update_hash = {:source_location_id => inventory_item_vo.storage_location_id} TaskModuleDataService::TransferTaskData.where(:id => transfer_task_data_vo.id).first.update_attributes!(update_hash) end end end end def swap_wsns(wsn, storage_location, transfer_list, picked_inventories, flow = nil) wid = wsn_service.get_wid_for_wsn(wsn) is_relabeled = false begin relabelling_inventory_item_ids = get_ready_to_pick_and_relabel_needed_inv_items(transfer_list.id) relabelling_inventory_item_vos = relabelling_inventory_item_ids.empty? ? [] : inventory_service.get_vos_by_ids(relabelling_inventory_item_ids) fki_to_alpha_seller_map = inventory_service.get_fki_to_alpha_wid_map(relabelling_inventory_item_vos.collect(&:wid).uniq) rescue Warehouse::RecordNotFoundError => e fki_to_alpha_seller_map = {} end inventory_item_vo, transfer_list_items_map = if storage_location.present? begin get_inventory_item_vo_using_aggregator(wsn, storage_location.first, transfer_list, wid, picked_inventories, is_relabeled) rescue TransferListItemNotFoundError #seller_wid = wid_seller_mapping_data_service.get_fki_to_seller_wids_hash([wid])[wid] seller_wid = fki_to_alpha_seller_map[wid] raise TransferListItemNotFoundError.new("WSN : #{wsn} , Storage_location: #{storage_location} not available to pick") if seller_wid.nil? is_relabeled = true get_inventory_item_vo_using_aggregator(wsn, storage_location.first, transfer_list, seller_wid, picked_inventories, is_relabeled) end else get_inventory_item_vo(wsn, transfer_list, wid, picked_inventories) end UtilityFactory.inventory_utility.fetch_and_swap_wsn(inventory_item_vo, wsn, is_relabeled, flow) [transfer_list_items_map] end def get_inventory_item_vo_using_aggregator(wsn, storage_location, transfer_list, wid, picked_inventories, expected_relabel_status = false) aggregation_value = storage_location + '|' + wid begin aggregator_value_vo = transfer_list_service.get_aggregator_value_vo_by_transfer_list_id_and_value( transfer_list.id, aggregation_value) rescue Warehouse::RecordNotFoundError => e raise TransferListItemNotFoundError.new("WSN : #{wsn} , Storage_location: #{storage_location} not available to pick") end transfer_list_items_maps = transfer_list_service. get_inventory_item_id_and_transfer_list_item_by_transfer_list_id_and_item_status_and_aggregator_value_id(transfer_list.id, TransferListItemStatusEnum::READY_TO_PICK, aggregator_value_vo.id) relabel_status_map = inventory_service.get_relabelling_required_map_for_inventory_item_ids( transfer_list_items_maps.collect{ |map| map[:inventory_item_id] }) transfer_list_items_map = transfer_list_items_maps.detect do |map| (picked_inventories.exclude? map[:inventory_item_id]) && (relabel_status_map[map[:inventory_item_id]] == expected_relabel_status) end if transfer_list_items_map.present? picked_inventories << transfer_list_items_map[:inventory_item_id] else raise TransferListItemNotFoundError.new("WSN : #{wsn} , Storage_location: #{storage_location} not available to pick") end raise TransferListItemNotFoundError.new("WSN : #{wsn} , Storage_location: #{storage_location} not available to pick") unless transfer_list_items_map.present? [inventory_service.get_vos_by_ids([transfer_list_items_map[:inventory_item_id]]).first, transfer_list_items_map] end def get_inventory_item_vo(wsn, transfer_list, wid, picked_inventories) transfer_list_items_map_list = transfer_list_service.get_inventory_item_id_and_transfer_list_item_by_transfer_list_id_and_item_status( transfer_list.id, TransferListItemStatusEnum::READY_TO_PICK) inventory_item_vo = if transfer_list_items_map_list.present? inventory_item_vos = inventory_service.get_vos_by_ids(transfer_list_items_map_list.collect { |item| item[:inventory_item_id] }) inventory_item_vos.detect { |item_vo| (item_vo.wid == wid && (picked_inventories.exclude? item_vo.id))} else nil end if inventory_item_vo.present? picked_inventories << inventory_item_vo.id else raise TransferListItemNotFoundError.new("WSN : #{wsn} not available to pick") end [inventory_item_vo, transfer_list_items_map_list.detect{ |map| map[:inventory_item_id] == inventory_item_vo.id }] end def is_inventory_reserved_or_in_transit_out_of_current_TL(inventory_item, current_transfer_list) is_inv_locked_outside_of_TL = ((inventory_item.atp == 1 && inventory_item.in_transit == false) ? false : true) if is_inv_locked_outside_of_TL inventory_TL = transfer_list_service.get_trasfer_list_for_inventory_item(inventory_item) is_inv_locked_outside_of_TL = false if inventory_TL.present? && inventory_TL.id == current_transfer_list.id end return is_inv_locked_outside_of_TL end def validate_wsn_reserved(inventory_item, wsn, transfer_list, outbound_request_type = true) unless inventory_item.area == transfer_list.source_area raise WarehouseService::InvalidInputError.new("WSN:#{wsn} is in location #{inventory_item.area}, cannot pick from location #{transfer_list.source_area}") end return true if inventory_item.atp == 1 && inventory_item.in_transit == false if inventory_item.in_transit == true and !allow_in_transit_swapping(inventory_item, wsn, transfer_list, outbound_request_type) raise WarehouseService::InvalidInputError.new("WSN:#{wsn} is already reserved") end outbound_request_items = outbound_request_service.get_item_vos_by_inventory_item_id(inventory_item.id) if outbound_request_type outbound_request = movement_request_service.get_outbound_request_for_movement_request_id(transfer_list.movement_request_id) if outbound_request_items.present? outbound_request_items.each do |item| next if item.outbound_request_id == outbound_request.id outbound_request_item_reserved_against_wsn_flow?(item, wsn) end end else outbound_request_items.each{|item| outbound_request_item_reserved_against_wsn_flow?(item, wsn)} WsnService.validate_picked_item_against_blocking_entities(inventory_item) end end def allow_in_transit_swapping(inventory_item, wsn, transfer_list, outbound_request_type) # method to check if in_transit swapping of inventory is allowed if outbound_request_type outbound_request_vo = movement_request_service .get_outbound_request_for_movement_request_id(transfer_list.movement_request_id) # validate warehouse, flow and area unless is_in_transit_swap_enabled_for_flow(outbound_request_vo.outbound_request_type) and \ is_in_transit_swap_enabled_for_area(transfer_list.source_area) return false end # check if scanned inventory in same location as reserved inventory in TL begin storage_location_vo = storage_location_service.get_vos_by_ids([inventory_item.storage_location_id]).first aggregator_value = "#{storage_location_vo.label}|#{inventory_item.wid}" aggregator_value_vo = transfer_list_service .get_aggregator_value_vo_by_transfer_list_id_and_value(transfer_list.id, aggregator_value) rescue Warehouse::RecordNotFoundError raise WarehouseService::InvalidInputError .new("Scanned WSN:#{wsn} is in different location than TL - #{transfer_list.display_id}") end # check if TL item in ready to pick state for scanned wid begin transfer_list_items_vos = transfer_list_service .get_transfer_list_items_by_transfer_list_id_and_gregator_value_id_and_status( transfer_list.id, aggregator_value_vo.id, TransferListStatusEnum::READY_TO_PICK) unless transfer_list_items_vos.present? return false end rescue Warehouse::RecordNotFoundError raise WarehouseService::InvalidInputError .new("WID:#{inventory_item.wid} in location #{storage_location_vo.label} already picked for TL - #{transfer_list.display_id}") end # check if scanned inventory not yet picked movement_request_item_vo = movement_request_service .get_movement_request_item_vos_by_inventory_item_ids(inventory_item.id) .map{ |item| item if [MovementRequestItemStatusEnum::CREATED, MovementRequestItemStatusEnum::PROCESSING].include? item.status} .compact.first unless movement_request_item_vo.present? return false end transfer_list_item_vo = transfer_list_service .get_transfer_list_items_by_movement_request_item_ids(movement_request_item_vo.id).first allowed_transfer_list_item_status = [TransferListItemStatusEnum::CREATED, TransferListItemStatusEnum::READY_TO_PICK, TransferListItemStatusEnum::CANCELLED] unless allowed_transfer_list_item_status.include? transfer_list_item_vo.status return false end log.info("In transit swapping of WSN - #{wsn} and Inventory - #{inventory_item.id} and TL - #{transfer_list.display_id}") return true end return false end def is_in_transit_swap_enabled_for_flow(outbound_request_type) config_hash = WarehouseService.settings.in_transit_inventory_swap_allowed_flows config_hash[outbound_request_type].present? && (config_hash[outbound_request_type].include?('ALL') || config_hash[outbound_request_type].include?(@warehouse_id)) end def is_in_transit_swap_enabled_for_area(source_area) storage_areas = WarehouseService.settings.in_transit_inventory_swap_allowed_areas storage_areas.include? source_area end def get_fki_to_seller_wids_hash(fki_wids) # catching exception here to keep the usage cleaner begin wid_seller_mapping_data_service.get_fki_to_seller_wids_hash(fki_wids) rescue Warehouse::RecordNotFoundError nil end end def outbound_request_item_reserved_against_wsn_flow?(item, wsn) if (([OutboundRequestStatusEnum::CANCELLED, OutboundRequestStatusEnum::COMPLETED].exclude? item.status) && picked_item_reserved_against_wsn_flow?(item.outbound_request_id)) raise WarehouseService::InvalidInputError.new("WSN:#{wsn} is already reserved for outbound request #{item.outbound_request_id}") end end def picked_item_reserved_against_wsn_flow?(outbound_request_id) outbound_request = outbound_request_service.get_vos_by_ids([outbound_request_id]).first OutboundRequestEnums.get_serialized_pick_flows.include?(outbound_request.outbound_request_type.to_s) end def validate_duplicate_wsn(inventory_item, transfer_list, wsn) transfer_list_items = transfer_list_service.find_transfer_list_items_by_inventory_item_id(inventory_item.id) transfer_list_items.each do |transfer_list_item| if transfer_list_item.status == TransferListItemStatusEnum::PICKED transfer_list_for_item = transfer_list_item.transfer_list_id == transfer_list.id ? transfer_list : transfer_list_service.get_vo_by_id(transfer_list_item.transfer_list_id) raise WarehouseService::InvalidInputError.new("WSN:#{wsn} is already picked for TL#{transfer_list_item.transfer_list_id}") if transfer_list.movement_request_id == transfer_list_for_item.movement_request_id end end end def validate_scanned_wsn_warehouse(inventory_item, transfer_list, wsn) unless inventory_item.warehouse_id == transfer_list.warehouse_id raise InvalidInputError.new("WSN #{wsn} belongs to warehouse #{inventory_item.warehouse_id}") end end def validate_picked_item_and_swap(pickable_item, transfer_list, wsn, inventory_item, outbound_request_type, picked_inventories, flow = nil) if WarehouseService.settings.kalash_warehouses.include?(@warehouse_id) block_swap_for_kalash = is_inventory_reserved_or_in_transit_out_of_current_TL(inventory_item, transfer_list) err_msg = "Cannot pick #{wsn} for TL id #{transfer_list.id}. Choose a different WSN to pick. Scanned wsn has zero atp or it is in-transit for another process." if block_swap_for_kalash raise WarehouseService::InvalidInputError.new(err_msg) if err_msg.present? end validate_wsn_reserved(inventory_item, wsn, transfer_list, outbound_request_type) WsnService.validate_picked_item_not_reserved_against_wsn_flow(inventory_item) if outbound_request_type outbound_request_vo = movement_request_service.get_outbound_request_for_movement_request_id(transfer_list.movement_request_id) if is_inv_swap_enabled_for_flow(outbound_request_vo.outbound_request_type) && is_inv_swap_enabled_for_area(transfer_list.source_area) swap_inventories(wsn, pickable_item[:source_loaction_id], transfer_list, picked_inventories, inventory_item, flow) else swap_wsns(wsn, pickable_item[:source_loaction_id], transfer_list, picked_inventories, flow) end else swap_wsns(wsn, pickable_item[:source_loaction_id], transfer_list, picked_inventories, flow) end end def get_product_details_by_wid(wid) product_details_dao.get_by_wid(wid) end def wsn_service BusinessServiceFactory.get_wsn_service end def storage_zone_service BusinessServiceFactory.storage_location_service(@warehouse_id) end def transfer_list_service BusinessServiceFactory.get_transfer_list_service(@warehouse_id) end def inventory_service BusinessServiceFactory.inventory_service(@warehouse_id) end def outbound_request_service BusinessServiceFactory.get_outbound_request_service(@warehouse_id) end def movement_request_service BusinessServiceFactory.get_movement_request_service(@warehouse_id) end def wid_seller_mapping_data_service DataServiceFactory.get_wid_seller_mapping_data_service end def relabel_status_service BusinessServiceFactory.get_inventory_relabel_status_service(@warehouse_id) end def shard_manager ShardManager.new end def transfer_request_service BusinessServiceFactory.get_transfer_request_service(@warehouse_id) end def storage_location_service BusinessServiceFactory.storage_location_service(@warehouse_id) end def product_details_dao DAOFactory.get_dao(StorageNamespaceEnum::PRODUCT_DETAIL, [@warehouse_id])[@warehouse_id] end def b2b_warehouse_client ExternalClientFactory.get_b2b_warehouse_client end def wh_serial_number_data_service BusinessServiceFactory.get_wh_serial_number_data_service end def aggregator_value_dao DAOFactory.get_dao("aggregator_values", [@warehouse_id])[@warehouse_id] end end
Editor is loading...
Leave a Comment