Exemplo n.º 1
0
def item_on_shelf(app, document, item_on_shelf_data, location, item_type):
    """."""
    item = Item.create(
        data=item_on_shelf_data,
        delete_pid=False,
        dbcommit=True,
        reindex=True)
    flush_index(ItemsSearch.Meta.index)
    return item
Exemplo n.º 2
0
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}')
Exemplo n.º 3
0
def item_lib_fully(app, document, item_lib_fully_data, loc_public_fully,
                   item_type_standard_martigny):
    """Create item of fully library."""
    item = Item.create(data=item_lib_fully_data,
                       delete_pid=False,
                       dbcommit=True,
                       reindex=True)
    flush_index(ItemsSearch.Meta.index)
    return item
Exemplo n.º 4
0
def item2_lib_sion(app, document, item2_lib_sion_data, loc_restricted_sion,
                   item_type_regular_sion):
    """Create item of sion library."""
    item = Item.create(data=item2_lib_sion_data,
                       delete_pid=False,
                       dbcommit=True,
                       reindex=True)
    flush_index(ItemsSearch.Meta.index)
    return item
Exemplo n.º 5
0
def test_item_different_actions(client, librarian_martigny_no_email,
                                lib_martigny, patron_martigny_no_email,
                                loc_public_martigny, item_lib_martigny,
                                json_header, item_type_standard_martigny,
                                circ_policy_short_martigny,
                                patron_type_children_martigny, lib_saxon,
                                loc_public_saxon, librarian_saxon_no_email):
    """Test item possible actions other scenarios."""
    login_user_via_session(client, librarian_martigny_no_email.user)
    circ_policy_origin = deepcopy(circ_policy_short_martigny)
    circ_policy = circ_policy_short_martigny

    patron_pid = patron_martigny_no_email.pid
    res = client.get(
        url_for('api_item.item',
                item_barcode='does not exist',
                patron_pid=patron_pid))
    assert res.status_code == 404

    res, data = postdata(
        client, 'api_item.checkout',
        dict(item_pid=item_lib_martigny.pid, patron_pid=patron_pid))
    assert res.status_code == 200
    loan_pid = data.get('action_applied')[LoanAction.CHECKOUT].get('pid')

    record = Item.get_record_by_pid(item_lib_martigny.pid)

    class current_i18n:
        class locale:
            language = 'en'

    with mock.patch('rero_ils.modules.items.api.current_i18n', current_i18n):
        text = item_status_text(record, format='medium', locale='en')
        assert 'due until' in text

    res, _ = postdata(
        client,
        'api_item.checkin',
        dict(item_pid='does not exist',
             pid=loan_pid,
             transaction_location_pid=loc_public_saxon.pid),
    )
    assert res.status_code == 404

    res, data = postdata(
        client,
        'api_item.checkin',
        dict(item_pid=item_lib_martigny.pid,
             pid=loan_pid,
             transaction_location_pid=loc_public_saxon.pid),
    )
    assert res.status_code == 200
    loan_pid = data.get('action_applied')[LoanAction.CHECKIN].get('pid')

    data = {'pid': loan_pid}
    return_data = item_lib_martigny.prior_checkout_actions(data)
    assert return_data == {}
Exemplo n.º 6
0
    def get_items(self):
        """Get items.

        :param self: self
        :return: list of items linked to collection
        """
        return [
            Item.get_record_by_pid(item['pid'])
            for item in self.replace_refs().get('items', [])
        ]
Exemplo n.º 7
0
def get_pickup_locations(item_pid):
    """HTTP request to return the available pickup locations for an item.

    :param item_pid: the item pid
    """
    item = Item.get_record_by_pid(item_pid)
    if not item:
        abort(404, 'Item not found')
    locations = record_library_pickup_locations(item)
    return jsonify({'locations': locations})
Exemplo n.º 8
0
def test_holding_delete_after_item_deletion(
        client, holding_lib_martigny, item_lib_martigny):
    """Test automatic holding delete after deleting last item."""
    for pid in Item.get_all_pids():
        if pid != item_lib_martigny.pid:
            item = Item.get_record_by_pid(pid)
            Item.delete(item, dbcommit=True, delindex=True)
            flush_index(ItemsSearch.Meta.index)

    pid = holding_lib_martigny.pid
    holding = Holding.get_record_by_pid(pid)
    assert not holding.can_delete

    item_lib_martigny.delete(dbcommit=True, delindex=True)
    flush_index(ItemsSearch.Meta.index)

    pid = holding_lib_martigny.pid
    holding = Holding.get_record_by_pid(pid)
    assert not holding
Exemplo n.º 9
0
def test_item_create(item_lib_martigny_data_tmp, item_lib_martigny):
    """Test itemanisation creation."""
    item = Item.create(item_lib_martigny_data_tmp, delete_pid=True)
    assert item == item_lib_martigny_data_tmp
    # we have used item_lib_martigny_data_tmp two times -> pid == 2
    assert item.get('pid') == '2'
    assert item.can_delete

    item = Item.get_record_by_pid('1')
    item_lib_martigny_data_tmp['pid'] = '1'
    assert item == item_lib_martigny_data_tmp

    fetched_pid = item_id_fetcher(item.id, item)
    assert fetched_pid.pid_value == '1'
    assert fetched_pid.pid_type == 'item'

    item_lib_martigny.delete_from_index()
    assert not item_lib_martigny.delete_from_index()
    item_lib_martigny.dbcommit(forceindex=True)
Exemplo n.º 10
0
def test_checkout_on_item_on_loan(
        item_on_loan_martigny_patron_and_loan_on_loan,
        patron_martigny_no_email, patron2_martigny_no_email,
        loc_public_martigny, librarian_martigny_no_email):
    """Test CHECKOUT on an ON_LOAN item."""
    # Prepare a new item with an ITEM_ON_LOAN loan
    onloan_item, patron, loan = item_on_loan_martigny_patron_and_loan_on_loan
    assert onloan_item.number_of_requests() == 0

    # the following tests the circulation action CHECKOUT_3_1
    # an ON_LOAN item
    # checkout patron = patron of current loan
    # can NOT be CHECKOUT
    params = {
        'patron_pid': patron_martigny_no_email.pid,
        'transaction_location_pid': loc_public_martigny.pid,
        'transaction_user_pid': librarian_martigny_no_email.pid,
        'pickup_location_pid': loc_public_martigny.pid
    }
    # Checkout it! CHECKOUT patron == current LOAN patron
    assert params['patron_pid'] == patron['pid']
    with pytest.raises(NoValidTransitionAvailableError):
        asked_item, actions = onloan_item.checkout(**params, pid=loan.pid)
    # Check item is ON_SHELF (because no
    # other request + item_member = transaction one)
    checkout_loan = Loan.get_record_by_pid(loan.pid)
    asked_item = Item.get_record_by_pid(onloan_item.pid)
    assert asked_item.status == ItemStatus.ON_LOAN
    assert checkout_loan['state'] == LoanState.ITEM_ON_LOAN

    # the following tests the circulation action CHECKOUT_3_2
    # an ON_LOAN item
    # checkout patron != patron of current loan
    # can NOT be CHECKOUT
    params['patron_pid'] = patron2_martigny_no_email.pid
    assert params['patron_pid'] != patron['pid']
    with pytest.raises(ItemNotAvailableError):
        asked_item, actions = onloan_item.checkout(**params)
    asked_item = Item.get_record_by_pid(onloan_item.pid)
    checkout_loan = Loan.get_record_by_pid(loan.pid)
    assert asked_item.status == ItemStatus.ON_LOAN
    assert checkout_loan['state'] == LoanState.ITEM_ON_LOAN
    assert asked_item.number_of_requests() == 0
Exemplo n.º 11
0
def can_extend(loan_pid):
    """Loan can extend."""
    loan = Loan.get_record_by_pid(loan_pid)
    item_pid = loan.get('item_pid', {}).get('value')
    can_extend = {'can': False, 'reasons': []}
    if item_pid:
        item = Item.get_record_by_pid(item_pid)
        can, reasons = item.can(ItemCirculationAction.EXTEND, loan=loan)
        can_extend = {'can': can, 'reasons': reasons}
    return jsonify(can_extend)
Exemplo n.º 12
0
def test_less_than_one_day_checkout(
        circ_policy_less_than_one_day_martigny, patron_martigny_no_email,
        patron2_martigny_no_email, item_lib_martigny, loc_public_martigny,
        librarian_martigny_no_email,
        item_on_shelf_martigny_patron_and_loan_pending):
    """Test checkout on an ON_SHELF item with 'less than one day' cipo."""
    # Create a new item in ON_SHELF (without Loan)
    data = deepcopy(item_lib_martigny)
    data.pop('barcode')
    data.setdefault('status', ItemStatus.ON_SHELF)
    created_item = Item.create(data=data,
                               dbcommit=True,
                               reindex=True,
                               delete_pid=True)

    # Check item is ON_SHELF and NO PENDING loan exist!
    assert created_item.number_of_requests() == 0
    assert created_item.status == ItemStatus.ON_SHELF
    assert not created_item.is_requested_by_patron(
        patron2_martigny_no_email.get('patron', {}).get('barcode'))

    # the following tests the circulation action CHECKOUT_1_1
    # an ON_SHELF item
    # WITHOUT pending loan
    # CAN be CHECKOUT for less than one day
    params = {
        'patron_pid': patron2_martigny_no_email.pid,
        'transaction_location_pid': loc_public_martigny.pid,
        'transaction_user_pid': librarian_martigny_no_email.pid,
        'pickup_location_pid': loc_public_martigny.pid
    }
    onloan_item, actions = created_item.checkout(**params)
    loan = Loan.get_record_by_pid(actions[LoanAction.CHECKOUT].get('pid'))
    # Check loan is ITEM_ON_LOAN and item is ON_LOAN
    assert onloan_item.number_of_requests() == 0
    assert onloan_item.status == ItemStatus.ON_LOAN
    assert loan['state'] == LoanState.ITEM_ON_LOAN

    # Check due date
    loan_end_date = loan.get('end_date')
    lib = Library.get_record_by_pid(onloan_item.library_pid)
    today = datetime.now(pytz.utc)
    # Get next open day
    next_open_day = lib.next_open(today)
    if lib.is_open(today):
        next_open_day = today
    # Loan date should be in UTC.
    loan_datetime = ciso8601.parse_datetime(loan_end_date)
    # Compare year, month and date
    fail_msg = "Check timezone for Loan and Library. \
It should be the same date, even if timezone changed."

    assert loan_datetime.year == next_open_day.year, fail_msg
    assert loan_datetime.month == next_open_day.month, fail_msg
    assert loan_datetime.day == next_open_day.day, fail_msg
Exemplo n.º 13
0
    def decorated_view(*args, **kwargs):
        try:
            data = flask_request.get_json()
            description = data.pop('description')
        except KeyError:
            # The description parameter is missing.
            abort(400, str('missing description parameter.'))

        try:
            holding_pid = data.pop('holding_pid', None)
            holding = Holding.get_record_by_pid(holding_pid)
            if not holding:
                abort(404, 'Holding not found')
            # create a provisional item
            item_metadata = {
                'type': 'provisional',
                'document': {
                    '$ref': get_ref_for_pid('doc', holding.document_pid)
                },
                'location': {
                    '$ref': get_ref_for_pid('loc', holding.location_pid)
                },
                'item_type': {
                    '$ref':
                    get_ref_for_pid('itty', holding.circulation_category_pid)
                },
                'enumerationAndChronology': description,
                'status': ItemStatus.ON_SHELF,
                'holding': {
                    '$ref': get_ref_for_pid('hold', holding.pid)
                }
            }
            item = Item.create(item_metadata, dbcommit=True, reindex=True)

            _, action_applied = func(holding, item, data, *args, **kwargs)
            return jsonify({'action_applied': action_applied})
        except NoCirculationActionIsPermitted:
            # The circulation specs do not allow updates on some loan states.
            return jsonify({'status': 'error: Forbidden'}), 403
        except MissingRequiredParameterError as error:
            # Return error 400 when there is a missing required parameter
            abort(400, str(error))
        except CirculationException as error:
            abort(403, error.description or str(error))
        except NotFound as error:
            raise error
        except exceptions.RequestError as error:
            # missing required parameters
            return jsonify({'status': f'error: {error}'}), 400
        except Exception as error:
            # TODO: need to know what type of exception and document there.
            # raise error
            current_app.logger.error(str(error))
            return jsonify({'status': f'error: {error}'}), 400
Exemplo n.º 14
0
def test_item_create(db, es_clear, item_lib_martigny_data_tmp,
                     item_lib_martigny):
    """Test itemanisation creation."""
    item = Item.create(item_lib_martigny_data_tmp, delete_pid=True)
    del item['holding']
    assert item == item_lib_martigny_data_tmp
    assert item.get('pid') == '1'
    assert item.can_delete

    item = Item.get_record_by_pid('1')
    del item['holding']
    assert item == item_lib_martigny_data_tmp

    fetched_pid = item_id_fetcher(item.id, item)
    assert fetched_pid.pid_value == '1'
    assert fetched_pid.pid_type == 'item'

    item_lib_martigny.delete_from_index()
    assert not item_lib_martigny.delete_from_index()
    item_lib_martigny.dbcommit(forceindex=True)
Exemplo n.º 15
0
def test_automatic_checkin(client, librarian_martigny_no_email, lib_martigny,
                           patron_martigny_no_email, loc_public_martigny,
                           item_lib_martigny, json_header,
                           item_type_standard_martigny,
                           circ_policy_short_martigny,
                           patron_type_children_martigny, lib_saxon,
                           loc_public_saxon, librarian_saxon_no_email):
    """Test item automatic checkin."""
    login_user_via_session(client, librarian_saxon_no_email.user)
    circ_policy_origin = deepcopy(circ_policy_short_martigny)
    circ_policy = circ_policy_short_martigny

    record, actions = item_lib_martigny.automatic_checkin()
    assert actions == {'no': None}

    res = client.post(
        url_for('api_item.librarian_request'),
        data=json.dumps(
            dict(
                item_pid=item_lib_martigny.pid,
                pickup_location_pid=loc_public_saxon.pid,
                patron_pid=patron_martigny_no_email.pid
            )
        ),
        content_type='application/json',
    )
    assert res.status_code == 200
    data = get_json(res)
    loan_pid = data.get('action_applied')[LoanAction.REQUEST].get('pid')

    res = client.post(
        url_for('api_item.validate_request'),
        data=json.dumps(
            dict(
                item_pid=item_lib_martigny.pid,
                pid=loan_pid,
                transaction_location_pid=loc_public_martigny.pid
            )
        ),
        content_type='application/json',
    )
    assert res.status_code == 200

    item = Item.get_record_by_pid(item_lib_martigny.pid)
    assert item.status == ItemStatus.IN_TRANSIT

    text = item_status_text(item, format='medium', locale='en')
    assert text == 'not available (requested) (in_transit)'

    record, actions = item.automatic_checkin()
    assert 'receive' in actions

    item.cancel_loan(pid=loan_pid)
    assert item.status == ItemStatus.ON_SHELF
Exemplo n.º 16
0
def test_nb_item_requests(db, minimal_item_record, minimal_patron_only_record):
    """Test number of item requests."""
    assert minimal_patron_only_record['barcode']
    patron_barcode = minimal_patron_only_record['barcode']
    item = Item.create({})
    item.update(minimal_item_record, dbcommit=True)
    item.request_item(patron_barcode=patron_barcode)
    tr_barcode = item['_circulation']['holdings'][2]['patron_barcode']
    assert tr_barcode == patron_barcode
    number_requests = item.number_of_item_requests()
    assert number_requests == 2
Exemplo n.º 17
0
def test_regular_issue_creation_update_delete_api(
        client, holding_lib_martigny_w_patterns, loc_public_martigny,
        lib_martigny):
    """Test create, update and delete of a regular issue API."""
    holding = holding_lib_martigny_w_patterns
    issue_display, expected_date = holding._get_next_issue_display_text(
                        holding.get('patterns'))
    issue = holding.receive_regular_issue(dbcommit=True, reindex=True)
    issue_pid = issue.pid
    assert holding.delete(dbcommit=True, delindex=True)
    assert not Item.get_record_by_pid(issue_pid)
Exemplo n.º 18
0
def test_checkin_on_item_on_loan_with_requests(
        item3_on_loan_martigny_patron_and_loan_on_loan,
        loc_public_martigny, librarian_martigny,
        patron2_martigny):
    """Test checkin on an on_loan item with requests at local library."""
    # the following tests the circulation action CHECKIN_3_2_1
    # for an item on_loan, with pending requests. when the pickup library of
    # the first pending request equal to the transaction library,
    # checkin the item and item becomes at_desk.
    # the on_loan is returned and validating the first pending loan request.
    #
    # In this test, we will also ensure that the request expiration date of the
    # automatic validated request is correct
    item, patron, loan = item3_on_loan_martigny_patron_and_loan_on_loan

    # create a request on the same item one day after the first loan
    tomorrow = ciso8601.parse_datetime(loan['start_date']) + timedelta(days=10)
    with freeze_time(tomorrow.isoformat()):
        item, actions = item.request(
            pickup_location_pid=loc_public_martigny.pid,
            patron_pid=patron2_martigny.pid,
            transaction_location_pid=loc_public_martigny.pid,
            transaction_user_pid=librarian_martigny.pid
        )
        requested_loan_pid = actions[LoanAction.REQUEST].get('pid')
        requested_loan = Loan.get_record_by_pid(requested_loan_pid)

    # Check-in the item
    #  * reload item, loan and requested_loan
    #  * ensure the item is still AT_DESK (because the first pending request
    #    has been automatically validate and pickup location is the same than
    #    previous loan location)
    #  * ensure first loan is concluded
    #  * ensure the requested loan is now "AT_DESK" with a valid request
    #    expiration date
    next_day = tomorrow + timedelta(days=10)
    with freeze_time(next_day.isoformat()):
        item, actions = item.checkin(
            patron_pid=patron2_martigny.pid,
            transaction_location_pid=loc_public_martigny.pid,
            transaction_user_pid=librarian_martigny.pid,
            pickup_location_pid=loc_public_martigny.pid
        )

    item = Item.get_record_by_pid(item.pid)
    loan = Loan.get_record_by_pid(loan.pid)
    requested_loan = Loan.get_record_by_pid(requested_loan.pid)

    assert item.status == ItemStatus.AT_DESK
    assert loan['state'] == LoanState.ITEM_RETURNED
    assert requested_loan['state'] == LoanState.ITEM_AT_DESK
    trans_date = ciso8601.parse_datetime(requested_loan['transaction_date'])
    assert trans_date.strftime('%Y%m%d') == next_day.strftime('%Y%m%d')
Exemplo n.º 19
0
def test_update_loan_pickup_location(client, librarian_martigny_no_email,
                                     patron_martigny_no_email,
                                     loc_public_martigny, loc_public_saxon,
                                     item3_lib_martigny, circulation_policies):
    """Test loan pickup location change."""
    login_user_via_session(client, librarian_martigny_no_email.user)
    item_pid = item3_lib_martigny.pid
    first_loc_pid = loc_public_saxon.pid
    new_loc_pid = loc_public_martigny.pid
    # request an item by a librarian
    res, req_data = postdata(
        client, 'api_item.librarian_request',
        dict(item_pid=item_pid,
             pickup_location_pid=first_loc_pid,
             patron_pid=patron_martigny_no_email.pid))
    assert res.status_code == 200
    # Update pickup location of the request, no loan pid
    loan_pid = req_data.get('action_applied')[LoanAction.REQUEST].get('pid')
    res, data = postdata(
        client, 'api_item.update_loan_pickup_location',
        dict(item_pid=item_pid, pickup_location_pid=new_loc_pid))
    assert res.status_code == 400
    # Update pickup location of the request, no pickup location pid
    res, data = postdata(client, 'api_item.update_loan_pickup_location',
                         dict(item_pid=item_pid, loan_pid=loan_pid))
    assert res.status_code == 400
    # Update pickup location of the request
    res, data = postdata(
        client, 'api_item.update_loan_pickup_location',
        dict(item_pid=item_pid,
             pickup_location_pid=new_loc_pid,
             loan_pid=loan_pid))
    assert res.status_code == 200
    assert data.get('pickup_location_pid') == new_loc_pid
    # Change loan state to 'ITEM_AT_DESK'.
    # WARNING: Use loan from test_patron_checkouts_order (item3_lib_martigny)
    loans = Item.get_loans_by_item_pid(item_pid)
    for loan in loans:
        if loan.get('state') == 'ITEM_ON_LOAN':
            res, _ = postdata(
                client,
                'api_item.checkin',
                dict(item_pid=item_pid, pid=loan.get('pid')),
            )
            assert res.status_code == 200
    # Update pickup location of the request:
    # loan state different from 'pending'
    res, data = postdata(
        client, 'api_item.update_loan_pickup_location',
        dict(item_pid=item_pid,
             pickup_location_pid=new_loc_pid,
             loan_pid=loan_pid))
    assert res.status_code == 403
Exemplo n.º 20
0
def test_checkout_in_transit_return_same_library(
        client, librarian_martigny_no_email, librarian_saxon_no_email,
        patron_martigny_no_email, loc_public_martigny,
        item_type_standard_martigny, loc_public_saxon, item2_lib_martigny,
        json_header, circulation_policies):
    """Test item checkout, in-transit, checkin scenarios."""
    login_user_via_session(client, librarian_martigny_no_email.user)
    # checkout the item at location A
    res, data = postdata(
        client, 'api_item.checkout',
        dict(item_pid=item2_lib_martigny.pid,
             patron_pid=patron_martigny_no_email.pid,
             transaction_location_pid=loc_public_martigny.pid))
    assert res.status_code == 200
    item_data = data.get('metadata')
    actions = data.get('action_applied')
    assert item_data.get('status') == ItemStatus.ON_LOAN
    loan_pid = actions[LoanAction.CHECKOUT].get('pid')

    # checkin the item at location B
    res, data = postdata(
        client, 'api_item.checkin',
        dict(item_pid=item2_lib_martigny.pid,
             pid=loan_pid,
             transaction_location_pid=loc_public_saxon.pid))
    assert res.status_code == 200
    item_data = data.get('metadata')
    item = Item.get_record_by_pid(item_data.get('pid'))
    assert item.get('status') == ItemStatus.IN_TRANSIT

    # checkin the item at location A
    res, data = postdata(
        client, 'api_item.automatic_checkin',
        dict(item_pid=item2_lib_martigny.pid,
             pid=loan_pid,
             transaction_location_pid=loc_public_martigny.pid))
    assert res.status_code == 200
    item_data = data.get('metadata')
    item = Item.get_record_by_pid(item2_lib_martigny.pid)
    assert item.get('status') == ItemStatus.ON_SHELF
Exemplo n.º 21
0
def item_lib_martigny_masked(app, document, item_lib_martigny_data,
                             loc_public_martigny, item_type_standard_martigny):
    """Create item of martigny library."""
    data = deepcopy(item_lib_martigny_data)
    data['pid'] = f'maked-{data["pid"]}'
    data['_masked'] = True
    item = Item.create(data=data,
                       delete_pid=False,
                       dbcommit=True,
                       reindex=True)
    flush_index(ItemsSearch.Meta.index)
    yield item
    item.delete(True, True, True)
Exemplo n.º 22
0
def test_regular_issue_creation_update_delete_api(
        client, holding_lib_martigny_w_patterns, loc_public_martigny,
        lib_martigny):
    """Test create, update and delete of a regular issue API."""
    holding = holding_lib_martigny_w_patterns
    issue_display, expected_date = holding._get_next_issue_display_text(
        holding.get('patterns'))
    issue = holding.receive_regular_issue(dbcommit=True, reindex=True)
    item = deepcopy(issue)
    item['issue']['status'] = ItemIssueStatus.DELETED
    issue.update(data=item, dbcommit=True, reindex=True)
    created_issue = Item.get_record_by_pid(issue.pid)
    assert created_issue.get('issue').get('status') == ItemIssueStatus.DELETED
    # Unable to delete a regular issue
    with pytest.raises(IlsRecordError.NotDeleted):
        created_issue.delete(dbcommit=True, delindex=True)

    # no errors when deleting an irregular issue
    pid = created_issue.pid
    created_issue.get('issue')['regular'] = False
    created_issue.delete(dbcommit=True, delindex=True)
    assert not Item.get_record_by_pid(pid)
Exemplo n.º 23
0
def create_minimal_resources(db, minimal_member_record,
                             minimal_location_record, minimal_item_record,
                             minimal_document_record):
    """Simple patron record."""
    member = MemberWithLocations.create(minimal_member_record, dbcommit=True)
    location = Location.create(minimal_location_record, dbcommit=True)
    member.add_location(location)
    doc = DocumentsWithItems.create(minimal_document_record, dbcommit=True)
    item = Item.create({})
    item.update(minimal_item_record, dbcommit=True)
    doc.add_item(item, dbcommit=True)
    db.session.commit()
    yield doc, item, member, location
Exemplo n.º 24
0
def test_checking_out_external_items_at_non_circ_library(
        client, librarian_martigny, lib_martigny, lib_martigny_bourg,
        patron_martigny, loc_public_martigny, loc_public_martigny_bourg,
        item_lib_martigny_bourg, circulation_policies, item_lib_martigny,
        librarian_martigny_bourg):
    """Test checkout of external items at non-circ library."""
    login_user_via_session(client, librarian_martigny_bourg.user)
    # A non-circulation library (has no pickup configured) and library hours is
    # well configured
    opening_hours = [
      {
        "day": "monday",
        "is_open": True,
        "times": [
          {
            "start_time": "07:00",
            "end_time": "19:00"
          }
        ]
      }
    ]
    lib_martigny_bourg['opening_hours'] = opening_hours
    lib_martigny_bourg.update(lib_martigny_bourg, dbcommit=True, reindex=True)
    # a librarian from the non-circulating library can checkout items from
    # another library into his library
    params = dict(
        item_pid=item_lib_martigny.pid,
        patron_pid=patron_martigny.pid,
        transaction_user_pid=librarian_martigny_bourg.pid,
        transaction_library_pid=lib_martigny_bourg.pid,
    )
    res, data = postdata(
        client,
        'api_item.checkout',
        params
    )
    assert res.status_code == 200
    # the checkin is possible at the non-circulating library and the item goes
    # directly to in-transit
    res, data = postdata(
        client,
        'api_item.checkin',
        dict(
            item_pid=item_lib_martigny.pid,
            transaction_library_pid=lib_martigny_bourg.pid,
            transaction_user_pid=librarian_martigny_bourg.pid,
        )
    )
    assert res.status_code == 200
    item = Item.get_record_by_pid(item_lib_martigny.pid)
    assert item.status == ItemStatus.IN_TRANSIT
Exemplo n.º 25
0
def test_get_links_to_me_with_fees(patron_transaction_overdue_saxon):
    """Test for number loans with fees."""
    pttr = patron_transaction_overdue_saxon
    loan = pttr.loan
    item = Item.get_record_by_pid(loan.item_pid)
    assert item.get_links_to_me() == {'fees': 1, 'loans': 1}
    assert item.get_links_to_me(get_pids=True) == {
        'fees': ['1'], 'loans': ['1']}

    pttr['status'] = 'closed'
    pttr['total_amount'] = 0
    pttr = pttr.update(pttr, reindex=True, dbcommit=True)
    assert item.get_links_to_me() == {'loans': 1}
    assert item.get_links_to_me(get_pids=True) == {'loans': ['1']}
Exemplo n.º 26
0
def test_holding_delete_after_item_edition(client, holding_lib_saxon,
                                           item_lib_saxon, holding_lib_fully):
    """Test automatic holding delete after item edition."""

    item_lib_saxon['location'] = \
        {'$ref': 'https://ils.rero.ch/api/locations/loc5'}

    item_lib_saxon.update(item_lib_saxon, dbcommit=True, reindex=True)
    flush_index(ItemsSearch.Meta.index)
    item = Item.get_record_by_pid(item_lib_saxon.pid)
    assert item.holding_pid == holding_lib_fully.pid

    holding = Holding.get_record_by_pid(holding_lib_saxon.pid)
    assert not holding
Exemplo n.º 27
0
def test_items_simple_checkout(client, librarian_martigny_no_email,
                               patron_martigny_no_email, loc_public_martigny,
                               item_type_standard_martigny, item_lib_martigny,
                               json_header, circulation_policies):
    """Test item checkout."""
    login_user_via_session(client, librarian_martigny_no_email.user)
    item = item_lib_martigny
    item_pid = item.pid
    patron_pid = patron_martigny_no_email.pid
    assert not item.is_loaned_to_patron(
        patron_martigny_no_email.get('barcode'))
    assert item.can_delete
    assert item.available

    # checkout
    res = client.post(
        url_for('api_item.checkout'),
        data=json.dumps(dict(item_pid=item_pid, patron_pid=patron_pid)),
        content_type='application/json',
    )
    assert res.status_code == 200
    data = get_json(res)
    item_data = data.get('metadata')
    actions = data.get('action_applied')
    assert item_data.get('status') == ItemStatus.ON_LOAN
    assert actions.get(LoanAction.CHECKOUT)
    loan_pid = actions[LoanAction.CHECKOUT].get('pid')
    item = Item.get_record_by_pid(item_pid)
    assert item.is_loaned_to_patron(patron_martigny_no_email.get('barcode'))
    assert not item.available
    assert not item.can_delete

    # get loans for the patron
    res = client.get(url_for('api_item.loans', patron_pid=patron_pid))
    assert res.status_code == 200
    data = get_json(res)
    assert data.get('hits').get('total') == 1

    # checkin
    res = client.post(
        url_for('api_item.checkin'),
        data=json.dumps(dict(item_pid=item_pid, pid=loan_pid)),
        content_type='application/json',
    )
    assert res.status_code == 200
    data = get_json(res)
    item_data = data.get('metadata')
    actions = data.get('action_applied')
    assert item_data.get('status') == ItemStatus.ON_SHELF
    assert actions.get(LoanAction.CHECKIN)
Exemplo n.º 28
0
def test_clear_obsolete_temporary_item_type(item_lib_martigny,
                                            item_type_on_site_martigny):
    """test task clear_obsolete_temporary_item_type"""
    item = item_lib_martigny
    end_date = datetime.now() + timedelta(days=2)
    item['temporary_item_type'] = {
        '$ref': get_ref_for_pid('itty', item_type_on_site_martigny.pid),
        'end_date': end_date.strftime('%Y-%m-%d')
    }
    item.update(item, dbcommit=True, reindex=True)
    assert item.item_type_circulation_category_pid == \
        item_type_on_site_martigny.pid

    over_4_days = datetime.now() + timedelta(days=4)
    with freeze_time(over_4_days.strftime('%Y-%m-%d')):
        items = Item.get_items_with_obsolete_temporary_item_type()
        assert len(list(items)) == 1
        # run the tasks
        clean_obsolete_temporary_item_types()
        # check after task was ran
        items = Item.get_items_with_obsolete_temporary_item_type()
        assert len(list(items)) == 0
        assert item.item_type_circulation_category_pid == item.item_type_pid
Exemplo n.º 29
0
def test_item_different_actions(client, librarian_martigny_no_email,
                                lib_martigny, patron_martigny_no_email,
                                loc_public_martigny, item_lib_martigny,
                                json_header, item_type_standard_martigny,
                                circ_policy_short_martigny,
                                patron_type_children_martigny, lib_saxon,
                                loc_public_saxon, librarian_saxon_no_email):
    """Test item possible actions other scenarios."""
    login_user_via_session(client, librarian_martigny_no_email.user)
    circ_policy_origin = deepcopy(circ_policy_short_martigny)
    circ_policy = circ_policy_short_martigny

    patron_pid = patron_martigny_no_email.pid
    res = client.get(
        url_for('api_item.item',
                item_barcode='does not exist',
                patron_pid=patron_pid))
    assert res.status_code == 404

    res, data = postdata(
        client, 'api_item.checkout',
        dict(item_pid=item_lib_martigny.pid, patron_pid=patron_pid))
    assert res.status_code == 200
    loan_pid = data.get('action_applied')[LoanAction.CHECKOUT].get('pid')

    record = Item.get_record_by_pid(item_lib_martigny.pid)

    res, _ = postdata(
        client,
        'api_item.checkin',
        dict(item_pid='does not exist',
             pid=loan_pid,
             transaction_location_pid=loc_public_saxon.pid),
    )
    assert res.status_code == 404

    res, data = postdata(
        client,
        'api_item.checkin',
        dict(item_pid=item_lib_martigny.pid,
             pid=loan_pid,
             transaction_location_pid=loc_public_saxon.pid),
    )
    assert res.status_code == 200
    loan_pid = data.get('action_applied')[LoanAction.CHECKIN].get('pid')

    data = {'pid': loan_pid}
    params, actions = item_lib_martigny.prior_checkout_actions(data)
    assert 'cancel' in actions
Exemplo n.º 30
0
def test_automatic_item_creation_no_serials(client, json_header,
                                            holding_lib_martigny_w_patterns,
                                            item_lib_martigny_data,
                                            librarian_martigny_no_email):
    """Test automatically created items are not attached to serials."""
    login_user_via_session(client, librarian_martigny_no_email.user)
    post_url = 'invenio_records_rest.item_list'
    res, _ = postdata(client, post_url, item_lib_martigny_data)
    assert res.status_code == 201
    item = Item.get_record_by_pid(item_lib_martigny_data.get('pid'))
    holding = Holding.get_record_by_pid(item.holding_pid)
    assert holding.pid != holding_lib_martigny_w_patterns.pid
    assert holding.location_pid == holding_lib_martigny_w_patterns.location_pid
    assert holding.get('circulation_category') == \
        holding_lib_martigny_w_patterns.get('circulation_category')