Skip to content

Commit

Permalink
fix conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
elitonzky committed Dec 4, 2023
2 parents 91fc6dd + dc37009 commit d18fd22
Show file tree
Hide file tree
Showing 19 changed files with 819 additions and 93 deletions.
11 changes: 7 additions & 4 deletions marketplace/clients/facebook/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def get_url(self):

class FacebookClient(FacebookAuthorization, RequestClient):
# Product Catalog
def create_catalog(self, business_id, name, category=None):
def create_catalog(self, business_id, name, category="commerce"):
url = self.get_url + f"{business_id}/owned_product_catalogs"
data = {"name": name}
if category:
Expand Down Expand Up @@ -54,7 +54,7 @@ def create_product_feed(self, product_catalog_id, name):

return response.json()

def upload_product_feed(self, feed_id, file):
def upload_product_feed(self, feed_id, file, update_only=False):
url = self.get_url + f"{feed_id}/uploads"

headers = self._get_headers()
Expand All @@ -65,10 +65,13 @@ def upload_product_feed(self, feed_id, file):
file.content_type,
)
}
response = self.make_request(url, method="POST", headers=headers, files=files)
params = {"update_only": update_only}
response = self.make_request(
url, method="POST", headers=headers, params=params, files=files
)
return response.json()

def create_product_feed_via_url(
def create_product_feed_by_url(
self, product_catalog_id, name, feed_url, file_type, interval, hour
): # TODO: adjust this method
url = self.get_url + f"{product_catalog_id}/product_feeds"
Expand Down
79 changes: 54 additions & 25 deletions marketplace/clients/vtex/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,38 +34,67 @@ def search_product_by_sku_id(self, skuid, domain, sellerid=1):


class VtexPrivateClient(VtexAuthorization, VtexCommonClient):
def get_products_sku_ids(self, domain):
def is_valid_credentials(self, domain):
try:
url = (
f"https://{domain}/api/catalog_system/pvt/products/GetProductAndSkuIds"
)
headers = self._get_headers()
response = self.make_request(url, method="GET", headers=headers)
return response.status_code == 200
except Exception:
return False

def list_all_products_sku_ids(self, domain, page_size=1000):
all_skus = []
page_size = 250
_from = 1
_to = page_size
page = 1

while True:
url = f"https://{domain}/api/catalog_system/pvt/products/GetProductAndSkuIds?_from={_from}&_to={_to}"
url = f"https://{domain}/api/catalog_system/pvt/sku/stockkeepingunitids?page={page}&pagesize={page_size}"
headers = self._get_headers()
response = self.make_request(url, method="GET", headers=headers)

data = response.json().get("data")
if data:
for sku_ids in data.values():
all_skus.extend(sku_ids)

total_products = response.json().get("range", {}).get("total", 0)
if _to >= total_products:
break
_from += page_size
_to += page_size
_to = min(_to, total_products) # To avoid overshooting the total count
else:
sku_ids = response.json()
if not sku_ids:
break

all_skus.extend(sku_ids)
page += 1

return all_skus

def is_valid_credentials(self, domain):
try:
url = f"https://{domain}/api/catalog_system/pvt/products/GetProductAndSkuIds"
headers = self._get_headers()
response = self.make_request(url, method="GET", headers=headers)
return response.status_code == 200
except Exception:
return False
def list_active_sellers(self, domain):
url = f"https://{domain}/api/seller-register/pvt/sellers"
headers = self._get_headers()
response = self.make_request(url, method="GET", headers=headers)
sellers_data = response.json()
return [seller["id"] for seller in sellers_data["items"] if seller["isActive"]]

def get_product_details(self, sku_id, domain):
url = (
f"https://{domain}/api/catalog_system/pvt/sku/stockkeepingunitbyid/{sku_id}"
)
headers = self._get_headers()
response = self.make_request(url, method="GET", headers=headers)
return response.json()

def pub_simulate_cart_for_seller(self, sku_id, seller_id, domain):
cart_simulation_url = f"https://{domain}/api/checkout/pub/orderForms/simulation"
payload = {"items": [{"id": sku_id, "quantity": 1, "seller": seller_id}]}

response = self.make_request(cart_simulation_url, method="POST", json=payload)
simulation_data = response.json()

if simulation_data["items"]:
item_data = simulation_data["items"][0]
return {
"is_available": item_data["availability"] == "available",
"price": item_data["price"],
"list_price": item_data["listPrice"],
}
else:
return {
"is_available": False,
"price": 0,
"list_price": 0,
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ class MockFacebookService:
def __init__(self, *args, **kwargs):
pass

def create_vtex_catalog(self, validated_data, app, vtex_app, user):
if validated_data["name"] == "valid_catalog":
return (Catalog(app=app, facebook_catalog_id="123456789"), "123456789")
else:
return (None, None)

def catalog_deletion(self, catalog):
if catalog.facebook_catalog_id == "123456789":
return True
else:
return False

def enable_catalog(self, catalog):
return {"success": "True"}

Expand Down Expand Up @@ -47,6 +59,18 @@ def setUp(self):
name="catalog test",
category="commerce",
)
self.catalog_success = Catalog.objects.create(
app=self.app,
facebook_catalog_id="123456789",
name="valid_catalog",
category="commerce",
)
self.catalog_failure = Catalog.objects.create(
app=self.app,
facebook_catalog_id="987654321",
name="invlid_catalog",
category="commerce",
)
self.user_authorization = self.user.authorizations.create(
project_uuid=self.app.project_uuid
)
Expand Down Expand Up @@ -74,13 +98,13 @@ class CatalogListTestCase(MockServiceTestCase):
current_view_mapping = {"get": "list"}

def test_list_catalogs(self):
url = reverse("catalog-list", kwargs={"app_uuid": self.app.uuid})
url = reverse("catalog-list-create", kwargs={"app_uuid": self.app.uuid})
response = self.request.get(url, app_uuid=self.app.uuid)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.json["results"]), 1)
self.assertEqual(len(response.json["results"]), 3)

def test_filter_by_name(self):
url = reverse("catalog-list", kwargs={"app_uuid": self.app.uuid})
url = reverse("catalog-list-create", kwargs={"app_uuid": self.app.uuid})

response = self.client.get(url, {"name": "catalog test"})
self.assertEqual(response.status_code, status.HTTP_200_OK)
Expand All @@ -96,7 +120,7 @@ class CatalogRetrieveTestCase(MockServiceTestCase):

def test_retreive_catalog(self):
url = reverse(
"catalog-detail",
"catalog-detail-delete",
kwargs={"app_uuid": self.app.uuid, "catalog_uuid": self.catalog.uuid},
)
response = self.request.get(
Expand Down Expand Up @@ -146,9 +170,115 @@ def test_list_catalog_with_connected_catalog(self):
name="another catalog test",
category="commerce",
)
url = reverse("catalog-list", kwargs={"app_uuid": self.app.uuid})
url = reverse("catalog-list-create", kwargs={"app_uuid": self.app.uuid})
response = self.request.get(url, app_uuid=self.app.uuid)

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.json["results"]), 2)
self.assertEqual(len(response.json["results"]), 4)
self.assertTrue(response.json["results"][0]["is_connected"])


class CatalogDestroyTestCase(MockServiceTestCase):
current_view_mapping = {"delete": "destroy"}

def test_delete_catalog_success(self):
url = reverse(
"catalog-detail-delete",
kwargs={"app_uuid": self.app.uuid, "catalog_uuid": self.catalog.uuid},
)

response = self.request.delete(
url, app_uuid=self.app.uuid, catalog_uuid=self.catalog_success.uuid
)
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

def test_delete_catalog_failure(self):
url = reverse(
"catalog-detail-delete",
kwargs={"app_uuid": self.app.uuid, "catalog_uuid": self.catalog.uuid},
)
response = self.request.delete(
url, app_uuid=self.app.uuid, catalog_uuid=self.catalog_failure.uuid
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
response.data["detail"], "Failed to delete catalog on Facebook."
)


class CatalogCreateTestCase(MockServiceTestCase):
current_view_mapping = {"post": "create"}

def setUp(self):
super().setUp()
# Configures a vtex App for an already created wpp-cloud App
self.vtex_app_configured = App.objects.create(
code="vtex",
created_by=self.user,
config={"domain": "valid_domain"},
configured=True,
project_uuid=self.app.project_uuid,
platform=App.PLATFORM_WENI_FLOWS,
)
# Creation of a wpp-cloud App to simulate a link with two Vtex Apps
self.app_double_vtex = App.objects.create(
code="wpp-cloud",
created_by=self.user,
project_uuid=str(uuid.uuid4()),
platform=App.PLATFORM_WENI_FLOWS,
)
# Create a Vtex App 01 and 02 with repeating the project_uuid to simulate duplicity of integration
self.vtex_app_01 = App.objects.create(
code="vtex",
created_by=self.user,
config={"domain": "double_domain"},
configured=True,
project_uuid=self.app_double_vtex.project_uuid,
platform=App.PLATFORM_WENI_FLOWS,
)
self.vtex_app_02 = App.objects.create(
code="vtex",
created_by=self.user,
config={"domain": "double_domain"},
configured=True,
project_uuid=self.app_double_vtex.project_uuid,
platform=App.PLATFORM_WENI_FLOWS,
)
# Create a wpp-cloud without App-vtex linked to the project
self.app_without_vtex = App.objects.create(
code="wpp-cloud",
created_by=self.user,
project_uuid=str(uuid.uuid4()),
platform=App.PLATFORM_WENI_FLOWS,
)

def test_create_catalog_with_vtex_app(self):
data = {"name": "valid_catalog"}
url = reverse("catalog-list-create", kwargs={"app_uuid": self.app.uuid})

response = self.request.post(url, data, app_uuid=self.app.uuid)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data["facebook_catalog_id"], "123456789")

def test_create_catalog_with_unconfigured_app(self):
data = {"name": "valid_catalog"}
url = reverse(
"catalog-list-create", kwargs={"app_uuid": self.app_without_vtex.uuid}
)

response = self.request.post(url, data, app_uuid=self.app_without_vtex.uuid)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertEqual(response.data["detail"], "There is no VTEX App configured.")

def test_create_catalog_with_multiple_configured_apps(self):
data = {"name": "valid_catalog"}
url = reverse(
"catalog-list-create", kwargs={"app_uuid": self.app_double_vtex.uuid}
)

response = self.request.post(url, data, app_uuid=self.app_double_vtex.uuid)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
response.data["detail"],
"Multiple VTEX Apps are configured, which is not expected.",
)
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
catalog_patterns = [
path(
"<uuid:app_uuid>/catalogs/",
CatalogViewSet.as_view({"get": "list"}),
name="catalog-list",
CatalogViewSet.as_view({"get": "list", "post": "create"}),
name="catalog-list-create",
),
path(
"<uuid:app_uuid>/catalogs/<uuid:catalog_uuid>/",
CatalogViewSet.as_view({"get": "retrieve"}),
name="catalog-detail",
CatalogViewSet.as_view({"get": "retrieve", "delete": "destroy"}),
name="catalog-detail-delete",
),
path(
"<uuid:app_uuid>/catalogs/<uuid:catalog_uuid>/enable/",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
TresholdSerializer,
CatalogListSerializer,
)
from marketplace.services.vtex.generic_service import VtexService


class BaseViewSet(viewsets.ModelViewSet):
Expand All @@ -49,6 +50,17 @@ class Pagination(PageNumberPagination):
class CatalogViewSet(BaseViewSet):
serializer_class = CatalogSerializer
pagination_class = Pagination
vtex_generic_service_class = VtexService

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._vtex_app_service = None

@property
def vtex_service(self): # pragma: no cover
if not self._vtex_app_service:
self._vtex_app_service = self.vtex_generic_service_class()
return self._vtex_app_service

def filter_queryset(self, queryset):
params = self.request.query_params
Expand All @@ -68,6 +80,24 @@ def get_object(self):
catalog_uuid = self.kwargs.get("catalog_uuid")
return get_object_or_404(queryset, uuid=catalog_uuid)

def create(self, request, app_uuid, *args, **kwargs):
app = get_object_or_404(App, uuid=app_uuid, code="wpp-cloud")
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)

vtex_app = self.vtex_service.get_vtex_app_or_error(app.project_uuid)

catalog, _fba_catalog_id = self.fb_service.create_vtex_catalog(
serializer.validated_data, app, vtex_app, self.request.user
)
if not catalog:
return Response(
{"detail": "Failed to create catalog on Facebook."},
status=status.HTTP_400_BAD_REQUEST,
)

return Response(CatalogSerializer(catalog).data, status=status.HTTP_201_CREATED)

def retrieve(self, request, *args, **kwargs):
catalog = self.get_object()
connected_catalog_id = self.fb_service.get_connected_catalog(catalog.app)
Expand All @@ -92,6 +122,16 @@ def list(self, request, *args, **kwargs):

return self.get_paginated_response(serialized_data)

def destroy(self, request, *args, **kwargs):
success = self.fb_service.catalog_deletion(self.get_object())
if not success:
return Response(
{"detail": "Failed to delete catalog on Facebook."},
status=status.HTTP_400_BAD_REQUEST,
)

return Response(status=status.HTTP_204_NO_CONTENT)

@action(detail=True, methods=["POST"])
def enable_catalog(self, request, *args, **kwargs):
response = self.fb_service.enable_catalog(self.get_object())
Expand Down
Loading

0 comments on commit d18fd22

Please sign in to comment.