scope weapon sync by element and proficiency
- accept filter param in preview_sync and import - element checks collection_weapon first, falls back to weapon - proficiency joins through weapon table
This commit is contained in:
parent
1ba23d84f8
commit
7b5b564edf
2 changed files with 52 additions and 11 deletions
|
|
@ -133,7 +133,8 @@ module Api
|
|||
game_data,
|
||||
update_existing: import_params[:update_existing] == true,
|
||||
is_full_inventory: import_params[:is_full_inventory] == true,
|
||||
reconcile_deletions: import_params[:reconcile_deletions] == true
|
||||
reconcile_deletions: import_params[:reconcile_deletions] == true,
|
||||
filter: import_params[:filter]
|
||||
)
|
||||
|
||||
result = service.import
|
||||
|
|
@ -157,12 +158,13 @@ module Api
|
|||
# @return [JSON] List of items that would be deleted
|
||||
def preview_sync
|
||||
game_data = import_params[:data]
|
||||
filter = import_params[:filter]
|
||||
|
||||
unless game_data.present?
|
||||
return render json: { error: 'No data provided' }, status: :bad_request
|
||||
end
|
||||
|
||||
service = WeaponImportService.new(current_user, game_data)
|
||||
service = WeaponImportService.new(current_user, game_data, filter: filter)
|
||||
items_to_delete = service.preview_deletions
|
||||
|
||||
render json: {
|
||||
|
|
@ -232,7 +234,8 @@ module Api
|
|||
update_existing: params[:update_existing],
|
||||
is_full_inventory: params[:is_full_inventory],
|
||||
reconcile_deletions: params[:reconcile_deletions],
|
||||
data: params[:data]&.to_unsafe_h
|
||||
data: params[:data]&.to_unsafe_h,
|
||||
filter: params[:filter]&.to_unsafe_h
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class WeaponImportService
|
|||
@update_existing = options[:update_existing] || false
|
||||
@is_full_inventory = options[:is_full_inventory] || false
|
||||
@reconcile_deletions = options[:reconcile_deletions] || false
|
||||
@filter = options[:filter] # { elements: [...], proficiencies: [...] }
|
||||
@created = []
|
||||
@updated = []
|
||||
@skipped = []
|
||||
|
|
@ -41,6 +42,7 @@ class WeaponImportService
|
|||
##
|
||||
# Previews what would be deleted in a sync operation.
|
||||
# Does not modify any data, just returns items that would be removed.
|
||||
# When a filter is active, only considers items matching that filter.
|
||||
#
|
||||
# @return [Array<CollectionWeapon>] Collection weapons that would be deleted
|
||||
def preview_deletions
|
||||
|
|
@ -56,10 +58,14 @@ class WeaponImportService
|
|||
return [] if game_ids.empty?
|
||||
|
||||
# Find collection weapons with game_ids NOT in the import
|
||||
@user.collection_weapons
|
||||
.includes(:weapon)
|
||||
.where.not(game_id: nil)
|
||||
.where.not(game_id: game_ids)
|
||||
# Scoped to filter criteria if present
|
||||
scope = @user.collection_weapons
|
||||
.includes(:weapon)
|
||||
.where.not(game_id: nil)
|
||||
.where.not(game_id: game_ids)
|
||||
|
||||
scope = apply_filter_scope(scope)
|
||||
scope
|
||||
end
|
||||
|
||||
##
|
||||
|
|
@ -313,18 +319,22 @@ class WeaponImportService
|
|||
##
|
||||
# Reconciles deletions by removing collection weapons not in the processed list.
|
||||
# Only called when @is_full_inventory and @reconcile_deletions are both true.
|
||||
# When a filter is active, only deletes items matching that filter.
|
||||
#
|
||||
# @return [Hash] Reconciliation result with deleted count and orphaned grid item IDs
|
||||
def reconcile_deletions
|
||||
# Find collection weapons with game_ids NOT in our processed list
|
||||
missing = @user.collection_weapons
|
||||
.where.not(game_id: nil)
|
||||
.where.not(game_id: @processed_game_ids)
|
||||
# Scoped to filter criteria if present
|
||||
scope = @user.collection_weapons
|
||||
.where.not(game_id: nil)
|
||||
.where.not(game_id: @processed_game_ids)
|
||||
|
||||
scope = apply_filter_scope(scope)
|
||||
|
||||
deleted_count = 0
|
||||
orphaned_grid_item_ids = []
|
||||
|
||||
missing.find_each do |coll_weapon|
|
||||
scope.find_each do |coll_weapon|
|
||||
# Collect IDs of grid items that will be orphaned
|
||||
grid_weapon_ids = GridWeapon.where(collection_weapon_id: coll_weapon.id).pluck(:id)
|
||||
orphaned_grid_item_ids.concat(grid_weapon_ids)
|
||||
|
|
@ -339,4 +349,32 @@ class WeaponImportService
|
|||
orphaned_grid_items: orphaned_grid_item_ids
|
||||
}
|
||||
end
|
||||
|
||||
##
|
||||
# Applies element and proficiency filters to a collection weapons scope.
|
||||
# Used to scope deletion checks to only items matching the current game filter.
|
||||
#
|
||||
# @param scope [ActiveRecord::Relation] The collection weapons relation to filter
|
||||
# @return [ActiveRecord::Relation] Filtered relation
|
||||
def apply_filter_scope(scope)
|
||||
return scope unless @filter.present?
|
||||
|
||||
# Element: check collection_weapon.element first (for element-changeable weapons),
|
||||
# fall back to weapon.element if nil
|
||||
if @filter[:elements].present? || @filter['elements'].present?
|
||||
elements = @filter[:elements] || @filter['elements']
|
||||
scope = scope.joins(:weapon).where(
|
||||
'collection_weapons.element IN (?) OR (collection_weapons.element IS NULL AND weapons.element IN (?))',
|
||||
elements, elements
|
||||
)
|
||||
end
|
||||
|
||||
# Proficiency: join through weapon
|
||||
if @filter[:proficiencies].present? || @filter['proficiencies'].present?
|
||||
proficiencies = @filter[:proficiencies] || @filter['proficiencies']
|
||||
scope = scope.joins(:weapon).where(weapons: { proficiency: proficiencies })
|
||||
end
|
||||
|
||||
scope
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue