mirror of
https://github.com/pretix/pretix.git
synced 2026-05-14 16:44:06 +00:00
Rename {pretix,external}_pk to {pretix,external}_id_field
This commit is contained in:
@@ -95,8 +95,8 @@ class OrderSyncLink(models.Model):
|
||||
OrderPosition, on_delete=models.CASCADE, related_name="synced_objects", blank=True, null=True,
|
||||
)
|
||||
external_object_type = models.CharField(blank=False, null=False, max_length=128)
|
||||
external_pk_name = models.CharField(blank=False, null=False, max_length=128)
|
||||
external_pk_value = models.CharField(blank=False, null=False, max_length=128)
|
||||
external_id_field = models.CharField(blank=False, null=False, max_length=128)
|
||||
id_value = models.CharField(blank=False, null=False, max_length=128)
|
||||
external_link_href = models.CharField(blank=True, null=True, max_length=255)
|
||||
external_link_display_name = models.CharField(blank=True, null=True, max_length=255)
|
||||
timestamp = models.DateTimeField(blank=False, null=False, auto_now_add=True)
|
||||
@@ -147,7 +147,7 @@ class SyncConfigError(Exception):
|
||||
self.full_message = full_message
|
||||
|
||||
|
||||
StaticMapping = namedtuple('StaticMapping', ('pk', 'pretix_model', 'external_object_type', 'pretix_pk', 'external_pk', 'property_mapping'))
|
||||
StaticMapping = namedtuple('StaticMapping', ('pk', 'pretix_model', 'external_object_type', 'pretix_id_field', 'external_id_field', 'property_mapping'))
|
||||
|
||||
|
||||
class OutboundSyncProvider:
|
||||
@@ -167,17 +167,17 @@ class OutboundSyncProvider:
|
||||
def display_name(cls):
|
||||
return str(cls.identifier)
|
||||
|
||||
"""
|
||||
Adds an order to the sync queue. May only be called on derived classes which define an "identifier" attribute.
|
||||
|
||||
Should be called in the appropriate signal receivers, e.g.:
|
||||
|
||||
@receiver(order_placed, dispatch_uid="mysync_order_placed")
|
||||
def on_order_placed(sender, order, **kwargs):
|
||||
MySyncProvider.enqueue_order(order, "order_placed")
|
||||
"""
|
||||
@classmethod
|
||||
def enqueue_order(cls, order, triggered_by, not_before=None):
|
||||
"""
|
||||
Adds an order to the sync queue. May only be called on derived classes which define an "identifier" attribute.
|
||||
|
||||
Should be called in the appropriate signal receivers, e.g.::
|
||||
|
||||
@receiver(order_placed, dispatch_uid="mysync_order_placed")
|
||||
def on_order_placed(sender, order, **kwargs):
|
||||
MySyncProvider.enqueue_order(order, "order_placed")
|
||||
"""
|
||||
if not hasattr(cls, 'identifier'):
|
||||
raise TypeError('Call this method on a derived class that defines an "identifier" attribute.')
|
||||
OrderSyncQueue.objects.create(
|
||||
@@ -198,37 +198,37 @@ class OutboundSyncProvider:
|
||||
info = cls.get_external_link_info(event, external_link_href, external_link_display_name)
|
||||
return make_link(info, '{val}')
|
||||
|
||||
"""
|
||||
Optionally override to configure a different retry backoff behavior
|
||||
"""
|
||||
def next_retry_date(self, sq):
|
||||
"""
|
||||
Optionally override to configure a different retry backoff behavior
|
||||
"""
|
||||
return now() + timedelta(hours=1)
|
||||
|
||||
"""
|
||||
Optionally override this method to exclude certain orders from sync by returning False
|
||||
"""
|
||||
def order_valid_for_sync(self, order):
|
||||
"""
|
||||
Optionally override this method to exclude certain orders from sync by returning False
|
||||
"""
|
||||
return True
|
||||
|
||||
"""
|
||||
Implementations must override this property to provide the data mappings as a list of objects.
|
||||
|
||||
They can return instances of the StaticMapping namedtuple defined above, or create their own
|
||||
class (e.g. a Django model).
|
||||
|
||||
The returned objects must have at least the following properties:
|
||||
- pk: unique identifier
|
||||
- pretix_model: which pretix model to use as data source in this mapping. possible values are
|
||||
the keys of sourcefields.AVAILABLE_MODELS
|
||||
- external_object_type: destination object type in the target system. opaque string of maximum 128 characters.
|
||||
- pretix_pk: which pretix data field should be used to identify the mapped object. any
|
||||
DataFieldInfo.key returned by sourcefields.get_data_fields for the combination of
|
||||
Event and pretix_model
|
||||
- external_pk: destination identifier field in the target system
|
||||
- property_mapping: mapping configuration as generated by PropertyMappingFormSet.to_property_mapping_json()
|
||||
"""
|
||||
@property
|
||||
def mappings(self):
|
||||
"""
|
||||
Implementations must override this property to provide the data mappings as a list of objects.
|
||||
|
||||
They can return instances of the StaticMapping namedtuple defined above, or create their own
|
||||
class (e.g. a Django model).
|
||||
|
||||
:return: The returned objects must have at least the following properties:
|
||||
|
||||
- `pk`: Unique identifier
|
||||
- `pretix_model`: Which pretix model to use as data source in this mapping. Possible values are
|
||||
the keys of ``sourcefields.AVAILABLE_MODELS``
|
||||
- `external_object_type`: Destination object type in the target system. opaque string of maximum 128 characters.
|
||||
- `pretix_id_field`: Which pretix data field should be used to identify the mapped object. Any ``DataFieldInfo.key``
|
||||
returned by ``sourcefields.get_data_fields()`` for the combination of ``Event`` and ``pretix_model``.
|
||||
- `external_id_field`: Destination identifier field in the target system.
|
||||
- `property_mapping`: Mapping configuration as generated by ``PropertyMappingFormSet.to_property_mapping_json()``.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def sync_queued_orders(self, queued_orders):
|
||||
@@ -304,46 +304,52 @@ class OutboundSyncProvider:
|
||||
for m in property_mapping
|
||||
]
|
||||
|
||||
"""
|
||||
This method is called for each object that needs to be created/updated in the external system -- which these are is
|
||||
determined by the implementation of the `mapping` property.
|
||||
|
||||
:param pk_field: Identifier field in the target system as provided in mapping.external_pk
|
||||
:param pk_value: Identifier contents as retrieved from the property specified by mapping.pretix_pk of the model
|
||||
specified by mapping.pretix_model
|
||||
:param properties: All properties defined in mapping.property_mapping, as list of three-tuples
|
||||
(external_field, value, overwrite)
|
||||
:param inputs: All pretix model instances from which data can be retrieved for this mapping
|
||||
:param mapping: The mapping object as returned by self.mappings
|
||||
:param mapped_objects: Information about objects that were synced in the same sync run, by mapping definitions
|
||||
*before* the current one in order of self.mappings.
|
||||
Type is a dictionary {mapping.pk: [list of return values of this method]}
|
||||
Useful to create associations between objects in the target system.
|
||||
:return: {
|
||||
"object_type": mapping.external_object_type,
|
||||
"pk_field": pk_field,
|
||||
"pk_value": pk_value,
|
||||
"external_link_href": "https://external-system.example.com/backend/link/to/contact/123/",
|
||||
"external_link_display_name": "Contact #123 - Jane Doe",
|
||||
"...optionally further values you need in mapped_objects for association": 123456789,
|
||||
}
|
||||
|
||||
This method needs to be idempotent, i.e. calling it multiple times with the same input values should create
|
||||
only a single object in the target system.
|
||||
|
||||
Subsequent calls with the same mapping and pk_value should update the existing object, instead of creating a new one.
|
||||
In a SQL database, you might use an "INSERT OR UPDATE" or "UPSERT" statement; many REST APIs provide an equivalent API call.
|
||||
"""
|
||||
def sync_object_with_properties(
|
||||
self,
|
||||
pk_field,
|
||||
pk_value,
|
||||
external_id_field,
|
||||
id_value,
|
||||
properties: list,
|
||||
inputs: dict,
|
||||
mapping,
|
||||
mapped_objects: dict,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
This method is called for each object that needs to be created/updated in the external system -- which these are is
|
||||
determined by the implementation of the `mapping` property.
|
||||
|
||||
:param external_id_field: Identifier field in the external system as provided in mapping.external_identifier
|
||||
:param id_value: Identifier contents as retrieved from the property specified by mapping.pretix_identifier of the model
|
||||
specified by mapping.pretix_model
|
||||
:param properties: All properties defined in mapping.property_mapping, as list of three-tuples
|
||||
(external_field, value, overwrite)
|
||||
:param inputs: All pretix model instances from which data can be retrieved for this mapping
|
||||
:param mapping: The mapping object as returned by self.mappings
|
||||
:param mapped_objects: Information about objects that were synced in the same sync run, by mapping definitions
|
||||
*before* the current one in order of self.mappings.
|
||||
Type is a dictionary {mapping.pk: [list of return values of this method]}
|
||||
Useful to create associations between objects in the target system.
|
||||
|
||||
Example code to create return value::
|
||||
|
||||
return {
|
||||
# required:
|
||||
"object_type": mapping.external_object_type,
|
||||
"external_id_field": external_id_field,
|
||||
"id_value": id_value,
|
||||
|
||||
# optional:
|
||||
"external_link_href": "https://external-system.example.com/backend/link/to/contact/123/",
|
||||
"external_link_display_name": "Contact #123 - Jane Doe",
|
||||
"...optionally further values you need in mapped_objects for association": 123456789,
|
||||
}
|
||||
|
||||
This method needs to be idempotent, i.e. calling it multiple times with the same input values should create
|
||||
only a single object in the target system.
|
||||
|
||||
Subsequent calls with the same mapping and pk_value should update the existing object, instead of creating a new one.
|
||||
In a SQL database, you might use an "INSERT OR UPDATE" or "UPSERT" statement; many REST APIs provide an equivalent API call.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def sync_object(
|
||||
@@ -356,13 +362,13 @@ class OutboundSyncProvider:
|
||||
properties = self.get_properties(inputs, mapping.property_mapping)
|
||||
logger.debug("Properties: %r", properties)
|
||||
|
||||
pk_value = self.get_field_value(inputs, {"pretix_field": mapping.pretix_pk})
|
||||
if not pk_value:
|
||||
id_value = self.get_field_value(inputs, {"pretix_field": mapping.pretix_id_field})
|
||||
if not id_value:
|
||||
return None
|
||||
|
||||
info = self.sync_object_with_properties(
|
||||
pk_field=mapping.external_pk,
|
||||
pk_value=pk_value,
|
||||
external_id_field=mapping.external_id_field,
|
||||
id_value=id_value,
|
||||
properties=properties,
|
||||
inputs=inputs,
|
||||
mapping=mapping,
|
||||
@@ -371,8 +377,8 @@ class OutboundSyncProvider:
|
||||
OrderSyncLink.objects.create(
|
||||
order=inputs.get(ORDER), order_position=inputs.get(ORDER_POSITION), sync_provider=self.identifier,
|
||||
external_object_type=info.get('object_type'),
|
||||
external_pk_name=info.get('pk_field'),
|
||||
external_pk_value=info.get('pk_value'),
|
||||
external_id_field=info.get('external_id_field'),
|
||||
id_value=info.get('id_value'),
|
||||
external_link_href=info.get('external_link_href'),
|
||||
external_link_display_name=info.get('external_link_display_name'),
|
||||
)
|
||||
@@ -411,15 +417,15 @@ class OutboundSyncProvider:
|
||||
self.finalize_sync_order(order)
|
||||
return mapped_objects
|
||||
|
||||
"""
|
||||
Called after sync_object has been called successfully for all objects of a specific order. Can be used for saving
|
||||
bulk information per order.
|
||||
"""
|
||||
def finalize_sync_order(self, order):
|
||||
"""
|
||||
Called after sync_object has been called successfully for all objects of a specific order. Can be used for saving
|
||||
bulk information per order.
|
||||
"""
|
||||
pass
|
||||
|
||||
"""
|
||||
Called after all orders of an event have been synced. Can be used for clean-up tasks (closing a session etc).
|
||||
"""
|
||||
def close(self):
|
||||
"""
|
||||
Called after all orders of an event have been synced. Can be used for clean-up tasks (closing a session etc).
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -33,27 +33,27 @@ def assign_properties(
|
||||
):
|
||||
out = {}
|
||||
|
||||
for k, v, mode in new_values:
|
||||
for field_name, v, mode in new_values:
|
||||
if mode == MODE_OVERWRITE:
|
||||
out[k] = v
|
||||
out[field_name] = v
|
||||
continue
|
||||
elif mode == MODE_SET_IF_NEW and not is_new:
|
||||
continue
|
||||
if not v:
|
||||
continue
|
||||
|
||||
current_value = old_values.get(k, out.get(k, ""))
|
||||
current_value = old_values.get(field_name, out.get(field_name, ""))
|
||||
if mode in (MODE_SET_IF_EMPTY, MODE_SET_IF_NEW):
|
||||
if not current_value:
|
||||
out[k] = v
|
||||
out[field_name] = v
|
||||
elif mode == MODE_APPEND_LIST:
|
||||
_add_to_list(out, k, current_value, v, list_sep)
|
||||
_add_to_list(out, field_name, current_value, v, list_sep)
|
||||
else:
|
||||
raise SyncConfigError(["Invalid update mode " + mode])
|
||||
return out
|
||||
|
||||
|
||||
def _add_to_list(out, key, current_value, new_item, list_sep):
|
||||
def _add_to_list(out, field_name, current_value, new_item, list_sep):
|
||||
new_item = str(new_item)
|
||||
if list_sep is not None:
|
||||
new_item = new_item.replace(list_sep, "")
|
||||
@@ -64,4 +64,4 @@ def _add_to_list(out, key, current_value, new_item, list_sep):
|
||||
new_list = current_value + [new_item]
|
||||
if list_sep is not None:
|
||||
new_list = list_sep.join(new_list)
|
||||
out[key] = new_list
|
||||
out[field_name] = new_list
|
||||
|
||||
@@ -214,7 +214,7 @@ class SimpleOrderSync(OutboundSyncProvider):
|
||||
StaticMapping(
|
||||
pk=1,
|
||||
pretix_model='Order', external_object_type='ticketorders',
|
||||
pretix_pk='event_order_code', external_pk='ordernumber',
|
||||
pretix_id_field='event_order_code', external_id_field='ordernumber',
|
||||
property_mapping=json.dumps([
|
||||
{
|
||||
"pretix_field": "email",
|
||||
@@ -309,7 +309,7 @@ def test_simple_order_sync(event):
|
||||
|
||||
|
||||
StaticMappingWithAssociations = namedtuple('StaticMappingWithAssociations', (
|
||||
'pk', 'pretix_model', 'external_object_type', 'pretix_pk', 'external_pk', 'property_mapping', 'association_mapping'
|
||||
'pk', 'pretix_model', 'external_object_type', 'pretix_id_field', 'external_id_field', 'property_mapping', 'association_mapping'
|
||||
))
|
||||
AssociationMapping = namedtuple('AssociationMapping', (
|
||||
'via_mapping_pk'
|
||||
@@ -326,7 +326,7 @@ class OrderAndTicketAssociationSync(OutboundSyncProvider):
|
||||
StaticMappingWithAssociations(
|
||||
pk=1,
|
||||
pretix_model='OrderPosition', external_object_type='tickets',
|
||||
pretix_pk='ticket_id', external_pk='ticketnumber',
|
||||
pretix_id_field='ticket_id', external_id_field='ticketnumber',
|
||||
property_mapping=json.dumps([
|
||||
{
|
||||
"pretix_field": "ticket_price",
|
||||
@@ -379,7 +379,7 @@ class OrderAndTicketAssociationSync(OutboundSyncProvider):
|
||||
StaticMappingWithAssociations(
|
||||
pk=2,
|
||||
pretix_model='Order', external_object_type='ticketorders',
|
||||
pretix_pk='event_order_code', external_pk='ordernumber',
|
||||
pretix_id_field='event_order_code', external_id_field='ordernumber',
|
||||
property_mapping=json.dumps([
|
||||
{
|
||||
"pretix_field": "email",
|
||||
|
||||
Reference in New Issue
Block a user