airbyte-source-shopify 3.2.0.dev202602040050__tar.gz → 3.2.1.dev202601082335__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/PKG-INFO +1 -1
  2. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/pyproject.toml +1 -1
  3. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/product_variants.json +2 -10
  4. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/scopes.py +0 -1
  5. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/shopify_graphql/bulk/query.py +1 -146
  6. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/source.py +0 -5
  7. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/streams/streams.py +39 -19
  8. airbyte_source_shopify-3.2.0.dev202602040050/source_shopify/schemas/collection_products.json +0 -35
  9. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/README.md +0 -0
  10. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/__init__.py +0 -0
  11. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/auth.py +0 -0
  12. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/config_migrations.py +0 -0
  13. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/http_request.py +0 -0
  14. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/run.py +0 -0
  15. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/abandoned_checkouts.json +0 -0
  16. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/articles.json +0 -0
  17. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/balance_transactions.json +0 -0
  18. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/blogs.json +0 -0
  19. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/collections.json +0 -0
  20. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/collects.json +0 -0
  21. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/countries.json +0 -0
  22. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/custom_collections.json +0 -0
  23. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/customer_address.json +0 -0
  24. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/customer_journey_summary.json +0 -0
  25. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/customers.json +0 -0
  26. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/deleted_products.json +0 -0
  27. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/discount_codes.json +0 -0
  28. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/disputes.json +0 -0
  29. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/draft_orders.json +0 -0
  30. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/fulfillment_orders.json +0 -0
  31. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/fulfillments.json +0 -0
  32. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/inventory_items.json +0 -0
  33. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/inventory_levels.json +0 -0
  34. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/locations.json +0 -0
  35. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/metafield_articles.json +0 -0
  36. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/metafield_blogs.json +0 -0
  37. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/metafield_collections.json +0 -0
  38. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/metafield_customers.json +0 -0
  39. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/metafield_draft_orders.json +0 -0
  40. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/metafield_locations.json +0 -0
  41. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/metafield_orders.json +0 -0
  42. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/metafield_pages.json +0 -0
  43. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/metafield_product_images.json +0 -0
  44. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/metafield_product_variants.json +0 -0
  45. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/metafield_products.json +0 -0
  46. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/metafield_shops.json +0 -0
  47. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/metafield_smart_collections.json +0 -0
  48. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/order_agreements.json +0 -0
  49. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/order_refunds.json +0 -0
  50. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/order_risks.json +0 -0
  51. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/orders.json +0 -0
  52. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/pages.json +0 -0
  53. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/price_rules.json +0 -0
  54. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/product_images.json +0 -0
  55. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/products.json +0 -0
  56. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/profile_location_groups.json +0 -0
  57. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/shop.json +0 -0
  58. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/smart_collections.json +0 -0
  59. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/tender_transactions.json +0 -0
  60. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/schemas/transactions.json +0 -0
  61. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/shopify_graphql/bulk/__init__.py +0 -0
  62. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/shopify_graphql/bulk/exceptions.py +0 -0
  63. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/shopify_graphql/bulk/job.py +0 -0
  64. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/shopify_graphql/bulk/record.py +0 -0
  65. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/shopify_graphql/bulk/retry.py +0 -0
  66. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/shopify_graphql/bulk/status.py +0 -0
  67. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/shopify_graphql/bulk/tools.py +0 -0
  68. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/spec.json +0 -0
  69. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/streams/base_streams.py +0 -0
  70. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/transform.py +0 -0
  71. {airbyte_source_shopify-3.2.0.dev202602040050 → airbyte_source_shopify-3.2.1.dev202601082335}/source_shopify/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: airbyte-source-shopify
3
- Version: 3.2.0.dev202602040050
3
+ Version: 3.2.1.dev202601082335
4
4
  Summary: Source CDK implementation for Shopify.
5
5
  Home-page: https://airbyte.com
6
6
  License: ELv2
@@ -3,7 +3,7 @@ requires = [ "poetry-core>=1.0.0",]
3
3
  build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
- version = "3.2.0.dev.202602040050"
6
+ version = "3.2.1.dev.202601082335"
7
7
  name = "airbyte-source-shopify"
8
8
  description = "Source CDK implementation for Shopify."
9
9
  authors = [ "Airbyte <contact@airbyte.io>",]
@@ -52,20 +52,12 @@
52
52
  "items": {
53
53
  "type": ["null", "object"],
54
54
  "properties": {
55
- "id": {
56
- "description": "The unique identifier for the product option.",
57
- "type": ["null", "integer"]
58
- },
59
55
  "name": {
60
- "description": "The product option's name.",
56
+ "description": "The product options name.",
61
57
  "type": ["null", "string"]
62
58
  },
63
- "position": {
64
- "description": "The display order of the product option.",
65
- "type": ["null", "integer"]
66
- },
67
59
  "value": {
68
- "description": "The product option's value.",
60
+ "description": "The product options value.",
69
61
  "type": ["null", "string"]
70
62
  },
71
63
  "option_value": {
@@ -44,7 +44,6 @@ SCOPES_MAPPING: Mapping[str, set[str]] = {
44
44
  "MetafieldProductVariants": ("read_products",),
45
45
  "CustomCollections": ("read_products",),
46
46
  "Collects": ("read_products",),
47
- "CollectionProducts": ("read_products",),
48
47
  "ProductVariants": ("read_products", "read_inventory"),
49
48
  "MetafieldCollections": ("read_products",),
50
49
  "SmartCollections": ("read_products",),
@@ -952,114 +952,6 @@ class Collection(ShopifyBulkQuery):
952
952
  yield record
953
953
 
954
954
 
955
- class CollectionProduct(ShopifyBulkQuery):
956
- """
957
- Returns the products associated with each collection, including both custom collections
958
- and smart collections. This provides all product<>collection associations, not just
959
- manually associated products (which is what the Collects REST API provides).
960
-
961
- {
962
- collections(query: "updated_at:>='2023-02-07T00:00:00+00:00' AND updated_at:<='2023-12-04T00:00:00+00:00'", sortKey: UPDATED_AT) {
963
- edges {
964
- node {
965
- __typename
966
- id
967
- handle
968
- updatedAt
969
- products {
970
- edges {
971
- node {
972
- __typename
973
- id
974
- }
975
- }
976
- }
977
- }
978
- }
979
- }
980
- }
981
- """
982
-
983
- query_name = "collections"
984
- sort_key = "UPDATED_AT"
985
-
986
- products_fields: List[Field] = [
987
- Field(
988
- name="edges",
989
- fields=[
990
- Field(
991
- name="node",
992
- fields=[
993
- "__typename",
994
- "id",
995
- ],
996
- )
997
- ],
998
- )
999
- ]
1000
-
1001
- query_nodes: List[Field] = [
1002
- "__typename",
1003
- "id",
1004
- Field(name="handle"),
1005
- Field(name="updatedAt"),
1006
- Field(name="products", fields=products_fields),
1007
- ]
1008
-
1009
- record_composition = {
1010
- "new_record": "Collection",
1011
- "record_components": ["Product"],
1012
- }
1013
-
1014
- def _process_product_components(self, products: List[dict]) -> List[dict]:
1015
- """
1016
- Process product components to resolve IDs from string to int and preserve the original ID.
1017
-
1018
- Args:
1019
- products: List of product dictionaries with string IDs
1020
-
1021
- Returns:
1022
- List of processed product dictionaries with both id (int) and admin_graphql_api_id (str)
1023
- """
1024
- for product in products:
1025
- # Save the original string ID before resolving
1026
- product["admin_graphql_api_id"] = product.get("id")
1027
- # Resolve the ID from string to int
1028
- product["id"] = self.tools.resolve_str_id(product.get("id"))
1029
- return products
1030
-
1031
- def record_process_components(self, record: MutableMapping[str, Any]) -> Iterable[MutableMapping[str, Any]]:
1032
- """
1033
- Process collection records and yield one record per collection-product association.
1034
- """
1035
- record_components = record.get("record_components", {})
1036
- products = record_components.get("Product", [])
1037
-
1038
- # Get collection info - id is already resolved to int, admin_graphql_api_id has the string version
1039
- collection_id = record.get("id")
1040
- collection_admin_graphql_api_id = record.get("admin_graphql_api_id")
1041
- collection_handle = record.get("handle")
1042
- collection_updated_at = self.tools.from_iso8601_to_rfc3339(record, "updatedAt")
1043
-
1044
- if products:
1045
- # Process products to resolve their IDs
1046
- products = self._process_product_components(products)
1047
-
1048
- for product in products:
1049
- product_id = product.get("id")
1050
- product_admin_graphql_api_id = product.get("admin_graphql_api_id")
1051
-
1052
- yield {
1053
- "collection_id": collection_id,
1054
- "collection_admin_graphql_api_id": collection_admin_graphql_api_id,
1055
- "collection_handle": collection_handle,
1056
- "collection_updated_at": collection_updated_at,
1057
- "product_id": product_id,
1058
- "product_admin_graphql_api_id": product_admin_graphql_api_id,
1059
- "shop_url": self.config.get("shop"),
1060
- }
1061
-
1062
-
1063
955
  class CustomerAddresses(ShopifyBulkQuery):
1064
956
  """
1065
957
  {
@@ -2791,13 +2683,7 @@ class ProductVariant(ShopifyBulkQuery):
2791
2683
  Field(name="selectedOptions", alias="options", fields=option_fields),
2792
2684
  Field(name="image", fields=image_fields),
2793
2685
  Field(name="inventoryQuantity", alias="old_inventory_quantity"),
2794
- Field(
2795
- name="product",
2796
- fields=[
2797
- Field(name="id", alias="product_id"),
2798
- Field(name="options", alias="product_options", fields=["id", "name", "position"]),
2799
- ],
2800
- ),
2686
+ Field(name="product", fields=[Field(name="id", alias="product_id")]),
2801
2687
  Field(name="inventoryItem", fields=inventory_item_fields),
2802
2688
  ] + presentment_prices
2803
2689
 
@@ -2844,34 +2730,6 @@ class ProductVariant(ShopifyBulkQuery):
2844
2730
  entity = record.get(from_property, {})
2845
2731
  return self.tools.resolve_str_id(entity.get(id_field)) if entity else None
2846
2732
 
2847
- def _enrich_options_with_product_options(self, record: MutableMapping[str, Any]) -> None:
2848
- """
2849
- Enriches the variant's options with id and position from the product's options.
2850
- Matches options by name and adds the corresponding ProductOption id and position.
2851
- """
2852
- options = record.get("options") or []
2853
- product = record.get("product") or {}
2854
- product_options = product.get("product_options") or []
2855
-
2856
- # Build a lookup map from option name to ProductOption data
2857
- product_options_map = {}
2858
- for product_option in product_options:
2859
- if product_option:
2860
- name = product_option.get("name")
2861
- if name:
2862
- product_options_map[name] = {
2863
- "id": self.tools.resolve_str_id(product_option.get("id")),
2864
- "position": product_option.get("position"),
2865
- }
2866
-
2867
- # Enrich each option with id and position from the matching ProductOption
2868
- for option in options:
2869
- if option:
2870
- option_name = option.get("name")
2871
- if option_name and option_name in product_options_map:
2872
- option["id"] = product_options_map[option_name]["id"]
2873
- option["position"] = product_options_map[option_name]["position"]
2874
-
2875
2733
  def record_process_components(self, record: MutableMapping[str, Any]) -> Iterable[MutableMapping[str, Any]]:
2876
2734
  """
2877
2735
  Defines how to process collected components.
@@ -2884,9 +2742,6 @@ class ProductVariant(ShopifyBulkQuery):
2884
2742
  record["presentment_prices"] = self._process_presentment_prices(record_components.get("ProductVariantPricePair", []))
2885
2743
  record.pop("record_components")
2886
2744
 
2887
- # enrich options with id and position from product options (must be done before product is removed)
2888
- self._enrich_options_with_product_options(record)
2889
-
2890
2745
  # unnest mandatory fields from their placeholders
2891
2746
  record["product_id"] = self._unnest_and_resolve_id(record, "product", "product_id")
2892
2747
  record["inventory_item_id"] = self._unnest_and_resolve_id(record, "inventoryItem", "inventory_item_id")
@@ -11,7 +11,6 @@ from requests.exceptions import ConnectionError, RequestException, SSLError
11
11
  from airbyte_cdk.models import FailureType, SyncMode
12
12
  from airbyte_cdk.sources import AbstractSource
13
13
  from airbyte_cdk.sources.streams import Stream
14
- from airbyte_cdk.sources.streams.http.exceptions import BaseBackoffException
15
14
  from airbyte_cdk.utils import AirbyteTracedException
16
15
 
17
16
  from .auth import MissingAccessTokenError, ShopifyAuthenticator
@@ -21,7 +20,6 @@ from .streams.streams import (
21
20
  Articles,
22
21
  BalanceTransactions,
23
22
  Blogs,
24
- CollectionProducts,
25
23
  Collections,
26
24
  Collects,
27
25
  Countries,
@@ -110,8 +108,6 @@ class ConnectionCheckTest:
110
108
  return False, self.describe_error("index_error", shop_name, response)
111
109
  except MissingAccessTokenError:
112
110
  return False, self.describe_error("missing_token_error")
113
- except (BaseBackoffException, AirbyteTracedException) as error:
114
- return False, self.describe_error("connection_error", shop_name) or str(error)
115
111
 
116
112
  def get_shop_id(self) -> str:
117
113
  """
@@ -182,7 +178,6 @@ class SourceShopify(AbstractSource):
182
178
  Articles(config),
183
179
  BalanceTransactions(config),
184
180
  Blogs(config),
185
- CollectionProducts(config),
186
181
  Collections(config),
187
182
  Collects(config),
188
183
  CustomCollections(config),
@@ -10,7 +10,6 @@ from typing import Any, Iterable, Mapping, MutableMapping, Optional
10
10
  import requests
11
11
  from source_shopify.shopify_graphql.bulk.query import (
12
12
  Collection,
13
- CollectionProduct,
14
13
  CustomerAddresses,
15
14
  CustomerJourney,
16
15
  DeliveryProfile,
@@ -111,14 +110,50 @@ class Orders(IncrementalShopifyStreamWithDeletedEvents):
111
110
 
112
111
 
113
112
  class Disputes(IncrementalShopifyStream):
113
+ """
114
+ Disputes stream for Shopify Payments API.
115
+
116
+ Note: Uses 'initiated_at' as cursor field to ensure dispute status updates are captured
117
+ during incremental syncs. Previously used 'id' with 'since_id' filtering, which only
118
+ captured new disputes but missed updates to existing disputes (e.g., status changes
119
+ from 'needs_response' to 'won' or 'lost').
120
+
121
+ The Shopify API supports 'initiated_at' as a filter parameter, but only for exact date
122
+ matching (e.g., initiated_at=2013-05-03), not for range queries needed for incremental
123
+ sync. An alternative approach would be to iterate through dates and make multiple API
124
+ calls for each date, but this would be complex and inefficient. Instead, we leverage
125
+ the existing datetime-based client-side filtering that the connector already provides,
126
+ fetching all disputes ordered by 'initiated_at' and filtering them client-side.
127
+
128
+ API Reference: https://shopify.dev/docs/api/admin-rest/latest/resources/dispute
129
+ """
130
+
114
131
  data_field = "disputes"
115
- filter_field = "since_id"
116
- cursor_field = "id"
117
- order_field = "id"
132
+ cursor_field = "initiated_at"
133
+ order_field = "initiated_at"
118
134
 
119
135
  def path(self, **kwargs) -> str:
120
136
  return f"shopify_payments/{self.data_field}.json"
121
137
 
138
+ def request_params(
139
+ self, stream_state: Optional[Mapping[str, Any]] = None, next_page_token: Optional[Mapping[str, Any]] = None, **kwargs
140
+ ) -> MutableMapping[str, Any]:
141
+ """
142
+ Override to exclude server-side filtering since the API only supports exact date matching,
143
+ not the range queries needed for incremental sync.
144
+ """
145
+ params = ShopifyStream.request_params(self, stream_state=stream_state, next_page_token=next_page_token, **kwargs)
146
+ if not next_page_token:
147
+ params["order"] = f"{self.order_field} asc"
148
+ return params
149
+
150
+ def read_records(self, stream_state: Optional[Mapping[str, Any]] = None, **kwargs) -> Iterable[Mapping[str, Any]]:
151
+ """
152
+ Override to apply client-side filtering based on initiated_at cursor field.
153
+ """
154
+ records = super().read_records(stream_state=stream_state, **kwargs)
155
+ yield from self.filter_records_newer_than_state(stream_state=stream_state, records_slice=records)
156
+
122
157
 
123
158
  class MetafieldOrders(IncrementalShopifyGraphQlBulkStream):
124
159
  bulk_query: MetafieldOrder = MetafieldOrder
@@ -324,21 +359,6 @@ class MetafieldCollections(IncrementalShopifyGraphQlBulkStream):
324
359
  bulk_query: MetafieldCollection = MetafieldCollection
325
360
 
326
361
 
327
- class CollectionProducts(IncrementalShopifyGraphQlBulkStream):
328
- """
329
- Stream that returns all products associated with each collection, including both
330
- custom collections and smart collections. Unlike the Collects stream which only
331
- returns manually associated products, this stream returns all products that belong
332
- to a collection (including those matched by smart collection rules).
333
-
334
- https://shopify.dev/docs/api/admin-graphql/latest/objects/Collection#field-Collection.fields.products
335
- """
336
-
337
- bulk_query: CollectionProduct = CollectionProduct
338
- cursor_field = "collection_updated_at"
339
- primary_key = ["collection_id", "product_id"]
340
-
341
-
342
362
  class BalanceTransactions(IncrementalShopifyStream):
343
363
  """
344
364
  PaymentsTransactions stream does not support Incremental Refresh based on datetime fields, only `since_id` is supported:
@@ -1,35 +0,0 @@
1
- {
2
- "type": "object",
3
- "additionalProperties": true,
4
- "properties": {
5
- "collection_id": {
6
- "description": "The unique identifier for the collection.",
7
- "type": ["null", "integer"]
8
- },
9
- "collection_admin_graphql_api_id": {
10
- "description": "The Admin GraphQL API ID for the collection.",
11
- "type": ["null", "string"]
12
- },
13
- "collection_handle": {
14
- "description": "The handle (URL-friendly name) for the collection.",
15
- "type": ["null", "string"]
16
- },
17
- "collection_updated_at": {
18
- "description": "The date and time when the collection was last updated.",
19
- "type": ["null", "string"],
20
- "format": "date-time"
21
- },
22
- "product_id": {
23
- "description": "The unique identifier for the product.",
24
- "type": ["null", "integer"]
25
- },
26
- "product_admin_graphql_api_id": {
27
- "description": "The Admin GraphQL API ID for the product.",
28
- "type": ["null", "string"]
29
- },
30
- "shop_url": {
31
- "description": "The URL of the shop associated with this collection-product association.",
32
- "type": ["null", "string"]
33
- }
34
- }
35
- }