コード例 #1
0
def test_patron_transaction_jsonresolver(patron_transaction_overdue_martigny):
    """Test patron_transaction json resolver."""
    rec = Record.create(
        {'patron_transaction': {
            '$ref': 'https://ils.rero.ch/api/patron_transactions/1'
            }
         }
    )
    assert extracted_data_from_ref(rec.get('patron_transaction')) == '1'

    # delete attached events to patron transaction
    for patron_event in patron_transaction_overdue_martigny.events:
        patron_event.delete(dbcommit=True, delindex=True)
    # deleted record
    patron_transaction_overdue_martigny.delete()
    with pytest.raises(JsonRefError):
        rec.replace_refs().dumps()

    # non existing record
    rec = Record.create(
        {'patron_transaction':
            {
                '$ref': 'https://ils.rero.ch/api/patron_transactions/n_e'}}
    )
    with pytest.raises(JsonRefError):
        rec.replace_refs().dumps()
コード例 #2
0
ファイル: circulation.py プロジェクト: zannkukai/rero-ils
def loan_overdue_martigny(app, document, item4_lib_martigny,
                          loc_public_martigny, item_type_standard_martigny,
                          librarian_martigny, patron_martigny,
                          circulation_policies):
    """Checkout an item to a patron.

    item4_lib_martigny is overdue.
    """
    transaction_date = datetime.now(timezone.utc).isoformat()

    item4_lib_martigny.checkout(
        patron_pid=patron_martigny.pid,
        transaction_location_pid=loc_public_martigny.pid,
        transaction_user_pid=librarian_martigny.pid,
        transaction_date=transaction_date,
        document_pid=extracted_data_from_ref(
            item4_lib_martigny.get('document')))
    flush_index(ItemsSearch.Meta.index)
    flush_index(LoansSearch.Meta.index)
    loan = Loan.get_record_by_pid(
        item4_lib_martigny.get_loan_pid_with_item_on_loan(
            item4_lib_martigny.pid))
    end_date = datetime.now(timezone.utc) - timedelta(days=25)
    loan['end_date'] = end_date.isoformat()
    loan = loan.update(loan, dbcommit=True, reindex=True)
    return loan
コード例 #3
0
ファイル: permissions.py プロジェクト: zannkukai/rero-ils
    def update(cls, user, record):
        """Update permission check.

        :param user: Logged user.
        :param record: Record to check.
        :return: True is action can be done.
        """
        # User must be be authenticated and have (at least) librarian role
        if not current_librarian:
            return False
        if current_librarian and not record:  # legacy
            return True
        # * User can only update record of its own organisation
        #   - 'sys_lib' could always update a record
        #   - 'lib' could only update cipo, if :
        #     --> cipo is defined at the library level
        #     --> current user library is into the cipo libraries list
        if current_librarian.organisation_pid == record.organisation_pid:
            if current_librarian.is_system_librarian:
                return True
            # librarian
            elif record.get('policy_library_level', False):
                cipo_library_pids = []
                for library in record.get('libraries', []):
                    cipo_library_pids.append(extracted_data_from_ref(library))
                # Intersection patron libraries pid and cipo library pids
                return len(
                    set(current_librarian.library_pids).intersection(
                        cipo_library_pids)) > 0
        return False
コード例 #4
0
def create_collections(input_file, max_item=10):
    """Create collections."""
    organisation_items = {}
    with open(input_file, 'r', encoding='utf-8') as request_file:
        collections = json.load(request_file)
        for collection_data in collections:
            organisation_pid = extracted_data_from_ref(
                collection_data.get('organisation').get('$ref'))
            if organisation_pid not in organisation_items:
                organisation_items[organisation_pid] =\
                    get_items_by_organisation_pid(organisation_pid)
            items = random.choices(
                organisation_items[organisation_pid],
                k=random.randint(1, max_item)
            )
            collection_data['items'] = []
            for item_pid in items:
                ref = get_ref_for_pid('items', item_pid)
                collection_data['items'].append({'$ref': ref})
            request = Collection.create(
                collection_data,
                dbcommit=True,
                reindex=True
            )
            click.echo('\tCollection: #{pid}'.format(
                pid=request.pid,
            ))
コード例 #5
0
def test_local_fields_es_mapping(db, org_sion, document,
                                 local_field_sion_data):
    """Test local fields elasticsearch mapping."""
    search = LocalFieldsSearch()
    mapping = get_mapping(search.Meta.index)
    assert mapping
    lofi = LocalField.create(local_field_sion_data,
                             dbcommit=True,
                             reindex=True,
                             delete_pid=True)
    flush_index(LocalFieldsSearch.Meta.index)
    assert mapping == get_mapping(search.Meta.index)

    assert lofi == local_field_sion_data
    assert lofi.get('pid') == '1'

    lofi = LocalField.get_record_by_pid('1')
    assert lofi == local_field_sion_data

    fetched_pid = fetcher(lofi.id, lofi)
    assert fetched_pid.pid_value == '1'
    assert fetched_pid.pid_type == 'lofi'

    document_pid = extracted_data_from_ref(lofi.get('parent'))
    search = DocumentsSearch().filter('term', pid=document_pid)
    document = list(search.scan())[0].to_dict()
    for field in document['local_fields']:
        if field['organisation_pid'] == document_pid:
            assert field['fields'] ==\
                local_field_sion_data['fields']['field_1']
コード例 #6
0
def test_patron_type_exist_name_and_organisation_pid(
        patron_type_children_martigny):
    """Test patron type name uniquness."""
    org_pid = extracted_data_from_ref(
        patron_type_children_martigny.get('organisation'))
    assert PatronType.exist_name_and_organisation_pid(
        patron_type_children_martigny.get('name'), org_pid)
    assert not PatronType.exist_name_and_organisation_pid(
        'not exists yet', org_pid)
コード例 #7
0
def test_extract_data_from_ref(app, patron_sion_data, patron_type_grown_sion):
    """Test extract_data_from_ref."""
    # Check real data
    ptty = patron_sion_data['patron']['type']
    assert extracted_data_from_ref(ptty, data='pid') == 'ptty4'
    assert extracted_data_from_ref(ptty, data='resource') == 'patron_types'
    assert extracted_data_from_ref(ptty, data='record_class') == PatronType
    ptty_record = extracted_data_from_ref(ptty, data='record')
    assert ptty_record.pid == patron_type_grown_sion.pid

    # check dummy data
    assert extracted_data_from_ref('dummy_data', data='pid') is None
    assert extracted_data_from_ref('dummy_data', data='resource') is None
    assert extracted_data_from_ref('dummy_data', data='record_class') is None
    assert extracted_data_from_ref('dummy_data', data='record') is None
    assert extracted_data_from_ref(ptty, data='dummy') is None
コード例 #8
0
ファイル: circulation.py プロジェクト: zannkukai/rero-ils
def loan_validated_martigny(app, document, item2_lib_martigny,
                            loc_public_martigny, item_type_standard_martigny,
                            librarian_martigny, patron_martigny,
                            circulation_policies):
    """Request and validate item to a patron.

    item2_lib_martigny is requested and validated to patron_martigny.
    """
    transaction_date = datetime.now(timezone.utc).isoformat()

    item2_lib_martigny.request(
        patron_pid=patron_martigny.pid,
        transaction_location_pid=loc_public_martigny.pid,
        transaction_user_pid=librarian_martigny.pid,
        transaction_date=transaction_date,
        pickup_location_pid=loc_public_martigny.pid,
        document_pid=extracted_data_from_ref(
            item2_lib_martigny.get('document')))
    flush_index(ItemsSearch.Meta.index)
    flush_index(LoansSearch.Meta.index)
    flush_index(NotificationsSearch.Meta.index)

    loan = list(
        item2_lib_martigny.get_loans_by_item_pid(
            item_pid=item2_lib_martigny.pid))[0]
    item2_lib_martigny.validate_request(
        pid=loan.pid,
        patron_pid=patron_martigny.pid,
        transaction_location_pid=loc_public_martigny.pid,
        transaction_user_pid=librarian_martigny.pid,
        transaction_date=transaction_date,
        pickup_location_pid=loc_public_martigny.pid,
        document_pid=extracted_data_from_ref(
            item2_lib_martigny.get('document')))
    flush_index(ItemsSearch.Meta.index)
    flush_index(LoansSearch.Meta.index)
    flush_index(NotificationsSearch.Meta.index)
    loan = list(
        item2_lib_martigny.get_loans_by_item_pid(
            item_pid=item2_lib_martigny.pid))[0]
    return loan
コード例 #9
0
ファイル: cli.py プロジェクト: zannkukai/rero-ils
def migrate_virtua_operation_logs(infile, verbose, debug, lazy):
    """Migrate Virtua operation log records in reroils.

    :param infile: Json operation log file.
    :param lazy: lazy reads file
    """
    enabled_logs = current_app.config.get('RERO_ILS_ENABLE_OPERATION_LOG')
    click.secho('Migrate Virtua operation log records:', fg='green')
    if lazy:
        # try to lazy read json file (slower, better memory management)
        data = read_json_record(infile)
    else:
        # load everything in memory (faster, bad memory management)
        data = json.load(infile)
    index_count = 0
    with click.progressbar(data) as bar:
        for oplg in bar:
            try:
                operation = oplg.get('operation')
                resource = extracted_data_from_ref(
                    oplg.get('record').get('$ref'), data='resource')
                pid_type = enabled_logs.get(resource)
                if pid_type and operation == OperationLogOperation.CREATE:
                    # The virtua create operation log overrides the reroils
                    # create operation log, the method to use is UPDATE
                    record_pid = extracted_data_from_ref(
                        oplg.get('record').get('$ref'), data='pid')

                    create_rec = \
                        OperationLog.get_create_operation_log_by_resource_pid(
                            pid_type, record_pid)
                    if create_rec:
                        create_rec.update(oplg, dbcommit=True, reindex=True)
                elif pid_type and operation == OperationLogOperation.UPDATE:
                    # The virtua update operation log is a new entry in the
                    # reroils operation log, the method to use is CREATE
                    OperationLog.create(data=oplg, dbcommit=True, reindex=True)
            except Exception:
                pass
        index_count += len(data)
    click.echo(f'created {index_count} operation logs.')
コード例 #10
0
def test_acq_receipts_jsonresolver(acq_receipt_fiction_martigny):
    """Acquisition receipts resolver tests."""
    data = {'$ref': 'https://bib.rero.ch/api/acq_receipts/acre1'}
    rec = Record.create({'acq_receipt': data})
    assert extracted_data_from_ref(rec.get('acq_receipt')) == 'acre1'
    # deleted record
    acq_receipt_fiction_martigny.delete()
    with pytest.raises(JsonRefError):
        rec.replace_refs().dumps()

    # non existing record
    data = {'$ref': 'https://bib.rero.ch/api/acq_receipts/n_e'}
    rec = Record.create({'acq_receipt': data})
    with pytest.raises(JsonRefError):
        rec.replace_refs().dumps()
コード例 #11
0
def test_budgets_jsonresolver(budget_2017_martigny):
    """Budgets resolver tests."""
    rec = Record.create({
        'budget': {'$ref': 'https://ils.rero.ch/api/budgets/budg5'}
    })
    assert extracted_data_from_ref(rec.get('budget')) == 'budg5'

    # deleted record
    budget_2017_martigny.delete()
    with pytest.raises(JsonRefError):
        rec.replace_refs().dumps()

    # non existing record
    rec = Record.create({
        'budget': {'$ref': 'https://ils.rero.ch/api/budgets/n_e'}
    })
    with pytest.raises(JsonRefError):
        rec.replace_refs().dumps()
コード例 #12
0
def test_acq_orders_jsonresolver(acq_order_fiction_martigny):
    """Acquisition orders resolver tests."""
    rec = Record.create(
        {'acq_order': {
            '$ref': 'https://ils.rero.ch/api/acq_orders/acor1'
        }})
    assert extracted_data_from_ref(rec.get('acq_order')) == 'acor1'
    # deleted record
    acq_order_fiction_martigny.delete()
    with pytest.raises(JsonRefError):
        rec.replace_refs().dumps()

    # non existing record
    rec = Record.create(
        {'acq_order': {
            '$ref': 'https://ils.rero.ch/api/acq_orders/n_e'
        }})
    with pytest.raises(JsonRefError):
        rec.replace_refs().dumps()
コード例 #13
0
ファイル: circulation.py プロジェクト: zannkukai/rero-ils
def loan_pending_martigny(app, item_lib_fully, loc_public_martigny,
                          librarian_martigny, patron2_martigny,
                          circulation_policies):
    """Create loan record with state pending.

    item_lib_fully is requested by patron2_martigny.
    """
    transaction_date = datetime.now(timezone.utc).isoformat()
    item_lib_fully.request(patron_pid=patron2_martigny.pid,
                           transaction_location_pid=loc_public_martigny.pid,
                           transaction_user_pid=librarian_martigny.pid,
                           transaction_date=transaction_date,
                           pickup_location_pid=loc_public_martigny.pid,
                           document_pid=extracted_data_from_ref(
                               item_lib_fully.get('document')))
    flush_index(ItemsSearch.Meta.index)
    flush_index(LoansSearch.Meta.index)
    loan = list(
        item_lib_fully.get_loans_by_item_pid(item_pid=item_lib_fully.pid))[0]
    return loan
コード例 #14
0
def test_vendors_jsonresolver(app, vendor_martigny):
    """Test vendor resolver."""
    rec = Record.create({
        'vendor': {'$ref': 'https://bib.rero.ch/api/vendors/vndr1'}
    })
    assert extracted_data_from_ref(rec.get('vendor')) == 'vndr1'

    # deleted record
    vendor_martigny.delete()
    with pytest.raises(Exception):
        rec.replace_refs().dumps()

    # non existing record
    rec = Record.create({
        'vendor': {'$ref': 'https://bib.rero.ch/api/vendors/n_e'}
    })

    with pytest.raises(JsonRefError) as error:
        rec.replace_refs().dumps()
    assert 'PIDDoesNotExistError' in str(error)
コード例 #15
0
def test_local_field_jsonresolver(local_field_martigny):
    """Test local fields json resolver."""
    local_field = local_field_martigny
    rec = Record.create({
        'local_field': {
            '$ref': 'https://bib.rero.ch/api/local_fields/lofi1'
        }
    })
    assert extracted_data_from_ref(rec.get('local_field')) == 'lofi1'

    # deleted record
    local_field.delete()
    with pytest.raises(JsonRefError):
        rec.replace_refs().dumps()

    # non existing record
    rec = Record.create(
        {'local_fields': {
            '$ref': 'https://bib.rero.ch/api/local_fields/n_e'
        }})
    with pytest.raises(JsonRefError):
        rec.replace_refs().dumps()
コード例 #16
0
def test_receipts_properties(acq_order_fiction_martigny,
                             acq_account_fiction_martigny,
                             acq_receipt_fiction_martigny,
                             acq_receipt_line_1_fiction_martigny,
                             acq_receipt_line_2_fiction_martigny,
                             lib_martigny):
    """Test receipt properties."""
    acre1 = acq_receipt_fiction_martigny
    acrl1 = acq_receipt_line_1_fiction_martigny
    acrl2 = acq_receipt_line_2_fiction_martigny
    # LIBRARY------------------------------------------------------------------
    assert acre1.library_pid == lib_martigny.pid
    # ORGANISATION ------------------------------------------------------------
    assert acre1.organisation_pid == lib_martigny.organisation_pid
    # ORDER -------------------------------------------------------------------
    assert acre1.order_pid == acq_order_fiction_martigny.pid
    # NOTE --------------------------------------------------------------------
    assert acre1.get_note(AcqReceiptNoteType.STAFF)
    # EXCHANGE_RATE -----------------------------------------------------------
    assert acre1.exchange_rate
    # AMOUNT ------------------------------------------------------------------
    adj_amount = sum(adj.get('amount') for adj in acre1.amount_adjustments)
    wished_amount = sum([acrl1.total_amount, acrl2.total_amount, adj_amount])
    assert acre1.total_amount == wished_amount
    # QUANTITY ----------------------------------------------------------------
    assert acre1.total_item_quantity == sum([acrl1.quantity, acrl2.quantity])
    # ACQ ACCOUNT -------------------------------------------------------------
    for amount in acre1.amount_adjustments:
        assert extracted_data_from_ref(amount.get('acq_account')) == \
            acq_account_fiction_martigny.pid
    # RECEIPT LINES -----------------------------------------------------------
    lines = [acrl1, acrl2]
    assert all(line in lines for line in acre1.get_receipt_lines())

    lines_pid = [line.pid for line in lines]
    assert all(pid in lines_pid for pid in acre1.get_receipt_lines('pids'))

    assert acre1.get_receipt_lines('count') == 2
コード例 #17
0
def test_patron_transaction_event_jsonresolver(
        patron_transaction_overdue_event_saxon):
    """Test patron transaction event json resolver."""
    rec = Record.create({
        'patron_transaction_event': {
            '$ref': 'https://bib.rero.ch/api/patron_transaction_events/1'
        }
    })
    assert extracted_data_from_ref(rec.get('patron_transaction_event')) == '1'

    # deleted record
    patron_transaction_overdue_event_saxon.delete()
    with pytest.raises(JsonRefError):
        rec.replace_refs().dumps()

    # non existing record
    rec = Record.create({
        'patron_transaction': {
            '$ref': 'https://bib.rero.ch/api/patron_transaction_events/n_e'
        }
    })
    with pytest.raises(JsonRefError):
        rec.replace_refs().dumps()
コード例 #18
0
def test_patron_pending_subscription(client, patron_type_grown_sion,
                                     patron_sion_no_email,
                                     librarian_sion_no_email,
                                     patron_transaction_overdue_event_martigny,
                                     lib_sion):
    """Test get pending subscription for patron."""
    # At the beginning, `patron_sion_no_email` should have one pending
    # subscription.
    pending_subscription = patron_sion_no_email.get_pending_subscriptions()
    assert len(pending_subscription) == 1

    # Pay this subscription.
    login_user_via_session(client, librarian_sion_no_email.user)
    post_entrypoint = 'invenio_records_rest.ptre_list'
    trans_pid = extracted_data_from_ref(
        pending_subscription[0]['patron_transaction'], data='pid')
    transaction = PatronTransaction.get_record_by_pid(trans_pid)
    payment = deepcopy(patron_transaction_overdue_event_martigny)
    del payment['pid']
    payment['type'] = 'payment'
    payment['subtype'] = 'cash'
    payment['amount'] = transaction.total_amount
    payment['operator'] = {
        '$ref': get_ref_for_pid('patrons', librarian_sion_no_email.pid)
    }
    payment['library'] = {'$ref': get_ref_for_pid('libraries', lib_sion.pid)}
    payment['parent'] = pending_subscription[0]['patron_transaction']
    res, _ = postdata(client, post_entrypoint, payment)
    assert res.status_code == 201
    transaction = PatronTransaction.get_record_by_pid(transaction.pid)
    assert transaction.status == 'closed'

    # reload the patron and check the pending subscription. As we paid the
    # previous subscription, there will be none pending subscription
    patron_sion_no_email = Patron.get_record_by_pid(patron_sion_no_email.pid)
    pending_subscription = patron_sion_no_email.get_pending_subscriptions()
    assert len(pending_subscription) == 0
コード例 #19
0
ファイル: circulation.py プロジェクト: rerowep/rero-ils
 def loan_pid(self):
     """Shortcut for loan pid of the notification."""
     return extracted_data_from_ref(self['context']['loan'])
コード例 #20
0
ファイル: acq_order.py プロジェクト: rerowep/rero-ils
 def acq_order_pid(self):
     """Shortcut for acq order pid of the notification."""
     return extracted_data_from_ref(self['context']['order'])
コード例 #21
0
def update_items_locations_and_types(sender, record=None, **kwargs):
    """This method checks if the items of the parent record needs an update.

    This method checks the location and item_type of each item attached to the
    holding record and update the item record accordingly.
    This method should be connect with 'after_record_update'.
    :param record: the holding record.
    """
    if not isinstance(record, Holding) and \
            record.get('holdings_type') == HoldingTypes.SERIAL:
        # identify all items records attached to this serials holdings record
        # with different location and item_type.
        hold_circ_pid = record.circulation_category_pid
        hold_loc_pid = record.location_pid
        search = ItemsSearch().filter('term', holding__pid=record.pid)
        item_hits = search.\
            filter('bool', should=[
                        Q('bool', must_not=[
                            Q('match', item_type__pid=hold_circ_pid)]),
                        Q('bool', must_not=[
                            Q('match', location__pid=hold_loc_pid)])])\
            .source(['pid'])
        items = [hit.meta.id for hit in item_hits.scan()]
        items_to_index = []
        # update these items and make sure they have the same location/category
        # as the parent holdings record.
        for id in items:
            try:
                item = Item.get_record_by_id(id)
                if not item:
                    continue
                items_to_index.append(id)
                item_temp_loc_pid, item_temp_type_pid = None, None
                # remove the item temporary_location if it is equal to the
                # new item location.
                temporary_location = item.get('temporary_location', {})
                if temporary_location:
                    item_temp_loc_pid = extracted_data_from_ref(
                        temporary_location.get('$ref'))
                if hold_loc_pid != item.location_pid:
                    if item_temp_loc_pid == hold_loc_pid:
                        item.pop('temporary_location', None)
                    item['location'] = {
                        '$ref': get_ref_for_pid('locations', hold_loc_pid)
                    }
                # remove the item temporary_item_type if it is equal to the
                # new item item_type.
                temporary_type = item.get('temporary_item_type', {})
                if temporary_type:
                    item_temp_type_pid = extracted_data_from_ref(
                        temporary_type.get('$ref'))
                if hold_circ_pid != item.item_type_pid:
                    if item_temp_type_pid == hold_circ_pid:
                        item.pop('temporary_item_type', None)
                    item['item_type'] = {
                        '$ref': get_ref_for_pid('item_types', hold_circ_pid)
                    }
                # update directly in database.
                db.session.query(item.model_cls).filter_by(id=item.id).update(
                    {item.model_cls.json: item})
            except Exception as err:
                pass
        if items_to_index:
            # commit session
            db.session.commit()
            # bulk indexing of item records.
            indexer = ItemsIndexer()
            indexer.bulk_index(items_to_index)
            process_bulk_queue.apply_async()
コード例 #22
0
ファイル: extensions.py プロジェクト: rerowep/rero-ils
 def populate_currency(record):
     """Add vendor currency to order data."""
     vendor = record.get('vendor')
     if vendor:
         vendor = extracted_data_from_ref(vendor, data='record')
         record['currency'] = vendor.get('currency')