Пример #1
0
    def add_acquisition(self, data, buyers, sellers, houses, non_auctions,
                        buy_sell_modifiers, transaction, transaction_types):
        '''Add modeling of an acquisition as a transfer of title from the seller to the buyer'''
        hmo = get_crom_object(data)
        parent = data['parent_data']
        # 	transaction = parent['transaction']
        prices = parent.get('price')
        ask_price = parent.get('ask_price')
        auction_data = parent['auction_of_lot']
        lot_object_key = object_key(auction_data)
        cno, lno, date = lot_object_key
        sale_type = non_auctions.get(cno, 'Auction')
        data['buyer'] = buyers
        data['seller'] = sellers

        acq_label = None
        try:
            object_label = f'“{hmo._label}”'
            acq_label = f'Acquisition of {cno} {lno} ({date}): {object_label}'
        except AttributeError:
            object_label = '(object)'
            acq_label = f'Acquisition of {cno} {lno} ({date})'

    # 	if not prices:
    # 		print(f'*** No price data found for {transaction} transaction')

        tx_data = parent.get('_prov_entry_data')
        current_tx = get_crom_object(tx_data)

        # The payment URIs are just the provenance entry URI with a suffix. In any case
        # where the provenance entry is merged, the payment should be merged as well.
        sell_payment_id = current_tx.id + '-Pay-to-Seller'
        buy_payment_id = current_tx.id + '-Pay-from-Buyer'

        # The acquisition URI is just the provenance entry URI with a suffix. In any case
        # where the provenance entry is merged, the acquisition should be merged as well.
        acq_id = hmo.id + '-Acq'
        acq = model.Acquisition(ident=acq_id, label=acq_label)
        acq.transferred_title_of = hmo

        self.attach_source_catalog(data, acq, buyers + sellers)

        multi = tx_data.get('multi_lot_tx')
        paym_label = f'multiple lots {multi}' if multi else object_label
        # 		paym = model.Payment(ident=payment_id, label=f'Payment for {paym_label}')
        payments = {
            'buy':
            model.Payment(ident=buy_payment_id,
                          label=f'Payment from buyer for {paym_label}'),
            'sell':
            model.Payment(ident=sell_payment_id,
                          label=f'Payment to seller for {paym_label}'),
        }
        for house_data in houses:
            house = get_crom_object(house_data)
            payments['buy'].paid_to = house
            payments['sell'].paid_from = house
        payments_used = set()

        THROUGH = CaseFoldingSet(buy_sell_modifiers['through'])
        FOR = CaseFoldingSet(buy_sell_modifiers['for'])

        single_seller = (len(sellers) == 1)
        single_buyer = (len(buyers) == 1)

        pi = self.helper.person_identity

        def is_or_anon(data: dict):
            mods = self.modifiers(data, 'auth_mod_a')
            return 'or anonymous' in mods

        or_anon_records = [is_or_anon(a) for a in sellers]
        uncertain_attribution = any(or_anon_records)

        for seq_no, seller_data in enumerate(sellers):
            seller = get_crom_object(seller_data)
            mod = self.modifiers(seller_data, 'auth_mod_a')
            attrib_assignment_classes = [model.AttributeAssignment]
            if uncertain_attribution:
                attrib_assignment_classes.append(vocab.PossibleAssignment)

            if THROUGH.intersects(mod):
                acq.carried_out_by = seller
                payments['sell'].carried_out_by = seller
                payments_used.add('sell')
            elif FOR.intersects(mod):
                acq.transferred_title_from = seller
                payments['sell'].paid_to = seller
                payments_used.add('sell')
            elif uncertain_attribution:  # this is true if ANY of the sellers have an 'or anonymous' modifier
                # The assignment URIs are just the acquisition URI with a suffix.
                # In any case where the acquisition is merged, the assignments should be
                # merged as well.
                acq_assignment_uri = acq.id + f'-seller-assignment-{seq_no}'
                paym_assignment_uri = payments[
                    'sell'].id + f'-seller-assignment-{seq_no}'

                acq_assignment_label = f'Uncertain seller as previous title holder in acquisition'
                acq_assignment = vocab.PossibleAssignment(
                    ident=acq_assignment_uri, label=acq_assignment_label)
                acq_assignment.referred_to_by = vocab.Note(
                    ident='', content=acq_assignment_label)
                acq_assignment.assigned_property = 'transferred_title_from'
                acq_assignment.assigned = seller
                acq.attributed_by = acq_assignment

                paym_assignment_label = f'Uncertain seller as recipient of payment'
                paym_assignment = vocab.PossibleAssignment(
                    ident=paym_assignment_uri, label=paym_assignment_label)
                paym_assignment.referred_to_by = vocab.Note(
                    ident='', content=paym_assignment_label)
                paym_assignment.assigned_property = 'paid_to'
                paym_assignment.assigned = seller
                payments['sell'].attributed_by = paym_assignment
                payments_used.add('sell')
            else:
                # covers non-modified
                # 				acq.carried_out_by = seller
                acq.transferred_title_from = seller
                # 				payments['sell'].carried_out_by = seller
                payments['sell'].paid_to = seller
                payments_used.add('sell')

        for buyer_data in buyers:
            buyer = get_crom_object(buyer_data)
            mod = self.modifiers(buyer_data, 'auth_mod_a')

            if 'or' in mod:
                # or/or others/or another
                mod_non_auth = buyer_data.get('auth_mod')
                if mod_non_auth:
                    acq.referred_to_by = vocab.Note(ident='',
                                                    label=f'Buyer modifier',
                                                    content=mod_non_auth)
                warnings.warn(f'Handle buyer modifier: {mod}'
                              )  # TODO: some way to model this uncertainty?

            if THROUGH.intersects(mod):
                acq.carried_out_by = buyer
                payments['buy'].carried_out_by = buyer
                payments_used.add('buy')
            elif FOR.intersects(mod):
                acq.transferred_title_to = buyer
                payments['buy'].paid_from = buyer
                payments_used.add('buy')
            else:
                # covers FOR modifiers and non-modified
                # 				acq.carried_out_by = buyer
                acq.transferred_title_to = buyer
                payments['buy'].paid_from = buyer
                # 				payments['buy'].carried_out_by = buyer
                payments_used.add('buy')

        if prices:
            amnt = get_crom_object(prices[0])
            for paym in payments.values():
                self.set_possible_attribute(paym, 'paid_amount', prices[0])
                for price in prices[1:]:
                    amnt = get_crom_object(price)
                    content = self._price_note(price)
                    if content:
                        paym.referred_to_by = vocab.PriceStatement(
                            ident='', content=content)
        elif ask_price:
            # for non-auction sales, the ask price is the amount paid for the acquisition
            for paym in payments.values():
                self.set_possible_attribute(paym, 'paid_amount', ask_price)

        ts = tx_data.get('_date')
        if ts:
            acq.timespan = ts

        current_tx.part = acq
        for pay_key in payments_used:
            paym = payments[pay_key]
            current_tx.part = paym
# 		current_tx.part = paym
        data['_prov_entries'] += [add_crom_data(data={}, what=current_tx)]
        # 	lot_uid, lot_uri = helper.shared_lot_number_ids(cno, lno)
        # TODO: `annotation` here is from add_physical_catalog_objects
        # 	paym.referred_to_by = annotation

        data['_acquisition'] = add_crom_data(data={'uri': acq_id}, what=acq)

        final_owner_data = data.get('_final_org', [])
        if final_owner_data:
            data['_organizations'].append(final_owner_data)
            final_owner = get_crom_object(final_owner_data)
            tx_label_args = tuple([
                self.helper, sale_type, 'Sold',
                'leading to the currently known location of'
            ] + list(lot_object_key))
            tx, acq = self.final_owner_prov_entry(tx_label_args, final_owner,
                                                  current_tx, hmo, ts)
            note = final_owner_data.get('note')
            if note:
                acq.referred_to_by = vocab.Note(ident='', content=note)
            data['_prov_entries'].append(add_crom_data(data={}, what=tx))

        self.add_prev_post_owners(data, hmo, tx_data, sale_type,
                                  lot_object_key, ts)
        yield data, current_tx
Пример #2
0
    def related_procurement(self,
                            hmo,
                            tx_label_args,
                            current_tx=None,
                            current_ts=None,
                            buyer=None,
                            seller=None,
                            previous=False,
                            ident=None,
                            make_label=None):
        '''
		Returns a new `vocab.ProvenanceEntry` object (and related acquisition) that is temporally
		related to the supplied procurement and associated data. The new procurement is for
		the given object, and has the given buyer and seller (both optional).

		If the `previous` flag is `True`, the new procurement is occurs before `current_tx`,
		and if the timespan `current_ts` is given, has temporal data to that effect. If
		`previous` is `False`, this relationship is reversed.
		
		The `make_label` argument, if supplied, is used as a function to generate the
		label for the provenance entry. Its arguments (generated in `handle_prev_post_owner`)
		are:
		
		  * helper: the helper object for the current pipeline
		  * sale_type: the sale type passed to `handle_prev_post_owner` (e.g. "Auction")
		  * transaction: the transaction type being handled (e.g. "Sold")
		  * rel: a string describing the relationship between this provenance entry and the object (e.g. "leading to the previous ownership of")
		  * N trailing arguments used that are the contents of the `lot_object_key` tuple passed to `handle_prev_post_owner`
		'''
        def _make_label_default(helper, sale_type, transaction, rel, *args):
            strs = [str(x) for x in args]
            return ', '.join(strs)

        if make_label is None:
            make_label = _make_label_default

        tx = vocab.ProvenanceEntry(ident=ident)
        tx_label = make_label(*tx_label_args)
        tx._label = tx_label
        tx.identified_by = model.Name(ident='', content=tx_label)

        if current_tx:
            if previous:
                tx.ends_before_the_start_of = current_tx
            else:
                tx.starts_after_the_end_of = current_tx
        modifier_label = 'Previous' if previous else 'Subsequent'
        try:
            pacq = model.Acquisition(
                ident='',
                label=f'{modifier_label} Acquisition of: “{hmo._label}”')
            pxfer = model.TransferOfCustody(
                ident='',
                label=f'{modifier_label} Transfer of Custody of: “{hmo._label}”'
            )
        except AttributeError:
            pacq = model.Acquisition(ident='',
                                     label=f'{modifier_label} Acquisition')
            pxfer = model.TransferOfCustody(
                ident='', label=f'{modifier_label} Transfer of Custody')
        pacq.transferred_title_of = hmo
        pxfer.transferred_custody_of = hmo
        if buyer:
            pacq.transferred_title_to = buyer
            pxfer.transferred_custody_to = buyer
        if seller:
            pacq.transferred_title_from = seller
            pxfer.transferred_custody_from = seller

        tx.part = pacq
        tx.part = pxfer
        if current_ts:
            if previous:
                pacq.timespan = timespan_before(current_ts)
            else:
                pacq.timespan = timespan_after(current_ts)
        return tx, pacq
Пример #3
0
    def add_acquisition(self, data, buyers, sellers, non_auctions,
                        buy_sell_modifiers, transaction, transaction_types):
        '''Add modeling of an acquisition as a transfer of title from the seller to the buyer'''
        hmo = get_crom_object(data)
        parent = data['parent_data']
        # 	transaction = parent['transaction']
        prices = parent.get('price')
        auction_data = parent['auction_of_lot']
        lot_object_key = object_key(auction_data)
        cno, lno, date = lot_object_key
        sale_type = non_auctions.get(cno, 'Auction')
        data['buyer'] = buyers
        data['seller'] = sellers

        acq_label = None
        try:
            object_label = f'“{hmo._label}”'
            acq_label = f'Acquisition of {cno} {lno} ({date}): {object_label}'
        except AttributeError:
            object_label = '(object)'
            acq_label = f'Acquisition of {cno} {lno} ({date})'

    # 	if not prices:
    # 		print(f'*** No price data found for {transaction} transaction')

        tx_data = parent['_prov_entry_data']
        current_tx = get_crom_object(tx_data)
        payment_id = current_tx.id + '-Pay'

        acq_id = hmo.id + '-Acq'
        acq = model.Acquisition(ident=acq_id, label=acq_label)
        acq.transferred_title_of = hmo

        self.attach_source_catalog(data, acq, buyers + sellers)

        multi = tx_data.get('multi_lot_tx')
        paym_label = f'multiple lots {multi}' if multi else object_label
        paym = model.Payment(ident=payment_id,
                             label=f'Payment for {paym_label}')

        THROUGH = set(buy_sell_modifiers['through'])
        FOR = set(buy_sell_modifiers['for'])

        single_seller = (len(sellers) == 1)
        single_buyer = (len(buyers) == 1)

        for seq_no, seller_data in enumerate(sellers):
            seller = get_crom_object(seller_data)
            mod = seller_data.get('auth_mod_a', '')

            if mod == 'or':
                mod_non_auth = seller_data.get('auth_mod')
                if mod_non_auth:
                    acq.referred_to_by = vocab.Note(ident='',
                                                    label=f'Seller modifier',
                                                    content=mod_non_auth)
                warnings.warn('Handle OR buyer modifier'
                              )  # TODO: some way to model this uncertainty?

            if mod in THROUGH:
                acq.carried_out_by = seller
                paym.carried_out_by = seller
            elif mod in FOR:
                acq.transferred_title_from = seller
                paym.paid_to = seller
            elif mod == 'or anonymous':
                acq_assignment = vocab.PossibleAssignment(
                    ident=acq.id + f'-seller-assignment-{seq_no}',
                    label=
                    f'Uncertain seller as previous title holder in acquisition'
                )
                acq_assignment.assigned_property = 'transferred_title_from'
                acq_assignment.assigned = seller
                acq.attributed_by = acq_assignment

                paym_assignment = vocab.PossibleAssignment(
                    ident=paym.id + f'-seller-assignment-{seq_no}',
                    label=f'Uncertain seller as recipient of payment')
                paym_assignment.assigned_property = 'paid_to'
                paym_assignment.assigned = seller
                paym.attributed_by = paym_assignment
            else:
                # covers non-modified
                acq.carried_out_by = seller
                acq.transferred_title_from = seller
                paym.carried_out_by = seller
                paym.paid_to = seller

        for buyer_data in buyers:
            buyer = get_crom_object(buyer_data)
            mod = buyer_data.get('auth_mod_a', '')

            if mod == 'or':
                # or/or others/or another
                mod_non_auth = buyer_data.get('auth_mod')
                if mod_non_auth:
                    acq.referred_to_by = vocab.Note(ident='',
                                                    label=f'Buyer modifier',
                                                    content=mod_non_auth)
                warnings.warn(f'Handle buyer modifier: {mod}'
                              )  # TODO: some way to model this uncertainty?

            if mod in THROUGH:
                acq.carried_out_by = buyer
                paym.carried_out_by = buyer
            else:
                # covers FOR modifiers and non-modified
                acq.transferred_title_to = buyer
                paym.paid_from = buyer

        if prices:
            amnt = get_crom_object(prices[0])
            paym.paid_amount = amnt
            for price in prices[1:]:
                amnt = get_crom_object(price)
                content = self._price_note(price)
                if content:
                    paym.referred_to_by = vocab.PriceStatement(ident='',
                                                               content=content)

        ts = tx_data.get('_date')
        if ts:
            acq.timespan = ts

        current_tx.part = acq
        current_tx.part = paym
        data['_prov_entries'] += [add_crom_data(data={}, what=current_tx)]
        # 	lot_uid, lot_uri = helper.shared_lot_number_ids(cno, lno)
        # TODO: `annotation` here is from add_physical_catalog_objects
        # 	paym.referred_to_by = annotation

        data['_acquisition'] = add_crom_data(data={'uri': acq_id}, what=acq)

        final_owner_data = data.get('_final_org', [])
        if final_owner_data:
            data['_organizations'].append(final_owner_data)
            final_owner = get_crom_object(final_owner_data)
            tx_label_args = tuple([
                self.helper, sale_type, 'Sold',
                'leading to the currently known location of'
            ] + list(lot_object_key))
            tx, acq = self.final_owner_procurement(tx_label_args, final_owner,
                                                   current_tx, hmo, ts)
            note = final_owner_data.get('note')
            if note:
                acq.referred_to_by = vocab.Note(ident='', content=note)
            data['_prov_entries'].append(add_crom_data(data={}, what=tx))

        post_own = data.get('post_owner', [])
        prev_own = data.get('prev_owner', [])
        prev_post_owner_records = [(post_own, False), (prev_own, True)]
        for owner_data, rev in prev_post_owner_records:
            if rev:
                rev_name = 'prev-owner'
            else:
                rev_name = 'post-owner'
            ignore_fields = {'own_so', 'own_auth_l', 'own_auth_d'}
            for seq_no, owner_record in enumerate(owner_data):
                record_id = f'{rev_name}-{seq_no+1}'
                if not any([
                        bool(owner_record.get(k))
                        for k in owner_record.keys() if k not in ignore_fields
                ]):
                    # some records seem to have metadata (source information, location, or notes)
                    # but no other fields set these should not constitute actual records of a prev/post owner.
                    continue
                self.handle_prev_post_owner(data,
                                            hmo,
                                            tx_data,
                                            sale_type,
                                            lot_object_key,
                                            owner_record,
                                            record_id,
                                            rev,
                                            ts,
                                            make_label=prov_entry_label)
        yield data, current_tx