def get_provisional_items_pids_candidate_to_delete(): """Returns checked-in provisional items pids. Returns list of candidate provisional items pids to delete, based on the status of the item. Filtering by the status `ItemStatus.ON_SHELF` removes items with active loans. in addition, remove items with active fees. :return an item pid generator. """ from rero_ils.modules.items.api import ItemsSearch # query ES index for open fees query_fees = PatronTransactionsSearch()\ .filter('term', status='open')\ .filter('exists', field='item')\ .filter('range', total_amount={'gt': 0})\ .source('item') # list of item pids with open fees item_pids_with_fees = [hit.item.pid for hit in query_fees.scan()] query = ItemsSearch()\ .filter('term', type=TypeOfItem.PROVISIONAL) \ .filter('terms', status=[ItemStatus.ON_SHELF]) \ .exclude('terms', pid=item_pids_with_fees)\ .source('pid') for hit in query.scan(): yield hit.pid
def index_items_with_temporary_location(): """Index items with temporary location.""" query = ItemsSearch() \ .filter('exists', field='temporary_location').source(['pid']) ids = [(hit.meta.id, hit.pid) for hit in query.scan()] for id, pid in ids: item = Item.get_record_by_id(id) item.reindex() LOGGER.info(f' * Reindexed item#{pid}')
def index_items_with_temporary_location(): """Index items with temporary location.""" query = ItemsSearch() \ .filter('exists', field='temporary_location').source(['pid']) ids = [(hit.meta.id, hit.pid) for hit in query.scan()] errors = 0 for idx, (id, pid) in enumerate(ids): LOGGER.info(f'{idx} * Reindex item: {pid}') try: item = Item.get_record_by_id(id) item.reindex() except Exception as err: LOGGER.error(f'{idx} * Reindex item: {pid} {err}') errors += 1 return errors
def get(self, **kwargs): """Search records.""" search_obj = ItemsSearch() search, qs_kwargs = self.search_factory(search_obj) return self.make_response(pid_fetcher=None, search_result=search.scan())
def test_item_es_mapping(es_clear, db, document, location, item_type, item_on_loan_data_tmp): """.""" search = ItemsSearch() mapping = get_mapping(search.Meta.index) assert mapping Item.create(item_on_loan_data_tmp, dbcommit=True, reindex=True, delete_pid=True) assert mapping == get_mapping(search.Meta.index)
def test_item_es_mapping(document, loc_public_martigny, item_type_standard_martigny, item_lib_martigny_data_tmp): """Test item elasticsearch mapping.""" search = ItemsSearch() mapping = get_mapping(search.Meta.index) assert mapping Item.create(item_lib_martigny_data_tmp, dbcommit=True, reindex=True, delete_pid=True) assert mapping == get_mapping(search.Meta.index)
def test_location_get_links_to_me(loc_public_martigny, loc_public_sion, item_lib_martigny): """Test pickup locations retrieval.""" assert loc_public_martigny.get_links_to_me() == {'items': 1} assert loc_public_martigny.get_links_to_me(get_pids=True) == { 'items': ['item1'] } assert loc_public_sion.get_links_to_me() == {} item_lib_martigny['temporary_location'] = { '$ref': f'https://bib.rero.ch/api/locations/{loc_public_sion.pid}' } item_lib_martigny.update(data=item_lib_martigny, dbcommit=True, reindex=True) ItemsSearch.flush_and_refresh() assert loc_public_sion.get_links_to_me() == {'items': 1} assert loc_public_sion.get_links_to_me(get_pids=True) == { 'items': ['item1'] }
def same_location_validator(item_pid, input_location_pid): """Validate that item and transaction location are in same library. :param item_pid: the item_pid object :type input_location_pid: object :return: true if in same library otherwise false :rtype: boolean """ from rero_ils.modules.items.api import ItemsSearch lib_from_loc = LocationsSearch().get_record_by_pid( input_location_pid).library.pid lib_from_item = ItemsSearch().get_record_by_pid( item_pid.get('value')).library.pid return lib_from_loc == lib_from_item
def negative_availability_changes(sender, record=None, *args, **kwargs): """Reindex related items if negative availability changes.""" if isinstance(record, ItemType): ori_record = ItemType.get_record_by_pid(record.pid) record_availability = record.get('negative_availability', False) original_availability = ori_record.get('negative_availability', False) if record_availability != original_availability: # get all item uuid's related to the item type and mark them for # reindex into a asynchronous celery queue. item_uuids = [] search = ItemsSearch()\ .filter('bool', should=[ Q('match', item_type__pid=record.pid), Q('match', temporary_item_type__pid=record.pid) ]) \ .source().scan() for hit in search: item_uuids.append(hit.meta.id) ItemTypesIndexer().bulk_index(item_uuids) process_bulk_queue.apply_async()
def get_counts(pid, action): """Calculate items_count and public_items_count. :param str pid: holding pid. :param str action: upgrade or downgrade. :return: items_count and public_items_count """ if action == 'upgrade': item_search = ItemsSearch()[0:0]\ .filter('term', holding__pid=pid)\ .filter('term', issue__status="received") else: item_search = ItemsSearch()[0:0]\ .filter('term', holding__pid=pid) items_count = item_search.count() results = item_search.source([]).scan() public_items_count = len([res for res in results if "_masked" not in res or not res['_masked']]) return items_count, public_items_count
def get_items_by_organisation_pid(organisation_pid): """Get items by organisation pid.""" query = ItemsSearch().filter( 'term', organisation__pid=organisation_pid)\ .source('pid') return [item.pid for item in query.scan()]
def test_item_organisation_pid(client, org_martigny, item_lib_martigny): """Test organisation pid has been added during the indexing.""" search = ItemsSearch() item = next(search.filter('term', pid=item_lib_martigny.pid).scan()) assert item.organisation.pid == org_martigny.pid
def get_holdings_items(document_pid, organisation_pids=None, library_pids=None, location_pids=None): """Create Holding and Item informations. :param document_pid: document pid to use for holdings search :param organisation_pids: Which organisations items to add. :param library_pids: Which from libraries items to add. :param location_pids: Which from locations items to add. :returns: list of holding informations with associated organisation, library and location pid, name informations. """ def get_name(resource, pid): """Get name from resource. The name will be cached. :param resource: Resource class to use. :param pid: Pid for the resource to get the name from. :returns: name from the resource """ data = resource.get_record_by_pid(pid) if data: return data.get('name') results = [] if document_pid: holding_pids = Holding.get_holdings_pid_by_document_pid( document_pid=document_pid, with_masked=False) holding_pids = list(holding_pids) organisations = {} libraries = {} locations = {} query = HoldingsSearch().filter('terms', pid=holding_pids) if organisation_pids: query = query.filter( {'terms': { 'organisation.pid': organisation_pids }}) if library_pids: query = query.filter({'terms': {'library.pid': library_pids}}) if location_pids: query = query.filter({'terms': {'location.pid': location_pids}}) for hit in query.scan(): holding = hit.to_dict() organisation_pid = hit.organisation.pid if organisation_pid not in organisations: organisations[organisation_pid] = get_name( Organisation, organisation_pid) library_pid = hit.library.pid if library_pid not in libraries: libraries[library_pid] = get_name(Library, library_pid) location_pid = hit.location.pid if location_pid not in locations: locations[location_pid] = get_name(Location, location_pid) result = { 'organisation': { 'pid': organisation_pid, 'name': organisations[organisation_pid] }, 'library': { 'pid': library_pid, 'name': libraries[library_pid] }, 'location': { 'pid': location_pid, 'name': locations[location_pid] }, 'holdings': { 'call_number': holding.get('call_number'), 'second_call_number': holding.get('second_call_number'), 'enumerationAndChronology': holding.get('enumerationAndChronology'), 'electronic_location': holding.get('electronic_location', []), 'notes': holding.get('notes', []), 'supplementaryContent': holding.get('supplementaryContent'), 'index': holding.get('index'), 'missing_issues': holding.get('missing_issues'), } } if hit.holdings_type == 'standard': item_pids = Item.get_items_pid_by_holding_pid( hit.pid, with_masked=False) item_hits = ItemsSearch() \ .filter('terms', pid=list(item_pids)) \ .scan() for item_hit in item_hits: item_data = item_hit.to_dict() item_result = result item_result['item'] = { 'barcode': item_data.get('barcode'), 'all_number': item_data.get('all_number'), 'second_call_number': item_data.get('second_call_number'), 'enumerationAndChronology': item_data.get('enumerationAndChronology'), 'url': item_data.get('url'), 'notes': item_data.get('notes', []), } results.append(item_result) else: results.append(result) return results