diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/acceptance-test-config.yml b/airbyte-integrations/connectors/source-amazon-seller-partner/acceptance-test-config.yml index e94239156b64..d9e1b1d6b320 100644 --- a/airbyte-integrations/connectors/source-amazon-seller-partner/acceptance-test-config.yml +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/acceptance-test-config.yml @@ -61,76 +61,75 @@ acceptance_tests: extra_fields: no exact_order: no extra_records: yes - # TODO: Add records for empty streams - https://github.com/airbytehq/airbyte/issues/21555 empty_streams: - name: GET_FLAT_FILE_ACTIONABLE_ORDER_DATA_SHIPPING - bypass_reason: "no access and no data" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_ORDER_REPORT_DATA_SHIPPING - bypass_reason: "no access and no data" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_AMAZON_FULFILLED_SHIPMENTS_DATA_GENERAL - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_FBA_FULFILLMENT_REMOVAL_ORDER_DETAIL_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_FBA_FULFILLMENT_REMOVAL_SHIPMENT_DETAIL_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_SELLER_FEEDBACK_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_REPLACEMENT_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_LEDGER_DETAIL_VIEW_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_AFN_INVENTORY_DATA_BY_COUNTRY - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_FLAT_FILE_RETURNS_DATA_BY_RETURN_DATE - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_VENDOR_SALES_REPORT - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_BRAND_ANALYTICS_MARKET_BASKET_REPORT - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_FBA_FULFILLMENT_CUSTOMER_RETURNS_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_FBA_SNS_FORECAST_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_AFN_INVENTORY_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_MERCHANT_CANCELLED_LISTINGS_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_PROMOTION_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_LEDGER_SUMMARY_VIEW_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_BRAND_ANALYTICS_SEARCH_TERMS_REPORT - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_BRAND_ANALYTICS_REPEAT_PURCHASE_REPORT - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: VendorDirectFulfillmentShipping - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_FLAT_FILE_ARCHIVED_ORDERS_DATA_BY_ORDER_DATE - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_VENDOR_INVENTORY_REPORT - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_FBA_SNS_PERFORMANCE_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_FBA_ESTIMATED_FBA_FEES_TXT_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_FBA_INVENTORY_PLANNING_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_FBA_STORAGE_FEE_CHARGES_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_SALES_AND_TRAFFIC_REPORT - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_FBA_MYI_UNSUPPRESSED_INVENTORY_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_STRANDED_INVENTORY_UI_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_FBA_REIMBURSEMENTS_DATA - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_VENDOR_NET_PURE_PRODUCT_MARGIN_REPORT - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_VENDOR_REAL_TIME_INVENTORY_REPORT - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: GET_VENDOR_TRAFFIC_REPORT - bypass_reason: "no records" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" incremental: tests: - config_path: "secrets/config.json" diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/expected_records.jsonl b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/expected_records.jsonl index c36b190c842b..9fc6ce2a88a2 100644 --- a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/expected_records.jsonl +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/expected_records.jsonl @@ -43,14 +43,9 @@ {"stream": "OrderItems", "data": {"TaxCollection": {"Model": "MarketplaceFacilitator", "ResponsibleParty": "Amazon Services, Inc."}, "ProductInfo": {"NumberOfItems": "1"}, "BuyerInfo": {}, "ItemTax": {"CurrencyCode": "USD", "Amount": "0.00"}, "QuantityShipped": 0, "BuyerRequestedCancel": {"IsBuyerRequestedCancel": "false", "BuyerCancelReason": ""}, "ItemPrice": {"CurrencyCode": "USD", "Amount": "14.00"}, "ASIN": "B074K5MDLW", "SellerSKU": "2J-D6V7-C8XI", "Title": "Beyond Meat Beyond Burger Plant-Based Patties 2 pk, 8 oz (Frozen)", "IsGift": "false", "ConditionSubtypeId": "New", "IsTransparency": false, "QuantityOrdered": 0, "PromotionDiscountTax": {"CurrencyCode": "USD", "Amount": "0.00"}, "ConditionId": "New", "PromotionDiscount": {"CurrencyCode": "USD", "Amount": "0.00"}, "OrderItemId": "64356568394218", "LastUpdateDate": "2022-07-29T08:19:16Z", "AmazonOrderId": "113-8871452-8288246"}, "emitted_at": 1701969243138} {"stream": "GET_RESTOCK_INVENTORY_RECOMMENDATIONS_REPORT", "data": {"Country": "US", "Product Name": "Airbyte T-Shirt Black", "FNSKU": "X0041NMBPF", "Merchant SKU": "IA-VREM-8L92", "ASIN": "B0CJ5Q3NLP", "Condition": "New", "Supplier": "unassigned", "Supplier part no.": "", "Currency code": "USD", "Price": "15.00", "Sales last 30 days": "0.0", "Units Sold Last 30 Days": "0", "Total Units": "0", "Inbound": "0", "Available": "0", "FC transfer": "0", "FC Processing": "0", "Customer Order": "0", "Unfulfillable": "0", "Working": "0", "Shipped": "0", "Receiving": "0", "Fulfilled by": "Amazon", "Total Days of Supply (including units from open shipments)": "", "Days of Supply at Amazon Fulfillment Network": "", "Alert": "out_of_stock", "Recommended replenishment qty": "0", "Recommended ship date": "none", "Recommended action": "No action required", "Unit storage size": "", "dataEndTime": "2022-07-31"}, "emitted_at": 1701969512824} {"stream": "GET_RESTOCK_INVENTORY_RECOMMENDATIONS_REPORT", "data": {"Country": "US", "Product Name": "Airbyte Merch White", "FNSKU": "X003X1FG67", "Merchant SKU": "KW-J7BQ-WNKL", "ASIN": "B0CDLLJ5VV", "Condition": "New", "Supplier": "unassigned", "Supplier part no.": "", "Currency code": "USD", "Price": "10.00", "Sales last 30 days": "0.0", "Units Sold Last 30 Days": "0", "Total Units": "0", "Inbound": "0", "Available": "0", "FC transfer": "0", "FC Processing": "0", "Customer Order": "0", "Unfulfillable": "0", "Working": "0", "Shipped": "0", "Receiving": "0", "Fulfilled by": "Amazon", "Total Days of Supply (including units from open shipments)": "", "Days of Supply at Amazon Fulfillment Network": "", "Alert": "out_of_stock", "Recommended replenishment qty": "0", "Recommended ship date": "none", "Recommended action": "No action required", "Unit storage size": "0.1736 ft3", "dataEndTime": "2022-07-31"}, "emitted_at": 1701969512826} -{"stream": "GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE", "data": {"settlement-id": "19009771651", "settlement-start-date": "2023-11-13T22:51:31+00:00", "settlement-end-date": "2023-12-11T22:51:31+00:00", "deposit-date": "2023-12-13T22:51:31+00:00", "total-amount": "-39.99", "currency": "USD", "transaction-type": "", "order-id": "", "merchant-order-id": "", "adjustment-id": "", "shipment-id": "", "marketplace-name": "", "shipment-fee-type": "", "shipment-fee-amount": "", "order-fee-type": "", "order-fee-amount": "", "fulfillment-id": "", "posted-date": null, "order-item-code": "", "merchant-order-item-id": "", "merchant-adjustment-item-id": "", "sku": "", "quantity-purchased": "", "price-type": "", "price-amount": "", "item-related-fee-type": "", "item-related-fee-amount": "", "misc-fee-amount": "", "other-fee-amount": "", "other-fee-reason-description": "", "direct-payment-type": "", "direct-payment-amount": "", "other-amount": "", "dataEndTime": "2023-12-11"}, "emitted_at": 1705396604115} -{"stream": "GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE", "data": {"settlement-id": "19009771651", "settlement-start-date": null, "settlement-end-date": null, "deposit-date": null, "total-amount": "", "currency": "", "transaction-type": "Payable to Amazon", "order-id": "", "merchant-order-id": "", "adjustment-id": "", "shipment-id": "", "marketplace-name": "", "shipment-fee-type": "", "shipment-fee-amount": "", "order-fee-type": "", "order-fee-amount": "", "fulfillment-id": "", "posted-date": "2023-11-13T22:51:31+00:00", "order-item-code": "", "merchant-order-item-id": "", "merchant-adjustment-item-id": "", "sku": "", "quantity-purchased": "", "price-type": "", "price-amount": "", "item-related-fee-type": "", "item-related-fee-amount": "", "misc-fee-amount": "", "other-fee-amount": "", "other-fee-reason-description": "", "direct-payment-type": "", "direct-payment-amount": "", "other-amount": "-39.99", "dataEndTime": "2023-12-11"}, "emitted_at": 1705396604117} -{"stream": "GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE", "data": {"settlement-id": "19009771651", "settlement-start-date": null, "settlement-end-date": null, "deposit-date": null, "total-amount": "", "currency": "", "transaction-type": "Subscription Fee", "order-id": "", "merchant-order-id": "", "adjustment-id": "", "shipment-id": "", "marketplace-name": "", "shipment-fee-type": "", "shipment-fee-amount": "", "order-fee-type": "", "order-fee-amount": "", "fulfillment-id": "", "posted-date": "2023-12-09T20:02:53+00:00", "order-item-code": "", "merchant-order-item-id": "", "merchant-adjustment-item-id": "", "sku": "", "quantity-purchased": "", "price-type": "", "price-amount": "", "item-related-fee-type": "", "item-related-fee-amount": "", "misc-fee-amount": "", "other-fee-amount": "", "other-fee-reason-description": "", "direct-payment-type": "", "direct-payment-amount": "", "other-amount": "-39.99", "dataEndTime": "2023-12-11"}, "emitted_at": 1705396604118} -{"stream": "GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE", "data": {"settlement-id": "19009771651", "settlement-start-date": null, "settlement-end-date": null, "deposit-date": null, "total-amount": "", "currency": "", "transaction-type": "Successful charge", "order-id": "", "merchant-order-id": "", "adjustment-id": "", "shipment-id": "", "marketplace-name": "", "shipment-fee-type": "", "shipment-fee-amount": "", "order-fee-type": "", "order-fee-amount": "", "fulfillment-id": "", "posted-date": "2023-11-13T23:51:01+00:00", "order-item-code": "", "merchant-order-item-id": "", "merchant-adjustment-item-id": "", "sku": "", "quantity-purchased": "", "price-type": "", "price-amount": "", "item-related-fee-type": "", "item-related-fee-amount": "", "misc-fee-amount": "", "other-fee-amount": "", "other-fee-reason-description": "", "direct-payment-type": "", "direct-payment-amount": "", "other-amount": "39.99 ", "dataEndTime": "2023-12-11"}, "emitted_at": 1705396604118} -{"stream": "GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE", "data": {"settlement-id": "18923842351", "settlement-start-date": "2023-10-16T22:51:31+00:00", "settlement-end-date": "2023-11-13T22:51:31+00:00", "deposit-date": "2023-11-15T22:51:31+00:00", "total-amount": "-39.99", "currency": "USD", "transaction-type": "", "order-id": "", "merchant-order-id": "", "adjustment-id": "", "shipment-id": "", "marketplace-name": "", "shipment-fee-type": "", "shipment-fee-amount": "", "order-fee-type": "", "order-fee-amount": "", "fulfillment-id": "", "posted-date": null, "order-item-code": "", "merchant-order-item-id": "", "merchant-adjustment-item-id": "", "sku": "", "quantity-purchased": "", "price-type": "", "price-amount": "", "item-related-fee-type": "", "item-related-fee-amount": "", "misc-fee-amount": "", "other-fee-amount": "", "other-fee-reason-description": "", "direct-payment-type": "", "direct-payment-amount": "", "other-amount": "", "dataEndTime": "2023-11-13"}, "emitted_at": 1705396605853} -{"stream": "GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE", "data": {"settlement-id": "18923842351", "settlement-start-date": null, "settlement-end-date": null, "deposit-date": null, "total-amount": "", "currency": "", "transaction-type": "Payable to Amazon", "order-id": "", "merchant-order-id": "", "adjustment-id": "", "shipment-id": "", "marketplace-name": "", "shipment-fee-type": "", "shipment-fee-amount": "", "order-fee-type": "", "order-fee-amount": "", "fulfillment-id": "", "posted-date": "2023-10-16T22:51:31+00:00", "order-item-code": "", "merchant-order-item-id": "", "merchant-adjustment-item-id": "", "sku": "", "quantity-purchased": "", "price-type": "", "price-amount": "", "item-related-fee-type": "", "item-related-fee-amount": "", "misc-fee-amount": "", "other-fee-amount": "", "other-fee-reason-description": "", "direct-payment-type": "", "direct-payment-amount": "", "other-amount": "-27.54", "dataEndTime": "2023-11-13"}, "emitted_at": 1705396605855} -{"stream": "GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE", "data": {"settlement-id": "18923842351", "settlement-start-date": null, "settlement-end-date": null, "deposit-date": null, "total-amount": "", "currency": "", "transaction-type": "Subscription Fee", "order-id": "", "merchant-order-id": "", "adjustment-id": "", "shipment-id": "", "marketplace-name": "", "shipment-fee-type": "", "shipment-fee-amount": "", "order-fee-type": "", "order-fee-amount": "", "fulfillment-id": "", "posted-date": "2023-11-09T18:44:35+00:00", "order-item-code": "", "merchant-order-item-id": "", "merchant-adjustment-item-id": "", "sku": "", "quantity-purchased": "", "price-type": "", "price-amount": "", "item-related-fee-type": "", "item-related-fee-amount": "", "misc-fee-amount": "", "other-fee-amount": "", "other-fee-reason-description": "", "direct-payment-type": "", "direct-payment-amount": "", "other-amount": "-39.99", "dataEndTime": "2023-11-13"}, "emitted_at": 1705396605856} -{"stream": "GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE", "data": {"settlement-id": "18923842351", "settlement-start-date": null, "settlement-end-date": null, "deposit-date": null, "total-amount": "", "currency": "", "transaction-type": "Successful charge", "order-id": "", "merchant-order-id": "", "adjustment-id": "", "shipment-id": "", "marketplace-name": "", "shipment-fee-type": "", "shipment-fee-amount": "", "order-fee-type": "", "order-fee-amount": "", "fulfillment-id": "", "posted-date": "2023-10-17T00:01:09+00:00", "order-item-code": "", "merchant-order-item-id": "", "merchant-adjustment-item-id": "", "sku": "", "quantity-purchased": "", "price-type": "", "price-amount": "", "item-related-fee-type": "", "item-related-fee-amount": "", "misc-fee-amount": "", "other-fee-amount": "", "other-fee-reason-description": "", "direct-payment-type": "", "direct-payment-amount": "", "other-amount": "27.54 ", "dataEndTime": "2023-11-13"}, "emitted_at": 1705396605857} +{"stream": "GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE", "data": {"settlement-id": "19009771651", "settlement-start-date": "2023-11-13T22:51:31+00:00", "settlement-end-date": "2023-12-11T22:51:31+00:00", "deposit-date": "2023-12-13T22:51:31+00:00", "total-amount": "-39.99", "currency": "USD", "transaction-type": "", "order-id": "", "merchant-order-id": "", "adjustment-id": "", "shipment-id": "", "marketplace-name": "", "shipment-fee-type": "", "shipment-fee-amount": "", "order-fee-type": "", "order-fee-amount": "", "fulfillment-id": "", "posted-date": null, "order-item-code": "", "merchant-order-item-id": "", "merchant-adjustment-item-id": "", "sku": "", "quantity-purchased": "", "price-type": "", "price-amount": "", "item-related-fee-type": "", "item-related-fee-amount": "", "misc-fee-amount": "", "other-fee-amount": "", "other-fee-reason-description": "", "direct-payment-type": "", "direct-payment-amount": "", "other-amount": "", "dataEndTime": "2023-12-11"}, "emitted_at": 1707819017802} +{"stream": "GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE", "data": {"settlement-id": "19009771651", "settlement-start-date": null, "settlement-end-date": null, "deposit-date": null, "total-amount": "", "currency": "", "transaction-type": "Payable to Amazon", "order-id": "", "merchant-order-id": "", "adjustment-id": "", "shipment-id": "", "marketplace-name": "", "shipment-fee-type": "", "shipment-fee-amount": "", "order-fee-type": "", "order-fee-amount": "", "fulfillment-id": "", "posted-date": "2023-11-13T22:51:31+00:00", "order-item-code": "", "merchant-order-item-id": "", "merchant-adjustment-item-id": "", "sku": "", "quantity-purchased": "", "price-type": "", "price-amount": "", "item-related-fee-type": "", "item-related-fee-amount": "", "misc-fee-amount": "", "other-fee-amount": "", "other-fee-reason-description": "", "direct-payment-type": "", "direct-payment-amount": "", "other-amount": "-39.99", "dataEndTime": "2023-12-11"}, "emitted_at": 1707819017804} +{"stream": "GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE", "data": {"settlement-id": "19009771651", "settlement-start-date": null, "settlement-end-date": null, "deposit-date": null, "total-amount": "", "currency": "", "transaction-type": "Subscription Fee", "order-id": "", "merchant-order-id": "", "adjustment-id": "", "shipment-id": "", "marketplace-name": "", "shipment-fee-type": "", "shipment-fee-amount": "", "order-fee-type": "", "order-fee-amount": "", "fulfillment-id": "", "posted-date": "2023-12-09T20:02:53+00:00", "order-item-code": "", "merchant-order-item-id": "", "merchant-adjustment-item-id": "", "sku": "", "quantity-purchased": "", "price-type": "", "price-amount": "", "item-related-fee-type": "", "item-related-fee-amount": "", "misc-fee-amount": "", "other-fee-amount": "", "other-fee-reason-description": "", "direct-payment-type": "", "direct-payment-amount": "", "other-amount": "-39.99", "dataEndTime": "2023-12-11"}, "emitted_at": 1707819017805} {"stream": "GET_MERCHANT_LISTINGS_DATA_BACK_COMPAT", "data": {"item-name": "GiftBox", "item-description": "Monitor and optimize the GiftBox to reward your customers and increase the average order value", "listing-id": "0711ZJUYPNS", "seller-sku": "I0-RALD-N1UR", "price": "5", "quantity": "1000", "open-date": "2022-07-11T01:34:18-07:00", "image-url": "", "item-is-marketplace": "y", "product-id-type": "1", "zshop-shipping-fee": "", "item-note": "", "item-condition": "11", "zshop-category1": "", "zshop-browse-path": "", "zshop-storefront-feature": "", "asin1": "B0B68NBQ1Y", "asin2": "", "asin3": "", "will-ship-internationally": "", "expedited-shipping": "", "zshop-boldface": "", "product-id": "B0B68NBQ1Y", "bid-for-featured-placement": "", "add-delete": "", "pending-quantity": "0", "Business Price": "6.0", "Quantity Price Type": "", "Quantity Lower Bound 1": "", "Quantity Price 1": "", "Quantity Lower Bound 2": "", "Quantity Price 2": "", "Quantity Lower Bound 3": "", "Quantity Price 3": "", "Quantity Lower Bound 4": "", "Quantity Price 4": "", "Quantity Lower Bound 5": "", "Quantity Price 5": "", "merchant-shipping-group": "Migrated Template", "Progressive Price Type": "", "Progressive Lower Bound 1": "", "Progressive Price 1": "", "Progressive Lower Bound 2": "", "Progressive Price 2": "", "Progressive Lower Bound 3": "", "Progressive Price 3": "", "dataEndTime": "2022-07-31"}, "emitted_at": 1701976405556} {"stream": "ListFinancialEvents", "data": {"ShipmentEventList": [], "ShipmentSettleEventList": [], "RefundEventList": [], "GuaranteeClaimEventList": [], "ChargebackEventList": [], "PayWithAmazonEventList": [], "ServiceProviderCreditEventList": [], "RetrochargeEventList": [], "RentalTransactionEventList": [], "PerformanceBondRefundEventList": [], "ProductAdsPaymentEventList": [{"postedDate": "2022-07-28T20:06:07Z", "transactionType": "Charge", "invoiceId": "TR1T7Z7DR-1", "baseValue": {"CurrencyCode": "USD", "CurrencyAmount": -9.08}, "taxValue": {"CurrencyCode": "USD", "CurrencyAmount": 0.0}, "transactionValue": {"CurrencyCode": "USD", "CurrencyAmount": -9.08}}], "ServiceFeeEventList": [], "SellerDealPaymentEventList": [], "DebtRecoveryEventList": [], "LoanServicingEventList": [], "AdjustmentEventList": [], "SAFETReimbursementEventList": [], "SellerReviewEnrollmentPaymentEventList": [], "FBALiquidationEventList": [], "CouponPaymentEventList": [], "ImagingServicesFeeEventList": [], "NetworkComminglingTransactionEventList": [], "AffordabilityExpenseEventList": [], "AffordabilityExpenseReversalEventList": [], "RemovalShipmentEventList": [], "RemovalShipmentAdjustmentEventList": [], "TrialShipmentEventList": [], "TDSReimbursementEventList": [], "AdhocDisbursementEventList": [], "TaxWithholdingEventList": [], "ChargeRefundEventList": [], "FailedAdhocDisbursementEventList": [], "ValueAddedServiceChargeEventList": [], "CapacityReservationBillingEventList": [], "PostedBefore": "2022-07-31T00:00:00Z"}, "emitted_at": 1701976465145} {"stream": "ListFinancialEventGroups", "data": {"FinancialEventGroupId": "6uFLEEa3LQgyvcccMnVQ4Bj-I5zkOVNoM41q8leJzLk", "ProcessingStatus": "Closed", "FundTransferStatus": "Unknown", "OriginalTotal": {"CurrencyCode": "USD", "CurrencyAmount": -58.86}, "FundTransferDate": "2022-08-08T22:51:31Z", "BeginningBalance": {"CurrencyCode": "USD", "CurrencyAmount": -39.99}, "FinancialEventGroupStart": "2021-07-26T22:51:30Z", "FinancialEventGroupEnd": "2022-08-08T22:51:31Z"}, "emitted_at": 1701976502869} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/metadata.yaml b/airbyte-integrations/connectors/source-amazon-seller-partner/metadata.yaml index 61950b18e3cd..552bbaa1b92c 100644 --- a/airbyte-integrations/connectors/source-amazon-seller-partner/metadata.yaml +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/metadata.yaml @@ -15,7 +15,7 @@ data: connectorSubtype: api connectorType: source definitionId: e55879a8-0ef8-4557-abcf-ab34c53ec460 - dockerImageTag: 3.3.1 + dockerImageTag: 3.3.2 dockerRepository: airbyte/source-amazon-seller-partner documentationUrl: https://docs.airbyte.com/integrations/sources/amazon-seller-partner githubIssueLabel: source-amazon-seller-partner diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/setup.py b/airbyte-integrations/connectors/source-amazon-seller-partner/setup.py index ffb08022871d..e75c0a55146b 100644 --- a/airbyte-integrations/connectors/source-amazon-seller-partner/setup.py +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/setup.py @@ -7,7 +7,7 @@ MAIN_REQUIREMENTS = ["airbyte-cdk", "xmltodict~=0.12", "dateparser==1.2.0"] -TEST_REQUIREMENTS = ["requests-mock~=1.9.3", "pytest~=6.1", "pytest-mock"] +TEST_REQUIREMENTS = ["requests-mock~=1.9.3", "pytest~=6.1", "pytest-mock", "freezegun==1.2.2"] setup( entry_points={ diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_SALES_AND_TRAFFIC_REPORT.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_SALES_AND_TRAFFIC_REPORT.json index d41c4cb69df1..d5863d6d3532 100644 --- a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_SALES_AND_TRAFFIC_REPORT.json +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_SALES_AND_TRAFFIC_REPORT.json @@ -14,6 +14,9 @@ "childAsin": { "type": ["null", "string"] }, + "sku": { + "type": ["null", "string"] + }, "salesByAsin": { "type": "object", "properties": { diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/streams.py b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/streams.py index 5d4e1f9dd545..f59eee2663c9 100644 --- a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/streams.py +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/streams.py @@ -5,7 +5,8 @@ import csv import gzip -import json as json_lib +import json +import os import time from abc import ABC, abstractmethod from enum import Enum @@ -32,6 +33,8 @@ DATE_TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ" DATE_FORMAT = "%Y-%m-%d" +IS_TESTING = os.environ.get("DEPLOYMENT_MODE") == "testing" + class AmazonSPStream(HttpStream, ABC): data_field = "payload" @@ -64,6 +67,12 @@ def request_headers(self, *args, **kwargs) -> Mapping[str, Any]: def next_page_token(self, response: requests.Response) -> Optional[Mapping[str, Any]]: return None + def retry_factor(self) -> float: + """ + Override for testing purposes + """ + return 0 if IS_TESTING else super().retry_factor + class IncrementalAmazonSPStream(AmazonSPStream, ABC): page_size = 100 @@ -204,8 +213,11 @@ def http_method(self, value: str): @property def retry_factor(self) -> float: - # https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference#post-reports2021-06-30reports - return 60.0 + """ + Set this 60.0 due to https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference#post-reports2021-06-30reports + Override to 0 for integration testing purposes + """ + return 0 if IS_TESTING else 60.0 @property def url_base(self) -> str: @@ -246,7 +258,7 @@ def _create_report( create_report_request = self._create_prepared_request( path=f"{self.path_prefix}/reports", headers=dict(request_headers, **self.authenticator.get_auth_header()), - data=json_lib.dumps(report_data), + data=json.dumps(report_data), ) report_response = self._send_request(create_report_request, {}) self.http_method = "GET" # rollback @@ -268,8 +280,9 @@ def download_and_decompress_report_document(self, payload: dict) -> str: """ Unpacks a report document """ - report = requests.get(payload.get("url")) - report.raise_for_status() + + download_report_request = self._create_prepared_request(path=payload.get("url")) + report = self._send_request(download_report_request, {}) if "compressionAlgorithm" in payload: return gzip.decompress(report.content).decode("iso-8859-1") return report.content.decode("iso-8859-1") @@ -649,7 +662,7 @@ class FbaInventoryPlaningReport(IncrementalReportsAmazonSPStream): class AnalyticsStream(ReportsAmazonSPStream): def parse_document(self, document): - parsed = json_lib.loads(document) + parsed = json.loads(document) return parsed.get(self.result_key, []) def _report_data( @@ -885,12 +898,15 @@ def __init__(self, *args, **kwargs): def get_transform_function(self): def transform_function(original_value: Any, field_schema: Dict[str, Any]) -> Any: - if original_value and "format" in field_schema and field_schema["format"] == "date": + if original_value and field_schema.get("format") == "date": date_format = self.MARKETPLACE_DATE_FORMAT_MAP.get(self.marketplace_id) if not date_format: raise KeyError(f"Date format not found for Marketplace ID: {self.marketplace_id}") - transformed_value = pendulum.from_format(original_value, date_format).to_date_string() - return transformed_value + try: + transformed_value = pendulum.from_format(original_value, date_format).to_date_string() + return transformed_value + except ValueError: + pass return original_value @@ -1099,6 +1115,12 @@ class VendorDirectFulfillmentShipping(IncrementalAmazonSPStream): def path(self, **kwargs) -> str: return f"vendor/directFulfillment/shipping/{VENDORS_API_VERSION}/shippingLabels" + def next_page_token(self, response: requests.Response) -> Optional[Mapping[str, Any]]: + stream_data = response.json() + next_page_token = stream_data.get("payload", {}).get("pagination", {}).get(self.next_page_token_field) + if next_page_token: + return {self.next_page_token_field: next_page_token} + def request_params( self, stream_state: Mapping[str, Any], next_page_token: Mapping[str, Any] = None, **kwargs ) -> MutableMapping[str, Any]: diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/conftest.py b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/conftest.py index 1dcbb11a25fb..88ae651494b9 100644 --- a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/conftest.py +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/conftest.py @@ -3,10 +3,13 @@ # +import os from typing import Any, Dict import pytest +os.environ["DEPLOYMENT_MODE"] = "testing" + @pytest.fixture def report_init_kwargs() -> Dict[str, Any]: @@ -18,3 +21,8 @@ def report_init_kwargs() -> Dict[str, Any]: "report_options": None, "replication_end_date": None, } + + +@pytest.fixture +def http_mocker() -> None: + """This fixture is needed to pass http_mocker parameter from the @HttpMocker decorator to a test""" diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/__init__.py b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/config.py b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/config.py new file mode 100644 index 000000000000..8b79eafe8e94 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/config.py @@ -0,0 +1,46 @@ +# +# Copyright (c) 2024 Airbyte, Inc., all rights reserved. +# + + +from __future__ import annotations + +from datetime import datetime +from typing import Dict + +import pendulum + +ACCESS_TOKEN = "test_access_token" +LWA_APP_ID = "amazon_app_id" +LWA_CLIENT_SECRET = "amazon_client_secret" +MARKETPLACE_ID = "ATVPDKIKX0DER" +REFRESH_TOKEN = "amazon_refresh_token" + +CONFIG_START_DATE = "2023-01-01T00:00:00Z" +CONFIG_END_DATE = "2023-01-30T00:00:00Z" +NOW = pendulum.now(tz="utc") + + +class ConfigBuilder: + def __init__(self) -> None: + self._config: Dict[str, str] = { + "refresh_token": REFRESH_TOKEN, + "lwa_app_id": LWA_APP_ID, + "lwa_client_secret": LWA_CLIENT_SECRET, + "replication_start_date": CONFIG_START_DATE, + "replication_end_date": CONFIG_END_DATE, + "aws_environment": "PRODUCTION", + "region": "US", + "account_type": "Seller", + } + + def with_start_date(self, start_date: datetime) -> ConfigBuilder: + self._config["replication_start_date"] = start_date.isoformat()[:-13] + "Z" + return self + + def with_end_date(self, end_date: datetime) -> ConfigBuilder: + self._config["replication_end_date"] = end_date.isoformat()[:-13] + "Z" + return self + + def build(self) -> Dict[str, str]: + return self._config diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/pagination.py b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/pagination.py new file mode 100644 index 000000000000..f47a39e6655e --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/pagination.py @@ -0,0 +1,16 @@ +# +# Copyright (c) 2024 Airbyte, Inc., all rights reserved. +# + + +from typing import Any, Dict + +from airbyte_cdk.test.mock_http.response_builder import PaginationStrategy + +NEXT_TOKEN_STRING = "MDAwMDAwMDAwMQ==" + + +class VendorDirectFulfillmentShippingPaginationStrategy(PaginationStrategy): + def update(self, response: Dict[str, Any]) -> None: + response["payload"]["pagination"] = {} + response["payload"]["pagination"]["nextToken"] = NEXT_TOKEN_STRING diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/request_builder.py b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/request_builder.py new file mode 100644 index 000000000000..d0433259a582 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/request_builder.py @@ -0,0 +1,88 @@ +# +# Copyright (c) 2024 Airbyte, Inc., all rights reserved. +# + + +from __future__ import annotations + +import json +from typing import Any, List, Mapping, Optional, Union + +from airbyte_cdk.test.mock_http.request import ANY_QUERY_PARAMS, HttpRequest + +from .config import ACCESS_TOKEN, LWA_APP_ID, LWA_CLIENT_SECRET, MARKETPLACE_ID, NOW, REFRESH_TOKEN + + +class RequestBuilder: + + @classmethod + def auth_endpoint(cls) -> RequestBuilder: + request_headers = {"Content-Type": "application/x-www-form-urlencoded"} + request_body = ( + f"grant_type=refresh_token&client_id={LWA_APP_ID}&" + f"client_secret={LWA_CLIENT_SECRET}&refresh_token={REFRESH_TOKEN}" + ) + return cls("auth/o2/token").with_base_url("https://api.amazon.com").with_headers(request_headers).with_body( + request_body + ) + + @classmethod + def create_report_endpoint(cls, report_name: str) -> RequestBuilder: + request_body = { + "reportType": report_name, + "marketplaceIds": [MARKETPLACE_ID], + "dataStartTime": "2023-01-01T00:00:00Z", + "dataEndTime": "2023-01-30T00:00:00Z", + } + return cls("reports/2021-06-30/reports").with_body(json.dumps(request_body)) + + @classmethod + def check_report_status_endpoint(cls, report_id: str) -> RequestBuilder: + return cls(f"reports/2021-06-30/reports/{report_id}") + + @classmethod + def get_document_download_url_endpoint(cls, document_id: str) -> RequestBuilder: + return cls(f"reports/2021-06-30/documents/{document_id}") + + @classmethod + def download_document_endpoint(cls, url: str) -> RequestBuilder: + return cls("").with_base_url(url).with_headers(None) + + @classmethod + def vendor_direct_fulfillment_shipping_endpoint(cls) -> RequestBuilder: + return cls("vendor/directFulfillment/shipping/v1/shippingLabels") + + def __init__(self, resource: str) -> None: + self._resource = resource + self._base_url = "https://sellingpartnerapi-na.amazon.com" + self._headers = { + "content-type": "application/json", + "host": self._base_url.replace("https://", ""), + "user-agent": "python-requests", + "x-amz-access-token": ACCESS_TOKEN, + "x-amz-date": NOW.strftime("%Y%m%dT%H%M%SZ"), + } + self._query_params = ANY_QUERY_PARAMS + self._body = None + + def with_base_url(self, base_url: str) -> RequestBuilder: + self._base_url = base_url + return self + + def with_headers(self, headers: Optional[Union[str, Mapping[str, str]]]) -> RequestBuilder: + self._headers = headers + return self + + def with_query_params(self, query_params: Union[str, Mapping[str, Union[str, List[str]]]]) -> RequestBuilder: + self._query_params = query_params + return self + + def with_body(self, body: Union[str, bytes, Mapping[str, Any]]) -> RequestBuilder: + self._body = body + return self + + def _url(self) -> str: + return f"{self._base_url}/{self._resource}" if self._resource else self._base_url + + def build(self) -> HttpRequest: + return HttpRequest(url=self._url(), query_params=self._query_params, headers=self._headers, body=self._body) diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/response_builder.py b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/response_builder.py new file mode 100644 index 000000000000..c557e6bab9b8 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/response_builder.py @@ -0,0 +1,19 @@ +# +# Copyright (c) 2024 Airbyte, Inc., all rights reserved. +# + + +import json +from http import HTTPStatus +from typing import Any, Mapping, Optional + +from airbyte_cdk.test.mock_http import HttpResponse + + +def response_with_status(status_code: HTTPStatus, body: Optional[Mapping[str, Any]] = None) -> HttpResponse: + body = body or {} + return HttpResponse(body=json.dumps(body), status_code=status_code) + + +def build_response(body: Mapping[str, Any], status_code: HTTPStatus) -> HttpResponse: + return HttpResponse(body=json.dumps(body), status_code=status_code) diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/test_report_based_streams.py b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/test_report_based_streams.py new file mode 100644 index 000000000000..499f79330ae1 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/test_report_based_streams.py @@ -0,0 +1,508 @@ +# +# Copyright (c) 2024 Airbyte, Inc., all rights reserved. +# + + +import gzip +from http import HTTPStatus +from typing import List, Optional + +import freezegun +import pytest +import requests_mock +from airbyte_cdk.test.entrypoint_wrapper import EntrypointOutput +from airbyte_cdk.test.mock_http import HttpMocker, HttpResponse +from airbyte_cdk.test.mock_http.matcher import HttpRequestMatcher +from airbyte_protocol.models import AirbyteStateMessage, FailureType, SyncMode +from source_amazon_seller_partner.streams import ReportProcessingStatus + +from .config import CONFIG_END_DATE, CONFIG_START_DATE, MARKETPLACE_ID, NOW, ConfigBuilder +from .request_builder import RequestBuilder +from .response_builder import build_response, response_with_status +from .utils import assert_message_in_log_output, config, find_template, get_stream_by_name, mock_auth, read_output + +_DOCUMENT_DOWNLOAD_URL = "https://test.com/download" +_REPORT_ID = "6789087632" +_REPORT_DOCUMENT_ID = "report_document_id" + +DEFAULT_EXPECTED_NUMBER_OF_RECORDS = 2 # every test file in resource/http/response contains 2 records +STREAMS = ( + ("GET_FLAT_FILE_ACTIONABLE_ORDER_DATA_SHIPPING", "csv"), + ("GET_ORDER_REPORT_DATA_SHIPPING", "xml"), + ("GET_AMAZON_FULFILLED_SHIPMENTS_DATA_GENERAL", "csv"), + ("GET_FBA_FULFILLMENT_REMOVAL_ORDER_DETAIL_DATA", "csv"), + ("GET_FBA_FULFILLMENT_REMOVAL_SHIPMENT_DETAIL_DATA", "csv"), + ("GET_SELLER_FEEDBACK_DATA", "csv"), + ("GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_REPLACEMENT_DATA", "csv"), + ("GET_LEDGER_DETAIL_VIEW_DATA", "csv"), + ("GET_AFN_INVENTORY_DATA_BY_COUNTRY", "csv"), + ("GET_FLAT_FILE_RETURNS_DATA_BY_RETURN_DATE", "csv"), + ("GET_VENDOR_SALES_REPORT", "json"), + ("GET_BRAND_ANALYTICS_MARKET_BASKET_REPORT", "json"), + ("GET_FBA_FULFILLMENT_CUSTOMER_RETURNS_DATA", "csv"), + ("GET_FBA_SNS_FORECAST_DATA", "csv"), + ("GET_AFN_INVENTORY_DATA", "csv"), + ("GET_MERCHANT_CANCELLED_LISTINGS_DATA", "csv"), + ("GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_PROMOTION_DATA", "csv"), + ("GET_LEDGER_SUMMARY_VIEW_DATA", "csv"), + ("GET_BRAND_ANALYTICS_SEARCH_TERMS_REPORT", "json"), + ("GET_BRAND_ANALYTICS_REPEAT_PURCHASE_REPORT", "json"), + ("GET_FLAT_FILE_ARCHIVED_ORDERS_DATA_BY_ORDER_DATE", "csv"), + ("GET_VENDOR_INVENTORY_REPORT", "json"), + ("GET_FBA_SNS_PERFORMANCE_DATA", "csv"), + ("GET_FBA_ESTIMATED_FBA_FEES_TXT_DATA", "csv"), + ("GET_FBA_INVENTORY_PLANNING_DATA", "csv"), + ("GET_FBA_STORAGE_FEE_CHARGES_DATA", "csv"), + ("GET_FBA_MYI_UNSUPPRESSED_INVENTORY_DATA", "csv"), + ("GET_STRANDED_INVENTORY_UI_DATA", "csv"), + ("GET_FBA_REIMBURSEMENTS_DATA", "csv"), + ("GET_VENDOR_NET_PURE_PRODUCT_MARGIN_REPORT", "json"), + ("GET_VENDOR_REAL_TIME_INVENTORY_REPORT", "json"), + ("GET_VENDOR_TRAFFIC_REPORT", "json"), +) + + +def _create_report_request(report_name: str) -> RequestBuilder: + """ + A POST request needed to start generating a report on Amazon SP platform. + Performed in ReportsAmazonSPStream._create_report method. + """ + + return RequestBuilder.create_report_endpoint(report_name) + + +def _check_report_status_request(report_id: str) -> RequestBuilder: + """ + A GET request needed to check the report generating status. + Performed in ReportsAmazonSPStream._retrieve_report method. + """ + + return RequestBuilder.check_report_status_endpoint(report_id) + + +def _get_document_download_url_request(document_id: str) -> RequestBuilder: + """ + A GET request which returns a URL for the report download. + """ + + return RequestBuilder.get_document_download_url_endpoint(document_id) + + +def _download_document_request(url: str) -> RequestBuilder: + """ + A GET request which actually downloads the report. + Performed in ReportsAmazonSPStream.download_and_decompress_report_document method. + """ + + return RequestBuilder.download_document_endpoint(url) + + +def _create_report_response(report_id: str, status_code: Optional[HTTPStatus] = HTTPStatus.ACCEPTED) -> HttpResponse: + response_body = {"reportId": report_id} + return build_response(response_body, status_code=status_code) + + +def _check_report_status_response( + report_name: str, + processing_status: Optional[ReportProcessingStatus] = ReportProcessingStatus.DONE, + report_document_id: Optional[str] = None, +) -> HttpResponse: + if processing_status == ReportProcessingStatus.DONE and not report_document_id: + raise ValueError("report_document_id value should be passed when processing_status is 'DONE'.") + + response_body = { + "reportType": report_name, + "processingStatus": processing_status, + "marketplaceIds": [MARKETPLACE_ID], + "reportId": _REPORT_ID, + "dataEndTime": CONFIG_END_DATE, + "createdTime": CONFIG_START_DATE, + "dataStartTime": CONFIG_START_DATE, + } + if processing_status == ReportProcessingStatus.DONE: + response_body.update( + { + "reportDocumentId": report_document_id, + "processingEndTime": CONFIG_START_DATE, + "processingStartTime": CONFIG_START_DATE, + } + ) + + return build_response(response_body, status_code=HTTPStatus.OK) + + +def _get_document_download_url_response( + document_download_url: str, report_document_id: str, compressed: Optional[bool] = False +) -> HttpResponse: + response_body = {"reportDocumentId": report_document_id, "url": document_download_url} + if compressed: + # See https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference#compressionalgorithm + response_body["compressionAlgorithm"] = "GZIP" + return build_response(response_body, status_code=HTTPStatus.OK) + + +def _download_document_response( + stream_name: str, data_format: Optional[str] = "csv", compressed: Optional[bool] = False +) -> HttpResponse: + response_body = find_template(stream_name, __file__, data_format) + if compressed: + response_body = gzip.compress(response_body.encode("iso-8859-1")) + return HttpResponse(body=response_body, status_code=HTTPStatus.OK) + + +@freezegun.freeze_time(NOW.isoformat()) +class TestFullRefresh: + + @staticmethod + def _read(stream_name: str, config_: ConfigBuilder, expecting_exception: bool = False) -> EntrypointOutput: + return read_output( + config_builder=config_, + stream_name=stream_name, + sync_mode=SyncMode.full_refresh, + expecting_exception=expecting_exception, + ) + + @pytest.mark.parametrize(("stream_name", "data_format"), STREAMS) + @HttpMocker() + def test_given_report_when_read_then_return_records( + self, stream_name: str, data_format: str, http_mocker: HttpMocker + ) -> None: + mock_auth(http_mocker) + + http_mocker.post(_create_report_request(stream_name).build(), _create_report_response(_REPORT_ID)) + http_mocker.get( + _check_report_status_request(_REPORT_ID).build(), + _check_report_status_response(stream_name, report_document_id=_REPORT_DOCUMENT_ID), + ) + http_mocker.get( + _get_document_download_url_request(_REPORT_DOCUMENT_ID).build(), + _get_document_download_url_response(_DOCUMENT_DOWNLOAD_URL, _REPORT_DOCUMENT_ID), + ) + http_mocker.get( + _download_document_request(_DOCUMENT_DOWNLOAD_URL).build(), + _download_document_response(stream_name, data_format=data_format), + ) + + output = self._read(stream_name, config()) + assert len(output.records) == DEFAULT_EXPECTED_NUMBER_OF_RECORDS + + @pytest.mark.parametrize(("stream_name", "data_format"), STREAMS) + @HttpMocker() + def test_given_compressed_report_when_read_then_return_records( + self, stream_name: str, data_format: str, http_mocker: HttpMocker + ) -> None: + mock_auth(http_mocker) + + http_mocker.post(_create_report_request(stream_name).build(), _create_report_response(_REPORT_ID)) + http_mocker.get( + _check_report_status_request(_REPORT_ID).build(), + _check_report_status_response(stream_name, report_document_id=_REPORT_DOCUMENT_ID), + ) + http_mocker.get( + _get_document_download_url_request(_REPORT_DOCUMENT_ID).build(), + _get_document_download_url_response(_DOCUMENT_DOWNLOAD_URL, _REPORT_DOCUMENT_ID, compressed=True), + ) + + # a workaround to pass compressed document to the mocked response + document_request = _download_document_request(_DOCUMENT_DOWNLOAD_URL).build() + document_response = _download_document_response(stream_name, data_format=data_format, compressed=True) + document_request_matcher = HttpRequestMatcher(document_request, minimum_number_of_expected_match=1) + http_mocker._matchers.append(document_request_matcher) + + http_mocker._mocker.get( + requests_mock.ANY, + additional_matcher=http_mocker._matches_wrapper(document_request_matcher), + response_list=[{"content": document_response.body, "status_code": document_response.status_code}], + ) + + output = self._read(stream_name, config()) + assert len(output.records) == DEFAULT_EXPECTED_NUMBER_OF_RECORDS + + @pytest.mark.parametrize(("stream_name", "data_format"), STREAMS) + @HttpMocker() + def test_given_http_status_500_then_200_when_create_report_then_retry_and_return_records( + self, stream_name: str, data_format: str, http_mocker: HttpMocker + ) -> None: + mock_auth(http_mocker) + http_mocker.post( + _create_report_request(stream_name).build(), + [response_with_status(status_code=HTTPStatus.INTERNAL_SERVER_ERROR), _create_report_response(_REPORT_ID)], + ) + http_mocker.get( + _check_report_status_request(_REPORT_ID).build(), + _check_report_status_response(stream_name, report_document_id=_REPORT_DOCUMENT_ID), + ) + http_mocker.get( + _get_document_download_url_request(_REPORT_DOCUMENT_ID).build(), + _get_document_download_url_response(_DOCUMENT_DOWNLOAD_URL, _REPORT_DOCUMENT_ID), + ) + http_mocker.get( + _download_document_request(_DOCUMENT_DOWNLOAD_URL).build(), + _download_document_response(stream_name, data_format=data_format), + ) + + output = self._read(stream_name, config()) + assert len(output.records) == DEFAULT_EXPECTED_NUMBER_OF_RECORDS + + @pytest.mark.parametrize(("stream_name", "data_format"), STREAMS) + @HttpMocker() + def test_given_http_status_500_then_200_when_retrieve_report_then_retry_and_return_records( + self, stream_name: str, data_format: str, http_mocker: HttpMocker + ) -> None: + mock_auth(http_mocker) + http_mocker.post(_create_report_request(stream_name).build(), _create_report_response(_REPORT_ID)) + http_mocker.get( + _check_report_status_request(_REPORT_ID).build(), + [ + response_with_status(status_code=HTTPStatus.INTERNAL_SERVER_ERROR), + _check_report_status_response(stream_name, report_document_id=_REPORT_DOCUMENT_ID), + ], + ) + http_mocker.get( + _get_document_download_url_request(_REPORT_DOCUMENT_ID).build(), + _get_document_download_url_response(_DOCUMENT_DOWNLOAD_URL, _REPORT_DOCUMENT_ID), + ) + http_mocker.get( + _download_document_request(_DOCUMENT_DOWNLOAD_URL).build(), + _download_document_response(stream_name, data_format=data_format), + ) + + output = self._read(stream_name, config()) + assert len(output.records) == DEFAULT_EXPECTED_NUMBER_OF_RECORDS + + @pytest.mark.parametrize(("stream_name", "data_format"), STREAMS) + @HttpMocker() + def test_given_http_status_500_then_200_when_get_document_url_then_retry_and_return_records( + self, stream_name: str, data_format: str, http_mocker: HttpMocker + ) -> None: + mock_auth(http_mocker) + http_mocker.post(_create_report_request(stream_name).build(), _create_report_response(_REPORT_ID)) + http_mocker.get( + _check_report_status_request(_REPORT_ID).build(), + _check_report_status_response(stream_name, report_document_id=_REPORT_DOCUMENT_ID), + ) + http_mocker.get( + _get_document_download_url_request(_REPORT_DOCUMENT_ID).build(), + [ + response_with_status(status_code=HTTPStatus.INTERNAL_SERVER_ERROR), + _get_document_download_url_response(_DOCUMENT_DOWNLOAD_URL, _REPORT_DOCUMENT_ID), + ], + ) + http_mocker.get( + _download_document_request(_DOCUMENT_DOWNLOAD_URL).build(), + _download_document_response(stream_name, data_format=data_format), + ) + + output = self._read(stream_name, config()) + assert len(output.records) == DEFAULT_EXPECTED_NUMBER_OF_RECORDS + + @pytest.mark.parametrize(("stream_name", "data_format"), STREAMS) + @HttpMocker() + def test_given_http_status_500_then_200_when_download_document_then_retry_and_return_records( + self, stream_name: str, data_format: str, http_mocker: HttpMocker + ) -> None: + mock_auth(http_mocker) + http_mocker.post(_create_report_request(stream_name).build(), _create_report_response(_REPORT_ID)) + http_mocker.get( + _check_report_status_request(_REPORT_ID).build(), + _check_report_status_response(stream_name, report_document_id=_REPORT_DOCUMENT_ID), + ) + http_mocker.get( + _get_document_download_url_request(_REPORT_DOCUMENT_ID).build(), + _get_document_download_url_response(_DOCUMENT_DOWNLOAD_URL, _REPORT_DOCUMENT_ID), + ) + http_mocker.get( + _download_document_request(_DOCUMENT_DOWNLOAD_URL).build(), + [ + response_with_status(status_code=HTTPStatus.INTERNAL_SERVER_ERROR), + _download_document_response(stream_name, data_format=data_format), + ], + ) + + output = self._read(stream_name, config()) + assert len(output.records) == DEFAULT_EXPECTED_NUMBER_OF_RECORDS + + @pytest.mark.parametrize(("stream_name", "data_format"), STREAMS) + @HttpMocker() + def test_given_report_access_forbidden_when_read_then_no_records_and_error_logged( + self, stream_name: str, data_format: str, http_mocker: HttpMocker + ) -> None: + mock_auth(http_mocker) + + http_mocker.post( + _create_report_request(stream_name).build(), response_with_status(status_code=HTTPStatus.FORBIDDEN) + ) + + output = self._read(stream_name, config()) + message_on_access_forbidden = ( + "This is most likely due to insufficient permissions on the credentials in use. " + "Try to grant required permissions/scopes or re-authenticate." + ) + assert_message_in_log_output(message_on_access_forbidden, output) + assert len(output.records) == 0 + + @pytest.mark.parametrize(("stream_name", "data_format"), STREAMS) + @HttpMocker() + def test_given_report_status_cancelled_when_read_then_stream_completed_successfully_and_warn_about_cancellation( + self, stream_name: str, data_format: str, http_mocker: HttpMocker + ) -> None: + mock_auth(http_mocker) + + http_mocker.post(_create_report_request(stream_name).build(), _create_report_response(_REPORT_ID)) + http_mocker.get( + _check_report_status_request(_REPORT_ID).build(), + _check_report_status_response(stream_name, processing_status=ReportProcessingStatus.CANCELLED), + ) + + message_on_report_cancelled = ( + f"The report for stream '{stream_name}' was cancelled or there is no data to return." + ) + + output = self._read(stream_name, config()) + assert_message_in_log_output(message_on_report_cancelled, output) + assert len(output.records) == 0 + + @pytest.mark.parametrize(("stream_name", "data_format"), STREAMS) + @HttpMocker() + def test_given_report_status_fatal_when_read_then_exception_raised( + self, stream_name: str, data_format: str, http_mocker: HttpMocker + ) -> None: + mock_auth(http_mocker) + + http_mocker.post(_create_report_request(stream_name).build(), _create_report_response(_REPORT_ID)) + http_mocker.get( + _check_report_status_request(_REPORT_ID).build(), + _check_report_status_response(stream_name, processing_status=ReportProcessingStatus.FATAL), + ) + + output = self._read(stream_name, config(), expecting_exception=True) + assert output.errors[-1].trace.error.failure_type == FailureType.system_error + assert output.errors[-1].trace.error.internal_message == ( + f"Failed to retrieve the report '{stream_name}' for period {CONFIG_START_DATE}-{CONFIG_END_DATE} " + "due to Amazon Seller Partner platform issues. This will be read during the next sync." + ) + + @pytest.mark.parametrize( + ("stream_name", "date_field", "expected_date_value"), + ( + ("GET_SELLER_FEEDBACK_DATA", "date", "2020-10-20"), + ("GET_LEDGER_DETAIL_VIEW_DATA", "Date", "2021-11-21"), + ("GET_LEDGER_SUMMARY_VIEW_DATA", "Date", "2022-12-22"), + ), + ) + @HttpMocker() + def test_given_report_with_incorrect_date_format_when_read_then_formatted( + self, stream_name: str, date_field: str, expected_date_value: str, http_mocker: HttpMocker + ) -> None: + mock_auth(http_mocker) + + http_mocker.post(_create_report_request(stream_name).build(), _create_report_response(_REPORT_ID)) + http_mocker.get( + _check_report_status_request(_REPORT_ID).build(), + _check_report_status_response(stream_name, report_document_id=_REPORT_DOCUMENT_ID), + ) + http_mocker.get( + _get_document_download_url_request(_REPORT_DOCUMENT_ID).build(), + _get_document_download_url_response(_DOCUMENT_DOWNLOAD_URL, _REPORT_DOCUMENT_ID), + ) + http_mocker.get( + _download_document_request(_DOCUMENT_DOWNLOAD_URL).build(), _download_document_response(stream_name) + ) + + output = self._read(stream_name, config()) + assert len(output.records) == DEFAULT_EXPECTED_NUMBER_OF_RECORDS + assert output.records[0].record.data.get(date_field) == expected_date_value + + @pytest.mark.parametrize(("stream_name", "data_format"), STREAMS) + @HttpMocker() + def test_given_http_error_500_on_create_report_when_read_then_no_records_and_error_logged( + self, stream_name: str, data_format: str, http_mocker: HttpMocker + ) -> None: + mock_auth(http_mocker) + + http_mocker.post( + _create_report_request(stream_name).build(), + response_with_status(status_code=HTTPStatus.INTERNAL_SERVER_ERROR), + ) + + message_on_backoff_exception = ( + f"The report for stream '{stream_name}' was cancelled due to several failed retry attempts." + ) + + output = self._read(stream_name, config()) + assert_message_in_log_output(message_on_backoff_exception, output) + assert len(output.records) == 0 + + +@freezegun.freeze_time(NOW.isoformat()) +class TestIncremental: + default_cursor_field = "dataEndTime" + + @staticmethod + def _read( + stream_name: str, + config_: ConfigBuilder, + state: Optional[List[AirbyteStateMessage]] = None, + expecting_exception: bool = False, + ) -> EntrypointOutput: + return read_output( + config_builder=config_, + stream_name=stream_name, + sync_mode=SyncMode.incremental, + state=state, + expecting_exception=expecting_exception, + ) + + @pytest.mark.parametrize(("stream_name", "data_format"), STREAMS) + @HttpMocker() + def test_given_report_when_read_then_default_cursor_field_added_to_every_record( + self, stream_name: str, data_format: str, http_mocker: HttpMocker + ) -> None: + mock_auth(http_mocker) + + http_mocker.post(_create_report_request(stream_name).build(), _create_report_response(_REPORT_ID)) + http_mocker.get( + _check_report_status_request(_REPORT_ID).build(), + _check_report_status_response(stream_name, report_document_id=_REPORT_DOCUMENT_ID), + ) + http_mocker.get( + _get_document_download_url_request(_REPORT_DOCUMENT_ID).build(), + _get_document_download_url_response(_DOCUMENT_DOWNLOAD_URL, _REPORT_DOCUMENT_ID), + ) + http_mocker.get( + _download_document_request(_DOCUMENT_DOWNLOAD_URL).build(), + _download_document_response(stream_name, data_format=data_format), + ) + + output = self._read(stream_name, config()) + assert all([self.default_cursor_field in record.record.data for record in output.records]) + + @pytest.mark.parametrize(("stream_name", "data_format"), STREAMS) + @HttpMocker() + def test_given_report_when_read_then_state_message_produced_and_state_match_latest_record( + self, stream_name: str, data_format: str, http_mocker: HttpMocker + ) -> None: + _config = config() + mock_auth(http_mocker) + + http_mocker.post(_create_report_request(stream_name).build(), _create_report_response(_REPORT_ID)) + http_mocker.get( + _check_report_status_request(_REPORT_ID).build(), + _check_report_status_response(stream_name, report_document_id=_REPORT_DOCUMENT_ID), + ) + http_mocker.get( + _get_document_download_url_request(_REPORT_DOCUMENT_ID).build(), + _get_document_download_url_response(_DOCUMENT_DOWNLOAD_URL, _REPORT_DOCUMENT_ID), + ) + http_mocker.get( + _download_document_request(_DOCUMENT_DOWNLOAD_URL).build(), + _download_document_response(stream_name, data_format=data_format), + ) + + output = self._read(stream_name, _config) + assert len(output.state_messages) == 1 + + cursor_field = get_stream_by_name(stream_name, _config.build()).cursor_field + cursor_value_from_state_message = output.most_recent_state.get(stream_name, {}).get(cursor_field) + cursor_value_from_latest_record = output.records[-1].record.data.get(cursor_field) + assert cursor_value_from_state_message == cursor_value_from_latest_record diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/test_vendor_direct_fulfillment_shipping.py b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/test_vendor_direct_fulfillment_shipping.py new file mode 100644 index 000000000000..f267a106ddfc --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/test_vendor_direct_fulfillment_shipping.py @@ -0,0 +1,206 @@ +# +# Copyright (c) 2024 Airbyte, Inc., all rights reserved. +# + + +from http import HTTPStatus +from typing import List, Optional + +import freezegun +from airbyte_cdk.test.entrypoint_wrapper import EntrypointOutput +from airbyte_cdk.test.mock_http import HttpMocker +from airbyte_cdk.test.mock_http.response_builder import ( + FieldPath, + HttpResponseBuilder, + NestedPath, + RecordBuilder, + create_record_builder, + create_response_builder, + find_template, +) +from airbyte_cdk.test.state_builder import StateBuilder +from airbyte_protocol.models import AirbyteStateMessage, FailureType, SyncMode + +from .config import NOW, ConfigBuilder +from .pagination import NEXT_TOKEN_STRING, VendorDirectFulfillmentShippingPaginationStrategy +from .request_builder import RequestBuilder +from .response_builder import response_with_status +from .utils import config, mock_auth, read_output + +_STREAM_NAME = "VendorDirectFulfillmentShipping" +_TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ" + + +def _vendor_direct_fulfillment_shipping_request() -> RequestBuilder: + return RequestBuilder.vendor_direct_fulfillment_shipping_endpoint() + + +def _vendor_direct_fulfillment_shipping_response() -> HttpResponseBuilder: + return create_response_builder( + find_template(_STREAM_NAME, __file__), + NestedPath(["payload", "shippingLabels"]), + pagination_strategy=VendorDirectFulfillmentShippingPaginationStrategy(), + ) + + +def _a_shipping_label_record() -> RecordBuilder: + return create_record_builder( + response_template=find_template(_STREAM_NAME, __file__), + records_path=NestedPath(["payload", "shippingLabels"]), + record_id_path=FieldPath("purchaseOrderNumber"), + ) + + +@freezegun.freeze_time(NOW.isoformat()) +class TestFullRefresh: + + @staticmethod + def _read(config_: ConfigBuilder, expecting_exception: bool = False) -> EntrypointOutput: + return read_output( + config_builder=config_, + stream_name=_STREAM_NAME, + sync_mode=SyncMode.full_refresh, + expecting_exception=expecting_exception, + ) + + @HttpMocker() + def test_given_one_page_when_read_then_return_records(self, http_mocker: HttpMocker) -> None: + mock_auth(http_mocker) + http_mocker.get( + _vendor_direct_fulfillment_shipping_request().build(), + _vendor_direct_fulfillment_shipping_response().with_record(_a_shipping_label_record()).build(), + ) + output = self._read(config()) + assert len(output.records) == 1 + + @HttpMocker() + def test_given_two_pages_when_read_then_return_records(self, http_mocker: HttpMocker) -> None: + mock_auth(http_mocker) + http_mocker.get( + _vendor_direct_fulfillment_shipping_request().build(), + _vendor_direct_fulfillment_shipping_response().with_pagination().with_record( + _a_shipping_label_record() + ).build(), + ) + query_params_with_next_page_token = {"nextToken": NEXT_TOKEN_STRING} + http_mocker.get( + _vendor_direct_fulfillment_shipping_request().with_query_params(query_params_with_next_page_token).build(), + _vendor_direct_fulfillment_shipping_response().with_record(_a_shipping_label_record()).with_record( + _a_shipping_label_record() + ).build(), + ) + output = self._read(config()) + assert len(output.records) == 3 + + @HttpMocker() + def test_given_http_status_500_then_200_when_read_then_retry_and_return_records( + self, http_mocker: HttpMocker + ) -> None: + mock_auth(http_mocker) + http_mocker.get( + _vendor_direct_fulfillment_shipping_request().build(), + [ + response_with_status(status_code=HTTPStatus.INTERNAL_SERVER_ERROR), + _vendor_direct_fulfillment_shipping_response().with_record(_a_shipping_label_record()).build(), + ], + ) + output = self._read(config()) + assert len(output.records) == 1 + + @HttpMocker() + def test_given_http_status_500_on_availability_when_read_then_raise_system_error( + self, http_mocker: HttpMocker + ) -> None: + mock_auth(http_mocker) + http_mocker.get( + _vendor_direct_fulfillment_shipping_request().build(), + response_with_status(status_code=HTTPStatus.INTERNAL_SERVER_ERROR), + ) + output = self._read(config(), expecting_exception=True) + assert output.errors[-1].trace.error.failure_type == FailureType.system_error + + +@freezegun.freeze_time(NOW.isoformat()) +class TestIncremental: + cursor_field = "createdBefore" + replication_start_date = NOW.subtract(days=3) + replication_end_date = NOW + + @staticmethod + def _read( + config_: ConfigBuilder, state: Optional[List[AirbyteStateMessage]] = None, expecting_exception: bool = False + ) -> EntrypointOutput: + return read_output( + config_builder=config_, + stream_name=_STREAM_NAME, + sync_mode=SyncMode.incremental, + state=state, + expecting_exception=expecting_exception, + ) + + @HttpMocker() + def test_when_read_then_add_cursor_field(self, http_mocker: HttpMocker) -> None: + mock_auth(http_mocker) + http_mocker.get( + _vendor_direct_fulfillment_shipping_request().build(), + _vendor_direct_fulfillment_shipping_response().with_record(_a_shipping_label_record()).build(), + ) + + output = self._read( + config().with_start_date(self.replication_start_date).with_end_date(self.replication_end_date) + ) + + expected_cursor_value = self.replication_end_date.strftime(_TIME_FORMAT) + assert output.records[0].record.data[self.cursor_field] == expected_cursor_value + + @HttpMocker() + def test_when_read_then_state_message_produced_and_state_match_latest_record(self, http_mocker: HttpMocker) -> None: + mock_auth(http_mocker) + http_mocker.get( + _vendor_direct_fulfillment_shipping_request().build(), + _vendor_direct_fulfillment_shipping_response().with_record(_a_shipping_label_record()).with_record( + _a_shipping_label_record() + ).build(), + ) + + output = self._read( + config().with_start_date(self.replication_start_date).with_end_date(self.replication_end_date) + ) + assert len(output.state_messages) == 1 + + cursor_value_from_state_message = output.most_recent_state.get(_STREAM_NAME, {}).get(self.cursor_field) + cursor_value_from_latest_record = output.records[-1].record.data.get(self.cursor_field) + assert cursor_value_from_state_message == cursor_value_from_latest_record + + @HttpMocker() + def test_given_state_when_read_then_state_value_is_created_after_query_param(self, http_mocker: HttpMocker) -> None: + mock_auth(http_mocker) + state_value = self.replication_start_date.add(days=1).strftime(_TIME_FORMAT) + + query_params_first_read = { + "createdAfter": self.replication_start_date.strftime(_TIME_FORMAT), + self.cursor_field: self.replication_end_date.strftime(_TIME_FORMAT), + } + query_params_incremental_read = { + "createdAfter": state_value, self.cursor_field: self.replication_end_date.strftime(_TIME_FORMAT) + } + + http_mocker.get( + _vendor_direct_fulfillment_shipping_request().with_query_params(query_params_first_read).build(), + _vendor_direct_fulfillment_shipping_response().with_record(_a_shipping_label_record()).with_record( + _a_shipping_label_record() + ).build(), + ) + http_mocker.get( + _vendor_direct_fulfillment_shipping_request().with_query_params(query_params_incremental_read).build(), + _vendor_direct_fulfillment_shipping_response().with_record(_a_shipping_label_record()).with_record( + _a_shipping_label_record() + ).build(), + ) + output = self._read( + config_=config().with_start_date(self.replication_start_date).with_end_date(self.replication_end_date), + state=StateBuilder().with_stream_state(_STREAM_NAME, {self.cursor_field: state_value}).build(), + ) + assert output.most_recent_state == { + _STREAM_NAME: {self.cursor_field: self.replication_end_date.strftime(_TIME_FORMAT)} + } diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/utils.py b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/utils.py new file mode 100644 index 000000000000..58de04a90a9c --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/utils.py @@ -0,0 +1,77 @@ +# +# Copyright (c) 2024 Airbyte, Inc., all rights reserved. +# + + +import json +from http import HTTPStatus +from typing import Any, List, Mapping, Optional + +from airbyte_cdk.sources.streams import Stream +from airbyte_cdk.test.catalog_builder import CatalogBuilder +from airbyte_cdk.test.entrypoint_wrapper import EntrypointOutput, read +from airbyte_cdk.test.mock_http import HttpMocker +from airbyte_cdk.test.mock_http.response_builder import _get_unit_test_folder +from airbyte_protocol.models import AirbyteStateMessage, ConfiguredAirbyteCatalog, Level, SyncMode +from source_amazon_seller_partner import SourceAmazonSellerPartner + +from .config import ACCESS_TOKEN, ConfigBuilder +from .request_builder import RequestBuilder +from .response_builder import build_response + + +def config() -> ConfigBuilder: + return ConfigBuilder() + + +def catalog(stream_name: str, sync_mode: SyncMode) -> ConfiguredAirbyteCatalog: + return CatalogBuilder().with_stream(stream_name, sync_mode).build() + + +def source() -> SourceAmazonSellerPartner: + return SourceAmazonSellerPartner() + + +def read_output( + config_builder: ConfigBuilder, + stream_name: str, + sync_mode: SyncMode, + state: Optional[List[AirbyteStateMessage]] = None, + expecting_exception: Optional[bool] = False, +) -> EntrypointOutput: + _catalog = catalog(stream_name, sync_mode) + _config = config_builder.build() + return read(source(), _config, _catalog, state, expecting_exception) + + +def get_stream_by_name(stream_name: str, config_: Mapping[str, Any]) -> Stream: + streams = [stream for stream in source().streams(config_) if stream.name == stream_name] + if not streams: + raise ValueError("Please provide a valid stream name") + return streams[0] + + +def find_template(resource: str, execution_folder: str, template_format: Optional[str] = "csv") -> str: + response_template_filepath = str( + _get_unit_test_folder(execution_folder) / "resource" / "http" / "response" / f"{resource}.{template_format}" + ) + with open(response_template_filepath, "r") as template_file: + if template_file == "json": + return json.load(template_file) + else: + return template_file.read() + + +def mock_auth(http_mocker: HttpMocker) -> None: + response_body = {"access_token": ACCESS_TOKEN, "expires_in": 3600, "token_type": "bearer"} + http_mocker.post(RequestBuilder.auth_endpoint().build(), build_response(response_body, status_code=HTTPStatus.OK)) + + +def assert_message_in_log_output( + message: str, entrypoint_output: EntrypointOutput, log_level: Optional[Level] = Level.WARN +) -> None: + assert any( + message in airbyte_message.log.message + for airbyte_message in entrypoint_output.logs + if airbyte_message.log.level == log_level + ) diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_AFN_INVENTORY_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_AFN_INVENTORY_DATA.csv new file mode 100644 index 000000000000..3d90f23a5731 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_AFN_INVENTORY_DATA.csv @@ -0,0 +1,3 @@ +seller-sku fulfillment-channel-sku asin condition-type Warehouse-Condition-code Quantity Available +seller-sku-1 fulfillment-channel-sku-1 asin-1 condition-type-1 Warehouse-Condition-code-1 11 +seller-sku-1 fulfillment-channel-sku-2 asin-2 condition-type-2 Warehouse-Condition-code-2 22 diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_AFN_INVENTORY_DATA_BY_COUNTRY.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_AFN_INVENTORY_DATA_BY_COUNTRY.csv new file mode 100644 index 000000000000..73b819c535e3 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_AFN_INVENTORY_DATA_BY_COUNTRY.csv @@ -0,0 +1,3 @@ +seller-sku fulfillment-channel-sku asin condition-type country quantity-for-local-fulfillment +seller-sku-1 fulfillment-channel-sku-1 asin-1 condition-type-1 11 +seller-sku-2 fulfillment-channel-sku-2 asin-2 condition-type-1 22 diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_AMAZON_FULFILLED_SHIPMENTS_DATA_GENERAL.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_AMAZON_FULFILLED_SHIPMENTS_DATA_GENERAL.csv new file mode 100644 index 000000000000..e22e1ed5b267 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_AMAZON_FULFILLED_SHIPMENTS_DATA_GENERAL.csv @@ -0,0 +1,3 @@ +amazon-order-id merchant-order-id shipment-id shipment-item-id amazon-order-item-id merchant-order-item-id purchase-date payments-date shipment-date reporting-date buyer-email buyer-name buyer-phone-number sku product-name quantity-shipped currency item-price item-tax shipping-price shipping-tax gift-wrap-price gift-wrap-tax ship-service-level recipient-name ship-address-1 ship-address-2 ship-address-3 ship-city ship-state ship-postal-code ship-country ship-phone-number bill-address-1 bill-address-2 bill-address-3 bill-city bill-state bill-postal-code bill-country item-promotion-discount ship-promotion-discount carrier tracking-number estimated-arrival-date fulfillment-center-id fulfillment-channel sales-channel +amazon-order-id-1 merchant-order-id-1 shipment-id shipment-item-id-1 amazon-order-item-id-1 merchant-order-item-id-1 2022-07-05T08:09:12-07:00 2022-07-05T08:09:12-07:00 2022-07-05T08:09:12-07:00 2022-07-05T08:09:12-07:00 buyer-email-1 buyer-name-1 buyer-phone-number-1 sku-1 product-name-1 11 USD 111.0 10 12.00 15.99 16.99 0 ship-service-level-1 recipient-name-1 ship-address-1-1 ship-address-2-1 ship-address-3-1 ship-city-1 ship-state-1 ship-postal-code-1 ship-country-1 ship-phone-number-1 bill-address-1-1 bill-address-2-1 bill-address-3-1 bill-city-1 bill-state-1 bill-postal-code-1 bill-country-1 0.0 0.0 carrier-1 tracking-number-1 2022-07-05T08:09:12-07:00 fulfillment-center-id-1 fulfillment-channel sales-channel-1 +amazon-order-id-2 merchant-order-id-2 shipment-id shipment-item-id-2 amazon-order-item-id-2 merchant-order-item-id-2 2022-07-05T08:09:12-07:00 2022-07-05T08:09:12-07:00 2022-07-05T08:09:12-07:00 2022-07-05T08:09:12-07:00 buyer-email-2 buyer-name-2 buyer-phone-number-2 sku-2 product-name-2 22 CAD 222.0 20 25.00 15.99 16.99 0 ship-service-level-2 recipient-name-2 ship-address-1-2 ship-address-2-2 ship-address-3-2 ship-city-2 ship-state-2 ship-postal-code-2 ship-country-2 ship-phone-number-2 bill-address-1-2 bill-address-2-2 bill-address-3-2 bill-city-2 bill-state-2 bill-postal-code-2 bill-country-2 0.0 0.0 carrier-2 tracking-number-2 2022-07-05T08:09:12-07:00 fulfillment-center-id-2 fulfillment-channel sales-channel-2 diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_BRAND_ANALYTICS_MARKET_BASKET_REPORT.json b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_BRAND_ANALYTICS_MARKET_BASKET_REPORT.json new file mode 100644 index 000000000000..3e5ab5a52328 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_BRAND_ANALYTICS_MARKET_BASKET_REPORT.json @@ -0,0 +1,29 @@ +{ + "reportSpecification": { + "reportType": "GET_BRAND_ANALYTICS_MARKET_BASKET_REPORT", + "reportOptions": { + "reportPeriod": "WEEK" + }, + "dataStartTime": "2021-06-06", + "dataEndTime": "2021-06-19", + "marketplaceIds": ["ATVPDKIKX0DER"] + }, + "dataByAsin": [ + { + "startDate": "2021-06-06", + "endDate": "2021-06-12", + "asin": "B123456789", + "purchasedWithAsin": "B1A345B78C", + "purchasedWithRank": 1, + "combinationPct": 0.028 + }, + { + "startDate": "2021-06-06", + "endDate": "2021-06-12", + "asin": "B123456789", + "purchasedWithAsin": "B1D345E78F", + "purchasedWithRank": 2, + "combinationPct": 0.0229 + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_BRAND_ANALYTICS_REPEAT_PURCHASE_REPORT.json b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_BRAND_ANALYTICS_REPEAT_PURCHASE_REPORT.json new file mode 100644 index 000000000000..ff52ea200bbc --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_BRAND_ANALYTICS_REPEAT_PURCHASE_REPORT.json @@ -0,0 +1,39 @@ +{ + "reportSpecification": { + "reportType": "GET_BRAND_ANALYTICS_REPEAT_PURCHASE_REPORT", + "reportOptions": { + "reportPeriod": "WEEK" + }, + "dataStartTime": "2021-06-06", + "dataEndTime": "2021-06-19", + "marketplaceIds": ["ATVPDKIKX0DER"] + }, + "dataByAsin": [ + { + "startDate": "2021-06-06", + "endDate": "2021-06-12", + "asin": "B123456789", + "orders": 1256, + "uniqueCustomers": 1201, + "repeatCustomersPctTotal": 0.0083, + "repeatPurchaseRevenue": { + "amount": 2246.13, + "currencyCode": "USD" + }, + "repeatPurchaseRevenuePctTotal": 0.0217 + }, + { + "startDate": "2021-06-06", + "endDate": "2021-06-12", + "asin": "B234567890", + "orders": 2561, + "uniqueCustomers": 43, + "repeatCustomersPctTotal": 0.1234, + "repeatPurchaseRevenue": { + "amount": 1234.56, + "currencyCode": "USD" + }, + "repeatPurchaseRevenuePctTotal": 0.0465 + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_BRAND_ANALYTICS_SEARCH_TERMS_REPORT.json b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_BRAND_ANALYTICS_SEARCH_TERMS_REPORT.json new file mode 100644 index 000000000000..d0579b35ba2f --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_BRAND_ANALYTICS_SEARCH_TERMS_REPORT.json @@ -0,0 +1,31 @@ +{ + "reportSpecification": { + "reportType": "GET_BRAND_ANALYTICS_SEARCH_TERMS_REPORT", + "reportOptions": { + "reportPeriod": "WEEK" + }, + "dataStartTime": "2021-06-06", + "dataEndTime": "2021-06-12", + "marketplaceIds": ["ATVPDKIKX0DER"] + }, + "dataByDepartmentAndSearchTerm": [ + { + "departmentName": "Amazon.com", + "searchTerm": "search term rank one", + "searchFrequencyRank": 1, + "clickedAsin": "B123456789", + "clickShareRank": 1, + "clickShare": 0.0771, + "conversionShare": 0.0874 + }, + { + "departmentName": "Amazon.com", + "searchTerm": "search term rank one", + "searchFrequencyRank": 1, + "clickedAsin": "B987654321", + "clickShareRank": 2, + "clickShare": 0.0726, + "conversionShare": 0.0974 + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_ESTIMATED_FBA_FEES_TXT_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_ESTIMATED_FBA_FEES_TXT_DATA.csv new file mode 100644 index 000000000000..404688f64a25 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_ESTIMATED_FBA_FEES_TXT_DATA.csv @@ -0,0 +1,3 @@ +sku fnsku asin product-name product-group brand fulfilled-by has-local-inventory your-price sales-price longest-side median-side shortest-side length-and-girth unit-of-dimension item-package-weight unit-of-weight product-size-weight-band currency estimated-fee-total estimated-referral-fee-per-unit estimated-variable-closing-fee expected-domestic-fulfilment-fee-per-unit expected-efn-fulfilment-fee-per-unit-uk expected-efn-fulfilment-fee-per-unit-de expected-efn-fulfilment-fee-per-unit-fr expected-efn-fulfilment-fee-per-unit-it expected-efn-fulfilment-fee-per-unit-es expected-efn-fulfilment-fee-per-unit-se +sku-1 fnsku-1 asin-1 product-name-1 product-group-1 brand-1 fulfilled-by-1 false 111.0 112.0 10 9 8 10 MM 11 LB product-size-weight-band-1 USD 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +sku-2 fnsku-2 asin-2 product-name-2 product-group-2 brand-2 fulfilled-by-2 false 222.0 223.0 20 19 18 20 MM 22 KG product-size-weight-band-2 CAD 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_FULFILLMENT_CUSTOMER_RETURNS_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_FULFILLMENT_CUSTOMER_RETURNS_DATA.csv new file mode 100644 index 000000000000..882e088d079b --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_FULFILLMENT_CUSTOMER_RETURNS_DATA.csv @@ -0,0 +1,3 @@ +return-date order-id sku asin fnsku product-name quantity fulfillment-center-id detailed-disposition reason status license-plate-number customer-comments +return-date order-id sku asin fnsku product-name quantity fulfillment-center-id detailed-disposition reason status license-plate-number customer-comments +return-date order-id sku asin fnsku product-name quantity fulfillment-center-id detailed-disposition reason status license-plate-number customer-comments diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_PROMOTION_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_PROMOTION_DATA.csv new file mode 100644 index 000000000000..998dc7477725 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_PROMOTION_DATA.csv @@ -0,0 +1,3 @@ +shipment-date currency item-promotion-discount item-promotion-id description promotion-rule-value amazon-order-id shipment-id shipment-item-id +shipment-date currency item-promotion-discount item-promotion-id description promotion-rule-value amazon-order-id shipment-id shipment-item-id +shipment-date currency item-promotion-discount item-promotion-id description promotion-rule-value amazon-order-id shipment-id shipment-item-id diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_REPLACEMENT_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_REPLACEMENT_DATA.csv new file mode 100644 index 000000000000..ad5ee9b9902c --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_REPLACEMENT_DATA.csv @@ -0,0 +1,3 @@ +shipment-date sku asin fulfillment-center-id original-fulfillment-center-id quantity replacement-reason-code replacement-amazon-order-id original-amazon-order-id +shipment-date sku asin fulfillment-center-id original-fulfillment-center-id quantity replacement-reason-code replacement-amazon-order-id original-amazon-order-id +shipment-date sku asin fulfillment-center-id original-fulfillment-center-id quantity replacement-reason-code replacement-amazon-order-id original-amazon-order-id diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_FULFILLMENT_REMOVAL_ORDER_DETAIL_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_FULFILLMENT_REMOVAL_ORDER_DETAIL_DATA.csv new file mode 100644 index 000000000000..152f07f84f5d --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_FULFILLMENT_REMOVAL_ORDER_DETAIL_DATA.csv @@ -0,0 +1,3 @@ +request-date order-id order-type service-speed order-status last-updated-date sku fnsku disposition requested-quantity cancelled-quantity disposed-quantity shipped-quantity in-process-quantity removal-fee currency +request-date order-id order-type service-speed order-status last-updated-date sku fnsku disposition requested-quantity cancelled-quantity disposed-quantity shipped-quantity in-process-quantity removal-fee currency +request-date order-id order-type service-speed order-status last-updated-date sku fnsku disposition requested-quantity cancelled-quantity disposed-quantity shipped-quantity in-process-quantity removal-fee currency diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_FULFILLMENT_REMOVAL_SHIPMENT_DETAIL_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_FULFILLMENT_REMOVAL_SHIPMENT_DETAIL_DATA.csv new file mode 100644 index 000000000000..96f6732ebb9a --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_FULFILLMENT_REMOVAL_SHIPMENT_DETAIL_DATA.csv @@ -0,0 +1,3 @@ +request-date order-id shipment-date sku fnsku disposition shipped-quantity carrier tracking-number removal-order-type +request-date order-id shipment-date sku fnsku disposition shipped-quantity carrier tracking-number removal-order-type +request-date order-id shipment-date sku fnsku disposition shipped-quantity carrier tracking-number removal-order-type diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_INVENTORY_PLANNING_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_INVENTORY_PLANNING_DATA.csv new file mode 100644 index 000000000000..1ec5e6746a3a --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_INVENTORY_PLANNING_DATA.csv @@ -0,0 +1,3 @@ +snapshot-date sku fnsku asin product-name condition available pending-removal-quantity inv-age-0-to-90-days inv-age-91-to-180-days inv-age-181-to-270-days inv-age-271-to-365-days inv-age-365-plus-days currency qty-to-be-charged-ltsf-11-mo projected-ltsf-11-mo qty-to-be-charged-ltsf-12-mo estimated-ltsf-next-charge units-shipped-t7 units-shipped-t30 units-shipped-t60 units-shipped-t90 alert your-price sales-price lowest-price-new-plus-shipping lowest-price-used recommended-action healthy-inventory-level recommended-sales-price recommended-sale-duration-days recommended-removal-quantity estimated-cost-savings-of-recommended-actions sell-through item-volume volume-unit-measurement storage-type storage-volume marketplace product-group sales-rank days-of-supply estimated-excess-quantity weeks-of-cover-t30 weeks-of-cover-t90 featuredoffer-price sales-shipped-last-7-days sales-shipped-last-30-days sales-shipped-last-60-days sales-shipped-last-90-days inv-age-0-to-30-days inv-age-31-to-60-days inv-age-61-to-90-days inv-age-181-to-330-days inv-age-331-to-365-days estimated-storage-cost-next-month inbound-quantity inbound-working inbound-shipped inbound-received no-sale-last-6-months reserved-quantity unfulfillable-quantity +snapshot-date sku fnsku asin product-name condition available pending-removal-quantity inv-age-0-to-90-days inv-age-91-to-180-days inv-age-181-to-270-days inv-age-271-to-365-days inv-age-365-plus-days currency qty-to-be-charged-ltsf-11-mo projected-ltsf-11-mo qty-to-be-charged-ltsf-12-mo estimated-ltsf-next-charge units-shipped-t7 units-shipped-t30 units-shipped-t60 units-shipped-t90 alert your-price sales-price lowest-price-new-plus-shipping lowest-price-used recommended-action healthy-inventory-level recommended-sales-price recommended-sale-duration-days recommended-removal-quantity estimated-cost-savings-of-recommended-actions sell-through item-volume volume-unit-measurement storage-type storage-volume marketplace product-group sales-rank days-of-supply estimated-excess-quantity weeks-of-cover-t30 weeks-of-cover-t90 featuredoffer-price sales-shipped-last-7-days sales-shipped-last-30-days sales-shipped-last-60-days sales-shipped-last-90-days inv-age-0-to-30-days inv-age-31-to-60-days inv-age-61-to-90-days inv-age-181-to-330-days inv-age-331-to-365-days estimated-storage-cost-next-month inbound-quantity inbound-working inbound-shipped inbound-received no-sale-last-6-months reserved-quantity unfulfillable-quantity +snapshot-date sku fnsku asin product-name condition available pending-removal-quantity inv-age-0-to-90-days inv-age-91-to-180-days inv-age-181-to-270-days inv-age-271-to-365-days inv-age-365-plus-days currency qty-to-be-charged-ltsf-11-mo projected-ltsf-11-mo qty-to-be-charged-ltsf-12-mo estimated-ltsf-next-charge units-shipped-t7 units-shipped-t30 units-shipped-t60 units-shipped-t90 alert your-price sales-price lowest-price-new-plus-shipping lowest-price-used recommended-action healthy-inventory-level recommended-sales-price recommended-sale-duration-days recommended-removal-quantity estimated-cost-savings-of-recommended-actions sell-through item-volume volume-unit-measurement storage-type storage-volume marketplace product-group sales-rank days-of-supply estimated-excess-quantity weeks-of-cover-t30 weeks-of-cover-t90 featuredoffer-price sales-shipped-last-7-days sales-shipped-last-30-days sales-shipped-last-60-days sales-shipped-last-90-days inv-age-0-to-30-days inv-age-31-to-60-days inv-age-61-to-90-days inv-age-181-to-330-days inv-age-331-to-365-days estimated-storage-cost-next-month inbound-quantity inbound-working inbound-shipped inbound-received no-sale-last-6-months reserved-quantity unfulfillable-quantity diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_MYI_UNSUPPRESSED_INVENTORY_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_MYI_UNSUPPRESSED_INVENTORY_DATA.csv new file mode 100644 index 000000000000..039a6d93362f --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_MYI_UNSUPPRESSED_INVENTORY_DATA.csv @@ -0,0 +1,3 @@ +sku fnsku asin product-name condition your-price mfn-listing-exists mfn-fulfillable-quantity afn-listing-exists afn-warehouse-quantity afn-fulfillable-quantity afn-unsellable-quantity afn-reserved-quantity afn-total-quantity per-unit-volume afn-inbound-working-quantity afn-inbound-shipped-quantity afn-inbound-receiving-quantity afn-researching-quantity afn-reserved-future-supply afn-future-supply-buyable +sku fnsku asin product-name condition your-price mfn-listing-exists mfn-fulfillable-quantity afn-listing-exists afn-warehouse-quantity afn-fulfillable-quantity afn-unsellable-quantity afn-reserved-quantity afn-total-quantity per-unit-volume afn-inbound-working-quantity afn-inbound-shipped-quantity afn-inbound-receiving-quantity afn-researching-quantity afn-reserved-future-supply afn-future-supply-buyable +sku fnsku asin product-name condition your-price mfn-listing-exists mfn-fulfillable-quantity afn-listing-exists afn-warehouse-quantity afn-fulfillable-quantity afn-unsellable-quantity afn-reserved-quantity afn-total-quantity per-unit-volume afn-inbound-working-quantity afn-inbound-shipped-quantity afn-inbound-receiving-quantity afn-researching-quantity afn-reserved-future-supply afn-future-supply-buyable diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_REIMBURSEMENTS_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_REIMBURSEMENTS_DATA.csv new file mode 100644 index 000000000000..50b8dff481c4 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_REIMBURSEMENTS_DATA.csv @@ -0,0 +1,3 @@ +approval-date reimbursement-id case-id amazon-order-id reason sku fnsku asin product-name condition currency-unit amount-per-unit amount-total quantity-reimbursed-cash quantity-reimbursed-inventory quantity-reimbursed-total original-reimbursement-id original-reimbursement-type +approval-date reimbursement-id case-id amazon-order-id reason sku fnsku asin product-name condition currency-unit amount-per-unit amount-total quantity-reimbursed-cash quantity-reimbursed-inventory quantity-reimbursed-total original-reimbursement-id original-reimbursement-type +approval-date reimbursement-id case-id amazon-order-id reason sku fnsku asin product-name condition currency-unit amount-per-unit amount-total quantity-reimbursed-cash quantity-reimbursed-inventory quantity-reimbursed-total original-reimbursement-id original-reimbursement-type diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_SNS_FORECAST_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_SNS_FORECAST_DATA.csv new file mode 100644 index 000000000000..5e0a7eed1897 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_SNS_FORECAST_DATA.csv @@ -0,0 +1,3 @@ +offer-state snapshot-date sku fnsku asin estimated-avg-sns-discount-next-8-weeks product-name country active-subscriptions week-1-start-date scheduled-sns-units-week-1 scheduled-sns-units-week-2 scheduled-sns-units-week-3 scheduled-sns-units-week-4 scheduled-sns-units-week-5 scheduled-sns-units-week-6 scheduled-sns-units-week-7 scheduled-sns-units-week-8 +offer-state snapshot-date sku fnsku asin estimated-avg-sns-discount-next-8-weeks product-name country active-subscriptions week-1-start-date scheduled-sns-units-week-1 scheduled-sns-units-week-2 scheduled-sns-units-week-3 scheduled-sns-units-week-4 scheduled-sns-units-week-5 scheduled-sns-units-week-6 scheduled-sns-units-week-7 scheduled-sns-units-week-8 +offer-state snapshot-date sku fnsku asin estimated-avg-sns-discount-next-8-weeks product-name country active-subscriptions week-1-start-date scheduled-sns-units-week-1 scheduled-sns-units-week-2 scheduled-sns-units-week-3 scheduled-sns-units-week-4 scheduled-sns-units-week-5 scheduled-sns-units-week-6 scheduled-sns-units-week-7 scheduled-sns-units-week-8 diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_SNS_PERFORMANCE_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_SNS_PERFORMANCE_DATA.csv new file mode 100644 index 000000000000..1d3f83abf13f --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_SNS_PERFORMANCE_DATA.csv @@ -0,0 +1,3 @@ +offer-state snapshot-date sku fnsku asin product-name country week-1-start-date sns-units-shipped-week-1 oos-rate-week-1 sns-sale-price-week-1 sns-discount-week-1 sns-units-shipped-week-2 oos-rate-week-2 sns-sale-price-week-2 sns-discount-week-2 sns-units-shipped-week-3 oos-rate-week-3 sns-sale-price-week-3 sns-discount-week-3 sns-units-shipped-week-4 oos-rate-week-4 sns-sale-price-week-4 sns-discount-week-4 +offer-state snapshot-date sku fnsku asin product-name country week-1-start-date sns-units-shipped-week-1 oos-rate-week-1 sns-sale-price-week-1 sns-discount-week-1 sns-units-shipped-week-2 oos-rate-week-2 sns-sale-price-week-2 sns-discount-week-2 sns-units-shipped-week-3 oos-rate-week-3 sns-sale-price-week-3 sns-discount-week-3 sns-units-shipped-week-4 oos-rate-week-4 sns-sale-price-week-4 sns-discount-week-4 +offer-state snapshot-date sku fnsku asin product-name country week-1-start-date sns-units-shipped-week-1 oos-rate-week-1 sns-sale-price-week-1 sns-discount-week-1 sns-units-shipped-week-2 oos-rate-week-2 sns-sale-price-week-2 sns-discount-week-2 sns-units-shipped-week-3 oos-rate-week-3 sns-sale-price-week-3 sns-discount-week-3 sns-units-shipped-week-4 oos-rate-week-4 sns-sale-price-week-4 sns-discount-week-4 diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_STORAGE_FEE_CHARGES_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_STORAGE_FEE_CHARGES_DATA.csv new file mode 100644 index 000000000000..5e444ce2142c --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FBA_STORAGE_FEE_CHARGES_DATA.csv @@ -0,0 +1,3 @@ +asin fnsku product_name fulfillment_center country_code longest_side median_side shortest_side measurement_units weight weight_units item_volume volume_units product_size_tier average_quantity_on_hand average_quantity_pending_removal estimated_total_item_volume month_of_charge storage_rate currency estimated_monthly_storage_fee dangerous_goods_storage_type eligible_for_inventory_discount qualifies_for_inventory_discount total_incentive_fee_amount breakdown_incentive_fee_amount average_quantity_customer_orders +asin fnsku product_name fulfillment_center country_code longest_side median_side shortest_side measurement_units weight weight_units item_volume volume_units product_size_tier average_quantity_on_hand average_quantity_pending_removal estimated_total_item_volume month_of_charge storage_rate currency estimated_monthly_storage_fee dangerous_goods_storage_type eligible_for_inventory_discount qualifies_for_inventory_discount total_incentive_fee_amount breakdown_incentive_fee_amount average_quantity_customer_orders +asin fnsku product_name fulfillment_center country_code longest_side median_side shortest_side measurement_units weight weight_units item_volume volume_units product_size_tier average_quantity_on_hand average_quantity_pending_removal estimated_total_item_volume month_of_charge storage_rate currency estimated_monthly_storage_fee dangerous_goods_storage_type eligible_for_inventory_discount qualifies_for_inventory_discount total_incentive_fee_amount breakdown_incentive_fee_amount average_quantity_customer_orders diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FLAT_FILE_ACTIONABLE_ORDER_DATA_SHIPPING.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FLAT_FILE_ACTIONABLE_ORDER_DATA_SHIPPING.csv new file mode 100644 index 000000000000..308f234839cd --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FLAT_FILE_ACTIONABLE_ORDER_DATA_SHIPPING.csv @@ -0,0 +1,3 @@ +order-id order-item-id purchase-date payments-date reporting-date promise-date days-past-promise buyer-email buyer-phone-number sku product-name quantity-purchased quantity-shipped quantity-to-ship ship-service-level recipient-name ship-address-1 ship-address-2 ship-address-3 ship-city ship-state ship-postal-code ship-country is-business-order purchase-order-number price-designation is-prime +order-id order-item-id purchase-date payments-date reporting-date promise-date days-past-promise buyer-email buyer-phone-number sku product-name quantity-purchased quantity-shipped quantity-to-ship ship-service-level recipient-name ship-address-1 ship-address-2 ship-address-3 ship-city ship-state ship-postal-code ship-country is-business-order purchase-order-number price-designation is-prime +order-id order-item-id purchase-date payments-date reporting-date promise-date days-past-promise buyer-email buyer-phone-number sku product-name quantity-purchased quantity-shipped quantity-to-ship ship-service-level recipient-name ship-address-1 ship-address-2 ship-address-3 ship-city ship-state ship-postal-code ship-country is-business-order purchase-order-number price-designation is-prime diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FLAT_FILE_ARCHIVED_ORDERS_DATA_BY_ORDER_DATE.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FLAT_FILE_ARCHIVED_ORDERS_DATA_BY_ORDER_DATE.csv new file mode 100644 index 000000000000..80b4bcf8d400 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FLAT_FILE_ARCHIVED_ORDERS_DATA_BY_ORDER_DATE.csv @@ -0,0 +1,3 @@ +amazon-order-id merchant-order-id purchase-date last-updated-date order-status fulfillment-channel sales-channel order-channel url ship-service-level product-name sku asin item-status quantity currency item-price item-tax shipping-price shipping-tax gift-wrap-price gift-wrap-tax item-promotion-discount ship-promotion-discount ship-country ship-promotion-id promotion-ids is-business-order purchase-order-number price-designation customized-url customized-page is-heavy-or-bulky is-replacement-order +amazon-order-id merchant-order-id purchase-date last-updated-date order-status fulfillment-channel sales-channel order-channel url ship-service-level product-name sku asin item-status quantity currency item-price item-tax shipping-price shipping-tax gift-wrap-price gift-wrap-tax item-promotion-discount ship-promotion-discount ship-country ship-promotion-id promotion-ids is-business-order purchase-order-number price-designation customized-url customized-page is-heavy-or-bulky is-replacement-order +amazon-order-id merchant-order-id purchase-date last-updated-date order-status fulfillment-channel sales-channel order-channel url ship-service-level product-name sku asin item-status quantity currency item-price item-tax shipping-price shipping-tax gift-wrap-price gift-wrap-tax item-promotion-discount ship-promotion-discount ship-country ship-promotion-id promotion-ids is-business-order purchase-order-number price-designation customized-url customized-page is-heavy-or-bulky is-replacement-order diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FLAT_FILE_RETURNS_DATA_BY_RETURN_DATE.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FLAT_FILE_RETURNS_DATA_BY_RETURN_DATE.csv new file mode 100644 index 000000000000..4dd55103fdba --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_FLAT_FILE_RETURNS_DATA_BY_RETURN_DATE.csv @@ -0,0 +1,3 @@ +Order ID Order date Return request date Return request status Amazon RMA ID Merchant RMA ID Label type Label cost Currency code Return carrier Tracking ID Label to be paid by A-to-Z Claim Is prime ASIN Merchant SKU Item Name Return quantity Return Reason In policy Return type Resolution Invoice number Return delivery date Order Amount Order quantity SafeT Action reason SafeT claim id SafeT claim state SafeT claim creation time SafeT claim reimbursement amount Refunded Amount +Order ID Order date Return request date Return request status Amazon RMA ID Merchant RMA ID Label type Label cost Currency code Return carrier Tracking ID Label to be paid by A-to-Z Claim Is prime ASIN Merchant SKU Item Name Return quantity Return Reason In policy Return type Resolution Invoice number Return delivery date Order Amount Order quantity SafeT Action reason SafeT claim id SafeT claim state SafeT claim creation time SafeT claim reimbursement amount Refunded Amount +Order ID Order date Return request date Return request status Amazon RMA ID Merchant RMA ID Label type Label cost Currency code Return carrier Tracking ID Label to be paid by A-to-Z Claim Is prime ASIN Merchant SKU Item Name Return quantity Return Reason In policy Return type Resolution Invoice number Return delivery date Order Amount Order quantity SafeT Action reason SafeT claim id SafeT claim state SafeT claim creation time SafeT claim reimbursement amount Refunded Amount diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_LEDGER_DETAIL_VIEW_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_LEDGER_DETAIL_VIEW_DATA.csv new file mode 100644 index 000000000000..1df2f6161f65 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_LEDGER_DETAIL_VIEW_DATA.csv @@ -0,0 +1,3 @@ +Date FNSKU ASIN MSKU Title EventType ReferenceID Quantity FulfillmentCenter Disposition Reason Country ReconciledQuantity UnreconciledQuantity +11/21/2021 FNSKU ASIN MSKU Title EventType ReferenceID Quantity FulfillmentCenter Disposition Reason Country ReconciledQuantity UnreconciledQuantity +11/21/2021 FNSKU ASIN MSKU Title EventType ReferenceID Quantity FulfillmentCenter Disposition Reason Country ReconciledQuantity UnreconciledQuantity diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_LEDGER_SUMMARY_VIEW_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_LEDGER_SUMMARY_VIEW_DATA.csv new file mode 100644 index 000000000000..e794b787c519 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_LEDGER_SUMMARY_VIEW_DATA.csv @@ -0,0 +1,3 @@ +Date FNSKU ASIN MSKU Title Disposition StartingWarehouseBalance InTransitBetweenWarehouses Receipts CustomerShipments CustomerReturns VendorReturns WarehouseTransferIn/Out Found Lost Damaged Disposed OtherEvents EndingWarehouseBalance UnknownEvents Location +12/22/2022 FNSKU ASIN MSKU Title Disposition StartingWarehouseBalance InTransitBetweenWarehouses Receipts CustomerShipments CustomerReturns VendorReturns WarehouseTransferIn/Out Found Lost Damaged Disposed OtherEvents EndingWarehouseBalance UnknownEvents Location +12/22/2022 FNSKU ASIN MSKU Title Disposition StartingWarehouseBalance InTransitBetweenWarehouses Receipts CustomerShipments CustomerReturns VendorReturns WarehouseTransferIn/Out Found Lost Damaged Disposed OtherEvents EndingWarehouseBalance UnknownEvents Location diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_MERCHANT_CANCELLED_LISTINGS_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_MERCHANT_CANCELLED_LISTINGS_DATA.csv new file mode 100644 index 000000000000..7b0df2b1bcc6 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_MERCHANT_CANCELLED_LISTINGS_DATA.csv @@ -0,0 +1,3 @@ +item-name item-description seller-sku price quantity image-url item-is-marketplace product-id-type zshop-shipping-fee item-note item-condition zshop-category1 zshop-browse-path zshop-storefront-feature asin1 asin2 asin3 will-ship-internationally expedited-shipping zshop-boldface product-id add-delete merchant-shipping-group +item-name item-description seller-sku price quantity image-url item-is-marketplace product-id-type zshop-shipping-fee item-note item-condition zshop-category1 zshop-browse-path zshop-storefront-feature asin1 asin2 asin3 will-ship-internationally expedited-shipping zshop-boldface product-id add-delete merchant-shipping-group +item-name item-description seller-sku price quantity image-url item-is-marketplace product-id-type zshop-shipping-fee item-note item-condition zshop-category1 zshop-browse-path zshop-storefront-feature asin1 asin2 asin3 will-ship-internationally expedited-shipping zshop-boldface product-id add-delete merchant-shipping-group diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_ORDER_REPORT_DATA_SHIPPING.xml b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_ORDER_REPORT_DATA_SHIPPING.xml new file mode 100644 index 000000000000..b588785b665f --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_ORDER_REPORT_DATA_SHIPPING.xml @@ -0,0 +1,101 @@ + + +
+ 1.01 + M_SELLER_354577 +
+ Product + true + + 1 + + AmazonOrderID 1 + AmazonSessionID 1 + 2022-07-05 + 2022-07-05 + + BuyerEmailAddress 1 + BuyerName 1 + BuyerPhoneNumber 1 + + + FulfillmentMethod 1 + FulfillmentServiceLevel 1 +
+ Name 1 + AddressFieldOne 1 + City 1 + PostalCode 1 + CountryCode 1 + PhoneNumber 1 +
+
+ false + true + false + + AmazonOrderItemCode 1 + SKU 1 + Title 1 + 11 + ProductTaxCode 1 + + Type 1 + 111.00 + USD + + + Type 1 + 0.00 + USD + + +
+
+ + 2 + + AmazonOrderID 2 + AmazonSessionID 2 + 2022-07-06 + 2022-07-06 + + BuyerEmailAddress 2 + BuyerName 2 + BuyerPhoneNumber 2 + + + FulfillmentMethod 2 + FulfillmentServiceLevel 2 +
+ Name 2 + AddressFieldOne 2 + City 2 + PostalCode 2 + CountryCode 2 + PhoneNumber 2 +
+
+ false + true + false + + AmazonOrderItemCode 2 + SKU 2 + Title 2 + 2 + ProductTaxCode 2 + + Type 2 + 222.00 + USD + + + Type 2 + 0.00 + USD + + +
+
+
diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_SALES_AND_TRAFFIC_REPORT.json b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_SALES_AND_TRAFFIC_REPORT.json new file mode 100644 index 000000000000..e5782a60a52b --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_SALES_AND_TRAFFIC_REPORT.json @@ -0,0 +1,123 @@ +{ + "reportSpecification": { + "reportType": "GET_SALES_AND_TRAFFIC_REPORT", + "reportOptions": { + "dateGranularity": "DAY", + "asinGranularity": "SKU" + }, + "dataStartTime": "2021-06-11", + "dataEndTime": "2021-06-14", + "marketplaceIds": ["ATVPDKIKX0DER"] + }, + "salesAndTrafficByDate": [ + { + "date": "2021-06-11", + "salesByDate": { + "orderedProductSales": { + "amount": 238.44, + "currencyCode": "USD" + }, + "unitsOrdered": 23, + "totalOrderItems": 20, + "averageSalesPerOrderItem": { + "amount": 11.92, + "currencyCode": "USD" + }, + "averageUnitsPerOrderItem": 1.15, + "averageSellingPrice": { + "amount": 10.37, + "currencyCode": "USD" + }, + "unitsRefunded": 1, + "refundRate": 4.35, + "claimsGranted": 0, + "claimsAmount": { + "amount": 0.0, + "currencyCode": "USD" + }, + "shippedProductSales": { + "amount": 650.72, + "currencyCode": "USD" + }, + "unitsShipped": 59, + "ordersShipped": 54 + }, + "trafficByDate": { + "browserPageViews": 1158, + "mobileAppPageViews": 500, + "pageViews": 1658, + "browserSessions": 906, + "mobileAppSessions": 94, + "sessions": 1000, + "buyBoxPercentage": 10.54, + "orderItemSessionPercentage": 2.21, + "unitSessionPercentage": 2.54, + "averageOfferCount": 9686, + "averageParentItems": 9630, + "feedbackReceived": 10, + "negativeFeedbackReceived": 1, + "receivedNegativeFeedbackRate": 10.0 + } + } + ], + "salesAndTrafficByAsin": [ + { + "parentAsin": "B123456789", + "childAsin": "B123456789", + "sku": "AB-1C2D-EFGH", + "salesByAsin": { + "unitsOrdered": 1, + "orderedProductSales": { + "amount": 16.79, + "currencyCode": "USD" + }, + "totalOrderItems": 1 + }, + "trafficByAsin": { + "browserSessions": 13, + "mobileAppSessions": 5, + "sessions": 18, + "browserSessionPercentage": 0.33, + "mobileAppSessionPercentage": 0.2, + "sessionPercentage": 0.26, + "browserPageViews": 21, + "mobileAppPageViews": 22, + "pageViews": 43, + "browserPageViewsPercentage": 0.41, + "mobileAppPageViewsPercentage": 0.2, + "pageViewsPercentage": 0.3, + "buyBoxPercentage": 95.24, + "unitSessionPercentage": 7.69 + } + }, + { + "parentAsin": "B234567890", + "childAsin": "B234567890", + "sku": "CD-2E3F-GHIJ", + "salesByAsin": { + "unitsOrdered": 3, + "orderedProductSales": { + "amount": 26.25, + "currencyCode": "USD" + }, + "totalOrderItems": 2 + }, + "trafficByAsin": { + "browserSessions": 8, + "mobileAppSessions": 5, + "sessions": 13, + "browserSessionPercentage": 0.33, + "mobileAppSessionPercentage": 0.1, + "sessionPercentage": 0.2, + "browserPageViews": 21, + "mobileAppPageViews": 12, + "pageViews": 33, + "browserPageViewsPercentage": 0.41, + "mobileAppPageViewsPercentage": 0.25, + "pageViewsPercentage": 0.32, + "buyBoxPercentage": 0.0, + "unitSessionPercentage": 37.5 + } + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_SELLER_FEEDBACK_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_SELLER_FEEDBACK_DATA.csv new file mode 100644 index 000000000000..1d11467128aa --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_SELLER_FEEDBACK_DATA.csv @@ -0,0 +1,3 @@ +Date Rating Comments Your Response Order ID Rater Email +10/20/20 Rating Comments Your Response Order ID Rater Email +10/20/20 Rating Comments Your Response Order ID Rater Email diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_STRANDED_INVENTORY_UI_DATA.csv b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_STRANDED_INVENTORY_UI_DATA.csv new file mode 100644 index 000000000000..f49d85f0efd3 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_STRANDED_INVENTORY_UI_DATA.csv @@ -0,0 +1,3 @@ +primary-action date-stranded Date-to-take-auto-removal status-primary status-secondary error-message stranded-reason asin sku fnsku product-name condition fulfilled-by fulfillable-qty your-price unfulfillable-qty reserved-quantity inbound-shipped-qty +primary-action date-stranded Date-to-take-auto-removal status-primary status-secondary error-message stranded-reason asin sku fnsku product-name condition fulfilled-by fulfillable-qty your-price unfulfillable-qty reserved-quantity inbound-shipped-qty +primary-action date-stranded Date-to-take-auto-removal status-primary status-secondary error-message stranded-reason asin sku fnsku product-name condition fulfilled-by fulfillable-qty your-price unfulfillable-qty reserved-quantity inbound-shipped-qty diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_VENDOR_INVENTORY_REPORT.json b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_VENDOR_INVENTORY_REPORT.json new file mode 100644 index 000000000000..3ea8e2298d55 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_VENDOR_INVENTORY_REPORT.json @@ -0,0 +1,167 @@ +{ + "reportSpecification": { + "reportType": "GET_VENDOR_INVENTORY_REPORT", + "reportOptions": { + "reportPeriod": "WEEK", + "sellingProgram": "RETAIL", + "distributorView": "MANUFACTURING" + }, + "dataStartTime": "2021-06-06", + "dataEndTime": "2021-06-19", + "marketplaceIds": ["ATVPDKIKX0DER"] + }, + "inventoryAggregate": [ + { + "startDate": "2021-06-06", + "endDate": "2021-06-12", + "vendorConfirmationRate": 0.88, + "netReceivedInventoryCost": { + "amount": 2345.5, + "currencyCode": "USD" + }, + "netReceivedInventoryUnits": 278, + "openPurchaseOrderUnits": 123, + "averageVendorLeadTimeDays": 10.2, + "sellThroughRate": 0.88, + "unfilledCustomerOrderedUnits": 12, + "sellableOnHandInventoryCost": { + "amount": 43123.99, + "currencyCode": "USD" + }, + "sellableOnHandInventoryUnits": 5490, + "unsellableOnHandInventoryCost": { + "amount": 2345.5, + "currencyCode": "USD" + }, + "unsellableOnHandInventoryUnits": 881, + "aged90PlusDaysSellableInventoryCost": { + "amount": 123.5, + "currencyCode": "USD" + }, + "aged90PlusDaysSellableInventoryUnits": 2234, + "unhealthyInventoryCost": { + "amount": 123.45, + "currencyCode": "USD" + }, + "unhealthyInventoryUnits": 114, + "procurableProductOutOfStockRate": 0.72, + "uft": 0.19, + "receiveFillRate": 0.67 + }, + { + "startDate": "2021-06-13", + "endDate": "2021-06-19", + "vendorConfirmationRate": 0.98, + "netReceivedInventoryCost": { + "amount": 4335.5, + "currencyCode": "USD" + }, + "netReceivedInventoryUnits": 123, + "openPurchaseOrderUnits": 422, + "averageVendorLeadTimeDays": 5.2, + "sellThroughRate": 0.98, + "unfilledCustomerOrderedUnits": 3, + "sellableOnHandInventoryCost": { + "amount": 43123.99, + "currencyCode": "USD" + }, + "sellableOnHandInventoryUnits": 4490, + "unsellableOnHandInventoryCost": { + "amount": 3345.5, + "currencyCode": "USD" + }, + "unsellableOnHandInventoryUnits": 881, + "aged90PlusDaysSellableInventoryCost": { + "amount": 323.5, + "currencyCode": "USD" + }, + "aged90PlusDaysSellableInventoryUnits": 2234, + "unhealthyInventoryCost": { + "amount": 323.45, + "currencyCode": "USD" + }, + "unhealthyInventoryUnits": 314, + "procurableProductOutOfStockRate": 0.73, + "uft": 0.18, + "receiveFillRate": 0.77 + } + ], + "inventoryByAsin": [ + { + "startDate": "2021-06-06", + "endDate": "2021-06-12", + "asin": "B123456789", + "vendorConfirmationRate": 0.88, + "netReceivedInventoryCost": { + "amount": 2345.5, + "currencyCode": "USD" + }, + "netReceivedInventoryUnits": 278, + "openPurchaseOrderUnits": 123, + "averageVendorLeadTimeDays": 10.2, + "sellThroughRate": 0.88, + "unfilledCustomerOrderedUnits": 12, + "sellableOnHandInventoryCost": { + "amount": 43123.99, + "currencyCode": "USD" + }, + "sellableOnHandInventoryUnits": 5490, + "unsellableOnHandInventoryCost": { + "amount": 2345.5, + "currencyCode": "USD" + }, + "unsellableOnHandInventoryUnits": 881, + "aged90PlusDaysSellableInventoryCost": { + "amount": 123.5, + "currencyCode": "USD" + }, + "aged90PlusDaysSellableInventoryUnits": 2234, + "unhealthyInventoryCost": { + "amount": 123.45, + "currencyCode": "USD" + }, + "unhealthyInventoryUnits": 114, + "procurableProductOutOfStockRate": 0.47, + "uft": 0.26, + "receiveFillRate": 0.98 + }, + { + "startDate": "2021-06-06", + "endDate": "2021-06-12", + "asin": "B987654321", + "vendorConfirmationRate": 0.22, + "netReceivedInventoryCost": { + "amount": 235.5, + "currencyCode": "USD" + }, + "netReceivedInventoryUnits": 78, + "openPurchaseOrderUnits": 23, + "averageVendorLeadTimeDays": 1.2, + "sellThroughRate": 0.28, + "unfilledCustomerOrderedUnits": 1, + "sellableOnHandInventoryCost": { + "amount": 123.99, + "currencyCode": "USD" + }, + "sellableOnHandInventoryUnits": 590, + "unsellableOnHandInventoryCost": { + "amount": 245.5, + "currencyCode": "USD" + }, + "unsellableOnHandInventoryUnits": 81, + "aged90PlusDaysSellableInventoryCost": { + "amount": 13.5, + "currencyCode": "USD" + }, + "aged90PlusDaysSellableInventoryUnits": 234, + "unhealthyInventoryCost": { + "amount": 23.45, + "currencyCode": "USD" + }, + "unhealthyInventoryUnits": 14, + "procurableProductOutOfStockRate": 0.25, + "uft": 0.49, + "receiveFillRate": 0.81 + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_VENDOR_NET_PURE_PRODUCT_MARGIN_REPORT.json b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_VENDOR_NET_PURE_PRODUCT_MARGIN_REPORT.json new file mode 100644 index 000000000000..41f291c7f0e6 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_VENDOR_NET_PURE_PRODUCT_MARGIN_REPORT.json @@ -0,0 +1,37 @@ +{ + "reportSpecification": { + "reportType": "GET_VENDOR_NET_PURE_PRODUCT_MARGIN_REPORT", + "reportOptions": { + "reportPeriod": "WEEK" + }, + "dataStartTime": "2021-06-06", + "dataEndTime": "2021-06-19", + "marketplaceIds": ["ATVPDKIKX0DER"] + }, + "netPureProductMarginAggregate": [ + { + "startDate": "2021-06-06", + "endDate": "2021-06-12", + "netPureProductMargin": 0.1234 + }, + { + "startDate": "2021-06-13", + "endDate": "2021-06-19", + "netPureProductMargin": 0.1234 + } + ], + "netPureProductMarginByAsin": [ + { + "startDate": "2021-06-06", + "endDate": "2021-06-12", + "asin": "B123456789", + "netPureProductMargin": 0.1234 + }, + { + "startDate": "2021-06-06", + "endDate": "2021-06-12", + "asin": "B987654321", + "netPureProductMargin": 0.1234 + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_VENDOR_REAL_TIME_INVENTORY_REPORT.json b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_VENDOR_REAL_TIME_INVENTORY_REPORT.json new file mode 100644 index 000000000000..b289bb968e38 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_VENDOR_REAL_TIME_INVENTORY_REPORT.json @@ -0,0 +1,22 @@ +{ + "reportSpecification": { + "reportType": "GET_VENDOR_REAL_TIME_INVENTORY_REPORT", + "dataStartTime": "2022-10-01T00:00:00Z", + "dataEndTime": "2022-10-01T02:00:00Z", + "marketplaceIds": ["ATVPDKIKX0DER"] + }, + "reportData": [ + { + "startTime": "2022-10-01T00:00:00Z", + "endTime": "2022-10-01T01:00:00Z", + "asin": "B123456789", + "highlyAvailableInventory": 270 + }, + { + "startTime": "2022-10-01T00:00:00Z", + "endTime": "2022-10-01T01:00:00Z", + "asin": "B987654321", + "highlyAvailableInventory": 650 + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_VENDOR_SALES_REPORT.json b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_VENDOR_SALES_REPORT.json new file mode 100644 index 000000000000..43ab6d456d60 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_VENDOR_SALES_REPORT.json @@ -0,0 +1,95 @@ +{ + "reportSpecification": { + "reportType": "GET_VENDOR_SALES_REPORT", + "reportOptions": { + "distributorView": "MANUFACTURING", + "reportPeriod": "WEEK", + "sellingProgram": "RETAIL" + }, + "dataStartTime": "2021-06-06", + "dataEndTime": "2021-06-19", + "marketplaceIds": ["ATVPDKIKX0DER"] + }, + "salesAggregate": [ + { + "startDate": "2021-06-06", + "endDate": "2021-06-12", + "customerReturns": 0, + "orderedRevenue": { + "amount": 1500.0, + "currencyCode": "USD" + }, + "orderedUnits": 75, + "shippedCogs": { + "amount": 90.0, + "currencyCode": "USD" + }, + "shippedRevenue": { + "amount": 200.0, + "currencyCode": "USD" + }, + "shippedUnits": 10 + }, + { + "startDate": "2021-06-13", + "endDate": "2021-06-19", + "customerReturns": 0, + "orderedRevenue": { + "amount": 0.0, + "currencyCode": "USD" + }, + "orderedUnits": 0, + "shippedCogs": { + "amount": 0.0, + "currencyCode": "USD" + }, + "shippedRevenue": { + "amount": 0.0, + "currencyCode": "USD" + }, + "shippedUnits": 0 + } + ], + "salesByAsin": [ + { + "startDate": "2021-06-06", + "endDate": "2021-06-12", + "asin": "B123456789", + "customerReturns": 0, + "orderedRevenue": { + "amount": 1000.0, + "currencyCode": "USD" + }, + "orderedUnits": 25, + "shippedCogs": { + "amount": 50.0, + "currencyCode": "USD" + }, + "shippedRevenue": { + "amount": 150.0, + "currencyCode": "USD" + }, + "shippedUnits": 5 + }, + { + "startDate": "2021-06-06", + "endDate": "2021-06-12", + "asin": "B987654321", + "customerReturns": 0, + "orderedRevenue": { + "amount": 500, + "currencyCode": "USD" + }, + "orderedUnits": 50, + "shippedCogs": { + "amount": 40.0, + "currencyCode": "USD" + }, + "shippedRevenue": { + "amount": 50.0, + "currencyCode": "USD" + }, + "shippedUnits": 5 + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_VENDOR_TRAFFIC_REPORT.json b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_VENDOR_TRAFFIC_REPORT.json new file mode 100644 index 000000000000..fcf1c3d30f3c --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/GET_VENDOR_TRAFFIC_REPORT.json @@ -0,0 +1,37 @@ +{ + "reportSpecification": { + "reportType": "GET_VENDOR_TRAFFIC_REPORT", + "reportOptions": { + "reportPeriod": "WEEK" + }, + "dataStartTime": "2021-06-06", + "dataEndTime": "2021-06-19", + "marketplaceIds": ["ATVPDKIKX0DER"] + }, + "trafficAggregate": [ + { + "startDate": "2021-06-06", + "endDate": "2021-06-12", + "glanceViews": 100 + }, + { + "startDate": "2021-06-13", + "endDate": "2021-06-19", + "glanceViews": 250 + } + ], + "trafficByAsin": [ + { + "startDate": "2021-06-06", + "endDate": "2021-06-12", + "asin": "B123456789", + "glanceViews": 100 + }, + { + "startDate": "2021-06-13", + "endDate": "2021-06-19", + "asin": "B123456789", + "glanceViews": 250 + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/VendorDirectFulfillmentShipping.json b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/VendorDirectFulfillmentShipping.json new file mode 100644 index 000000000000..591d1b53f52a --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/resource/http/response/VendorDirectFulfillmentShipping.json @@ -0,0 +1,44 @@ +{ + "payload": { + "shippingLabels": [ + { + "purchaseOrderNumber": "2JK3S9VCE", + "sellingParty": { + "partyId": "999US" + }, + "shipFromParty": { + "partyId": "ABCD" + }, + "labelFormat": "PNG", + "labelData": [ + { + "packageIdentifier": "PKG001", + "trackingNumber": "1Z6A34Y60369738804", + "shipMethod": "UPS_GR_RES", + "shipMethodName": "UPS Ground Residential", + "content": "Base 64 encoded string goes here" + } + ] + }, + { + "purchaseOrderNumber": "2JK3S9VD", + "sellingParty": { + "partyId": "999US" + }, + "shipFromParty": { + "partyId": "ABCD" + }, + "labelFormat": "PNG", + "labelData": [ + { + "packageIdentifier": "PKG002", + "trackingNumber": "1Z6A34Y60369738805", + "shipMethod": "UPS_GR_RES", + "shipMethodName": "UPS Ground Residential", + "content": "Base 64 encoded string goes here" + } + ] + } + ] + } +} diff --git a/docs/integrations/sources/amazon-seller-partner.md b/docs/integrations/sources/amazon-seller-partner.md index 5d62f254719c..961a90292450 100644 --- a/docs/integrations/sources/amazon-seller-partner.md +++ b/docs/integrations/sources/amazon-seller-partner.md @@ -14,6 +14,7 @@ This page contains the setup guide and reference information for the Amazon Sell - AWS Region - AWS Seller Partner Account Type - Granted OAuth access + @@ -26,12 +27,15 @@ This page contains the setup guide and reference information for the Amazon Sell - LWA Client Id - LWA Client Secret - Refresh Token + ## Setup Guide ## Step 1: Set up Amazon Seller Partner +[Register](https://sellercentral.amazon.com/) your Amazon Seller Partner account. + **Airbyte Open Source setup steps** @@ -42,6 +46,8 @@ This page contains the setup guide and reference information for the Amazon Sell ## Step 2: Set up the source connector in Airbyte + + **For Airbyte Cloud:** 1. [Log into your Airbyte Cloud](https://cloud.airbyte.com/workspaces) account. @@ -55,6 +61,10 @@ This page contains the setup guide and reference information for the Amazon Sell 9. You can specify report options for each stream using **Report Options** section. Available options can be found in corresponding category [here](https://developer-docs.amazon.com/sp-api/docs/report-type-values). 10. Click `Set up source`. + + + + **For Airbyte Open Source:** 1. Using developer application from Step 1, [generate](https://developer-docs.amazon.com/sp-api/docs/self-authorization) refresh token. @@ -66,6 +76,8 @@ This page contains the setup guide and reference information for the Amazon Sell 7. You can specify report options for each stream using **Report Options** section. Available options can be found in corresponding category [here](https://developer-docs.amazon.com/sp-api/docs/report-type-values). 8. Click `Set up source`. + + ## Supported sync modes The Amazon Seller Partner source connector supports the following [sync modes](https://docs.airbyte.com/cloud/core-concepts/#connection-sync-mode): @@ -153,6 +165,7 @@ Information about rate limits you may find [here](https://developer-docs.amazon. | Version | Date | Pull Request | Subject | |:---------|:-----------|:------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `3.3.2` | 2024-02-13 | [\#33996](https://github.com/airbytehq/airbyte/pull/33996) | Add integration tests | | `3.3.1` | 2024-02-09 | [\#35106](https://github.com/airbytehq/airbyte/pull/35106) | Add logs for the failed check command | | `3.3.0` | 2024-02-09 | [\#35062](https://github.com/airbytehq/airbyte/pull/35062) | Fix the check command for the `Vendor` account type | | `3.2.2` | 2024-02-07 | [\#34914](https://github.com/airbytehq/airbyte/pull/34914) | Fix date formatting for ledger reports with aggregation by month |