From 6e54d513c95653bdaaeb18937144b4cedab16ba0 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 16 Feb 2021 12:51:12 +0000 Subject: [PATCH 01/13] first steps on woocommerce integration --- products/views.py | 2 +- requirements.txt | 3 +- utils/woocommerce.py | 80 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 utils/woocommerce.py diff --git a/products/views.py b/products/views.py index f9f356b..9a3b5b5 100644 --- a/products/views.py +++ b/products/views.py @@ -48,7 +48,7 @@ class ProductViewSet(viewsets.ModelViewSet): @action(detail=True, methods=['GET',]) def related(request): - # find the most similar products + # TODO: find the most similar products return Response(data=[]) diff --git a/requirements.txt b/requirements.txt index 05d3342..cb2021b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,4 +12,5 @@ django-tagulous==1.1.0 Pillow==8.1.0 drf-extra-fields==3.0.4 django-ipware==3.0.2 -geoip2==4.1.0 \ No newline at end of file +geoip2==4.1.0 +woocommerce==2.1.1 diff --git a/utils/woocommerce.py b/utils/woocommerce.py new file mode 100644 index 0000000..8dce681 --- /dev/null +++ b/utils/woocommerce.py @@ -0,0 +1,80 @@ +""" +This file holds the functions necesary to: + +- Connect to seller's shop API +- Load information on seller [??] +- Load product information + +""" +import logging + +from woocommerce import API + +from companies.models import Company +from products.models import Product +from products.serializers import ProductSerializer + + +def get_wcapi_instance(url, key, secret, version="wc/v3"): + wcapi = API( + url=url, + consumer_key=key, + consumer_secret=secret, + wp_api=True, + version=version + ) + return wcapi + + +def migrate_shop_products(url, key, secret, version="wc/v3"): + # get wcapi + wcapi = get_wcapi_instance(url, key, secret, version) + + consumer_key = 'ck_565539bb25b472b1ff7a209eb157ca11c0a26397' + consumer_secret = 'cs_9c1690ba5da0dd70f51d61c395628fa14d1a104c' + + # get company fom url + company = Company.objects.filter(web_link=url).first() + + if not company: + # logging.error(f"Could not find Company with URL: {url}") + # print(f"Could not find Company with URL: {url}") + # return None + # TODO: ELIMINATE THIS AFTER DEBUGGING + company = Company.objects.create(web_link=url) + logging.error(f"Created Company for testing: {url}") + + # list products + response = wcapi.get('/products/') + if response.status_code == 200: + products = response.json() + elif response.status_code == 401: + logging.error(f"{response.status_code} [{response.url}]: {response.json()}") + return None + else: + logging.error(f"Could not load products from {url}: [{response.status_code}]") + print(f"Could not load products fom {url}: [{response.status_code}]") + return None + + product_fields = [f.name for f in Product._meta.get_fields()] + + for product in products: + instance_data = {} + # remove unwanted fields + product.pop('id') + for key in product: + if key in product_fields: + instance_data[key] = product[key] + # validate data + import ipdb; ipdb.set_trace() + serializer = ProductSerializer(**instance_data) + if serializer.is_valid(): + import ipdb; ipdb.set_trace() + Product.objects.create(**serializer.validated_data) + else: + import ipdb; ipdb.set_trace() + + + + + From abd0c6312c7d5bc8ea4d7de2c0804ce7f21bfe1e Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 16 Feb 2021 13:23:40 +0000 Subject: [PATCH 02/13] integration starts to work --- companies/models.py | 4 ++-- products/models.py | 2 +- utils/woocommerce.py | 34 ++++++++++++++++++++++------------ 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/companies/models.py b/companies/models.py index 8b8a470..122fc89 100644 --- a/companies/models.py +++ b/companies/models.py @@ -48,8 +48,8 @@ class Company(models.Model): updated = models.DateTimeField('date last update', auto_now=True) creator = models.ForeignKey('core.CustomUser', on_delete=models.DO_NOTHING, null=True, related_name='creator') - def __str__(self): - return self.company_name + # def __str__(self): + # return self.company_name class Meta: verbose_name = "Compañía" diff --git a/products/models.py b/products/models.py index 14cc0a9..cd739dd 100644 --- a/products/models.py +++ b/products/models.py @@ -35,7 +35,7 @@ class Product(models.Model): discount = models.DecimalField('Descuento', max_digits=5, decimal_places=2, null=True, blank=True) stock = models.PositiveIntegerField('Stock', null=True) tags = TagField(to=TreeTag) - category = SingleTagField(null=True) # main tag category + category = SingleTagField(blank=True, null=True) # main tag category attributes = TagField(to=TreeTag, related_name='product_attributes') identifiers = models.TextField('Identificador único de producto', null=True, blank=True) diff --git a/utils/woocommerce.py b/utils/woocommerce.py index 8dce681..01c0a3f 100644 --- a/utils/woocommerce.py +++ b/utils/woocommerce.py @@ -57,22 +57,32 @@ def migrate_shop_products(url, key, secret, version="wc/v3"): return None product_fields = [f.name for f in Product._meta.get_fields()] - + counter = 0 + products_created = [] for product in products: - instance_data = {} - # remove unwanted fields - product.pop('id') + instance_data = {'company':company} + # parse the product info for key in product: if key in product_fields: instance_data[key] = product[key] - # validate data - import ipdb; ipdb.set_trace() - serializer = ProductSerializer(**instance_data) - if serializer.is_valid(): - import ipdb; ipdb.set_trace() - Product.objects.create(**serializer.validated_data) - else: - import ipdb; ipdb.set_trace() + # remove unwanted fields + instance_data.pop('id') + if instance_data.get('tags') == []: + instance_data.pop('tags') + if instance_data.get('attributes') == []: + instance_data.pop('attributes') + # create instance + try: + new = Product.objects.create(**instance_data) + products_created.append(new) + counter += 1 + logging.info(f"Product {instance_data.get('name')} created") + print(f"Product {instance_data.get('name')} created") + except Exception as e: + logging.error(f"Could not create product instance: {str(e)}") + + print(f"Products created: {counter}") + return products_created From 2e33748b7006afd6807e1bbed0d467843667d395 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 16 Feb 2021 13:32:37 +0000 Subject: [PATCH 03/13] migrate_shop_products working --- utils/woocommerce.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/utils/woocommerce.py b/utils/woocommerce.py index 01c0a3f..40ab6b6 100644 --- a/utils/woocommerce.py +++ b/utils/woocommerce.py @@ -60,7 +60,7 @@ def migrate_shop_products(url, key, secret, version="wc/v3"): counter = 0 products_created = [] for product in products: - instance_data = {'company':company} + instance_data = {'company':company.id} # parse the product info for key in product: if key in product_fields: @@ -71,15 +71,24 @@ def migrate_shop_products(url, key, secret, version="wc/v3"): instance_data.pop('tags') if instance_data.get('attributes') == []: instance_data.pop('attributes') - # create instance + # create instance with serializer + serializer = ProductSerializer(data=instance_data) + if serializer.is_valid(): + new = serializer.save() + else: + logging.error(f"{serializer.errors}") + continue + ''' + # alternative method try: new = Product.objects.create(**instance_data) - products_created.append(new) - counter += 1 - logging.info(f"Product {instance_data.get('name')} created") - print(f"Product {instance_data.get('name')} created") except Exception as e: logging.error(f"Could not create product instance: {str(e)}") + ''' + products_created.append(new) + counter += 1 + logging.info(f"Product {instance_data.get('name')} created") + print(f"Product {instance_data.get('name')} created") print(f"Products created: {counter}") return products_created From 0fff360b1c3adb86a96f9ee10b7ecbe717792dd9 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 16 Feb 2021 13:56:47 +0000 Subject: [PATCH 04/13] created json field Company.credentials, added import_products action to CompanyViewSet --- companies/models.py | 14 ++++++++------ companies/views.py | 17 +++++++++++++++-- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/companies/models.py b/companies/models.py index 122fc89..3d0efdd 100644 --- a/companies/models.py +++ b/companies/models.py @@ -1,12 +1,15 @@ # from django.db import models from django.contrib.gis.db import models - +from django.contrib.postgres.fields import JSONField +from django.contrib.auth import get_user_model from tagulous.models import TagField -# from core.models import TreeTag - +from history.models import HistorySync # Create your models here. +# User = get_user_model() + + class Company(models.Model): WOO_COMMERCE = 'WOO_COMMERCE' @@ -42,14 +45,13 @@ class Company(models.Model): sync = models.BooleanField('Sincronizar tienda', default=False, null=True, blank=True) is_validated = models.BooleanField('Validado', default=False, null=True, blank=True) is_active = models.BooleanField('Activado', default=False, null=True, blank=True) + credentials = JSONField(null=True) # internal created = models.DateTimeField('date of creation', auto_now_add=True) updated = models.DateTimeField('date last update', auto_now=True) creator = models.ForeignKey('core.CustomUser', on_delete=models.DO_NOTHING, null=True, related_name='creator') - - # def __str__(self): - # return self.company_name + # history = models.ForeignKey(HistorySync, null=True, on_delete=models.DO_NOTHING, related_name='company') class Meta: verbose_name = "Compañía" diff --git a/companies/views.py b/companies/views.py index a2114ae..4196a7e 100644 --- a/companies/views.py +++ b/companies/views.py @@ -35,8 +35,7 @@ class CompanyViewSet(viewsets.ModelViewSet): Send email to company.creator """ try: - queryset = self.get_custom_queryset(request) - instance = queryset.filter(pk=kwargs['pk']).first() + instance = self.queryset.filter(pk=kwargs['pk']).first() if instance: # IP stuff client_ip, is_routable = get_client_ip(request) @@ -121,6 +120,20 @@ class CompanyViewSet(viewsets.ModelViewSet): except Exception as e: return Response({"errors":{"details": str(e),}}, status=500) + @action(detail=True, methods=['POST', ]) + def import_products(self, request, **kwargs): + instance = self.queryset.filter(pk=kwargs['pk']).first() + # check if it's a shop + if instance.shop is not True: + return Response('This company is not s shop') + # check what platform + platform = instance.platform + # check required credentials + + # execute import + + return Response() + @api_view(['GET',]) @permission_classes([IsAuthenticated,]) From e6c83ef6334284d5b27daf0e225b34a5379aab78 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 16 Feb 2021 13:59:33 +0000 Subject: [PATCH 05/13] addid checks to import_products action --- companies/views.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/companies/views.py b/companies/views.py index 4196a7e..a1d2923 100644 --- a/companies/views.py +++ b/companies/views.py @@ -125,11 +125,15 @@ class CompanyViewSet(viewsets.ModelViewSet): instance = self.queryset.filter(pk=kwargs['pk']).first() # check if it's a shop if instance.shop is not True: - return Response('This company is not s shop') + return Response('This company is not a shop') # check what platform platform = instance.platform + if platform is None: + return Response('This company is not registered with any platforms') # check required credentials - + credentials = instance.credentials + if credentials is None or credentials == {}: + return Response('This company has no registered credentials') # execute import return Response() From cf600a8c1b74e2baeff58adbd004b5e6677391db Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 17 Feb 2021 11:31:39 +0000 Subject: [PATCH 06/13] added domain to product.image url --- products/serializers.py | 17 +++++++++++++++++ products/views.py | 4 ++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/products/serializers.py b/products/serializers.py index 0f09d36..8b59ec9 100644 --- a/products/serializers.py +++ b/products/serializers.py @@ -10,12 +10,29 @@ class ProductSerializer(TaggitSerializer, serializers.ModelSerializer): tags = TagListSerializerField(required=False) category = SingleTagSerializerField(required=False) # main tag category attributes = TagListSerializerField(required=False) + # image = serializers.SerializerMethodField() class Meta: model = Product exclude = ['created', 'updated', 'creator'] +class ProductSearchSerializer(TaggitSerializer, serializers.ModelSerializer): + + tags = TagListSerializerField(required=False) + category = SingleTagSerializerField(required=False) # main tag category + attributes = TagListSerializerField(required=False) + image = serializers.SerializerMethodField() + + class Meta: + model = Product + exclude = ['created', 'updated', 'creator'] + + def get_image(self, instance): + request = self.context.get('request') + return request.build_absolute_uri(instance.image.url) + + class TagFilterSerializer(TaggitSerializer, serializers.ModelSerializer): tags = TagListSerializerField(required=False) diff --git a/products/views.py b/products/views.py index 9a3b5b5..61a332e 100644 --- a/products/views.py +++ b/products/views.py @@ -18,7 +18,7 @@ from rest_framework.decorators import api_view, permission_classes, action import requests from products.models import Product -from products.serializers import ProductSerializer, TagFilterSerializer +from products.serializers import ProductSerializer, TagFilterSerializer, ProductSearchSerializer from companies.models import Company from history.models import HistorySync @@ -175,7 +175,7 @@ def product_search(request): # extract filters from result_set filters = extract_search_filters(result_set) # serialize and respond - product_serializer = ProductSerializer(result_set, many=True) + product_serializer = ProductSearchSerializer(result_set, many=True, context={'request': request}) return Response(data={"filters": filters, "products": product_serializer.data}) except Exception as e: return Response({"errors": {"details": str(type(e))}}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) From 41402501742ebbc88d5bd2b15f120968e39c0801 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 17 Feb 2021 11:34:15 +0000 Subject: [PATCH 07/13] cleanup --- products/serializers.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/products/serializers.py b/products/serializers.py index 8b59ec9..0cd0dee 100644 --- a/products/serializers.py +++ b/products/serializers.py @@ -22,16 +22,11 @@ class ProductSearchSerializer(TaggitSerializer, serializers.ModelSerializer): tags = TagListSerializerField(required=False) category = SingleTagSerializerField(required=False) # main tag category attributes = TagListSerializerField(required=False) - image = serializers.SerializerMethodField() class Meta: model = Product exclude = ['created', 'updated', 'creator'] - def get_image(self, instance): - request = self.context.get('request') - return request.build_absolute_uri(instance.image.url) - class TagFilterSerializer(TaggitSerializer, serializers.ModelSerializer): tags = TagListSerializerField(required=False) From 42097c310234fef70a0dfd2b49ee287ba9ce41d4 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 17 Feb 2021 12:26:40 +0000 Subject: [PATCH 08/13] importing woocommerce products is working --- companies/views.py | 33 +++++++++++++++++++++++---------- utils/woocommerce.py | 34 +++++++++++++++++++++++++--------- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/companies/views.py b/companies/views.py index a1d2923..18634a5 100644 --- a/companies/views.py +++ b/companies/views.py @@ -19,6 +19,8 @@ from companies.serializers import CompanySerializer from utils.tag_filters import CompanyTagFilter from back_latienda.permissions import IsCreator +from utils import woocommerce + class CompanyViewSet(viewsets.ModelViewSet): queryset = Company.objects.all() @@ -120,23 +122,34 @@ class CompanyViewSet(viewsets.ModelViewSet): except Exception as e: return Response({"errors":{"details": str(e),}}, status=500) - @action(detail=True, methods=['POST', ]) + @action(detail=True, methods=['GET', ]) def import_products(self, request, **kwargs): instance = self.queryset.filter(pk=kwargs['pk']).first() # check if it's a shop if instance.shop is not True: - return Response('This company is not a shop') - # check what platform - platform = instance.platform - if platform is None: - return Response('This company is not registered with any platforms') + return Response({'error': 'This company is not a shop'}) # check required credentials credentials = instance.credentials if credentials is None or credentials == {}: - return Response('This company has no registered credentials') - # execute import - - return Response() + return Response({'error': 'This company has no registered credentials'}) + # check what platform + platform = instance.platform + if platform is None: + message = {'error': 'This company is not registered with any platforms'} + elif platform == 'WOO_COMMERCE': + # recheck credentials + if 'key' in credentials.keys() and 'secret' in credentials.keys(): + # execute import + products = woocommerce.migrate_shop_products( + instance.web_link, + credentials['key'], + credentials['secret']) + message = {'details': f'{len(products)} products added for {instance.company_name}'} + else: + message = {"error": 'Credentials have wrong format'} + else: + message = {'error': f'Platform {plaform} not registered'} + return Response(message) @api_view(['GET',]) diff --git a/utils/woocommerce.py b/utils/woocommerce.py index 40ab6b6..c341176 100644 --- a/utils/woocommerce.py +++ b/utils/woocommerce.py @@ -67,24 +67,40 @@ def migrate_shop_products(url, key, secret, version="wc/v3"): instance_data[key] = product[key] # remove unwanted fields instance_data.pop('id') - if instance_data.get('tags') == []: - instance_data.pop('tags') - if instance_data.get('attributes') == []: - instance_data.pop('attributes') + # extract m2m field data + tags = instance_data.pop('tags') + attributes = instance_data.pop('attributes') + # create instance with serializer + ''' serializer = ProductSerializer(data=instance_data) if serializer.is_valid(): new = serializer.save() + if tags: + new.tags.set(tags) + if attributes: + new.attributes.set(attributes) + new.save() else: logging.error(f"{serializer.errors}") continue ''' # alternative method - try: - new = Product.objects.create(**instance_data) - except Exception as e: - logging.error(f"Could not create product instance: {str(e)}") - ''' + serializer = ProductSerializer(data=instance_data) + if serializer.is_valid(): + try: + new = Product.objects.create(**serializer.validated_data) + if tags: + new.tags.set(tags) + if attributes: + new.attributes.set(attributes) + new.save() + except Exception as e: + logging.error(f"Could not create product instance: {str(e)}") + else: + logging.error(f"{serializer.errors}") + continue + products_created.append(new) counter += 1 logging.info(f"Product {instance_data.get('name')} created") From 29a2f4f6e838505029d8a0ef22d034d5bdd70763 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 17 Feb 2021 12:33:32 +0000 Subject: [PATCH 09/13] update to readme --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index c7155f1..4c8ea38 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,30 @@ Location ednpoints: - `/api/v1/cities/` +## Shop Integrations + +We provide integrations with online shop platforms + +It requires the json field `Company.credentials` to have the appropiate format and values + +Endoint: `/api/v1/companies/{PK}/import_products/` + +The software to handle different platform imports can be found in `utils` + +### WooCommerce + +Credential format: + +```json +{ + "key": "qwerweqr", + "secret": "asdfsa", +} +``` + +Method: `utils.woocommerce.migrate_shop_products` + + ## Product Search Endpoint: `/api/v1/product_search/` From e42811300b565fb8e32b8bc2c446c010cdfaba39 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 17 Feb 2021 12:35:15 +0000 Subject: [PATCH 10/13] update to readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4c8ea38..cad0698 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ This README aims to document functionality of backend as well as required steps - [Load location data](#load-location-data) - [Load taxonomy data](#load-taxonomy-data) - [Endpoints](#endpoints) +- [Shop Integrations](#shop-integrations) + - [WooCommerce](#woocommerce) - [Product Search](#product-search) - [Massive Data Load Endpoints](#massive-data-load-endpoints) - [COOP and Managing User Data Load](#coop-and-managing-user-data-load) From 64c56514b70aa510df485d7373ad47ba36b012d4 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 17 Feb 2021 13:07:07 +0000 Subject: [PATCH 11/13] added command to extract top level tags --- core/management/commands/extractparenttags.py | 31 +++++++++++++++++++ datasets/top_tags.txt | 22 +++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 core/management/commands/extractparenttags.py create mode 100644 datasets/top_tags.txt diff --git a/core/management/commands/extractparenttags.py b/core/management/commands/extractparenttags.py new file mode 100644 index 0000000..7e14657 --- /dev/null +++ b/core/management/commands/extractparenttags.py @@ -0,0 +1,31 @@ +import logging + +from django.core.management.base import BaseCommand +from django.conf import settings + +from core.models import TreeTag + + +class Command(BaseCommand): + + help = 'Extract top level tags' + + def handle(self, *args, **kwargs): + # get all instances + tags = TreeTag.objects.all() + top_tags = [] + + print("Extracting top-level tags from TreeTag instances") + # extract tags with no ancestor + for tag in tags: + if not tag.get_ancestors(): + top_tags.append(tag.name) + + print("Saving top-level tags to file") + # save results to dataset/top_tags.txt + path = f"{settings.BASE_DIR}/../datasets/top_tags.txt" + with open(path, 'wt') as f: + f.writelines([tag + '\n' for tag in top_tags]) + + # print out results + logging.info(f"Extracted {len(top_tags)} to {path}") diff --git a/datasets/top_tags.txt b/datasets/top_tags.txt new file mode 100644 index 0000000..294d7cb --- /dev/null +++ b/datasets/top_tags.txt @@ -0,0 +1,22 @@ +Alimentación, bebida y tabaco +Arte y ocio +Bebés y niños pequeños +Bricolaje +Cámaras y ópticas +Casa y jardín +Economía e industria +Electrónica +Elementos religiosos y ceremoniales +Equipamiento deportivo +# Google_Product_Taxonomy_Version: 2015-02-19 +Juegos y juguetes +Maletas y bolsos de viaje +Material de oficina +Mobiliario +Multimedia +Productos para adultos +Productos para mascotas y animales +Ropa y accesorios +Salud y belleza +Software +Vehículos y recambios From 5fd08123e5833c22d119648621567027916218ad Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 17 Feb 2021 13:10:57 +0000 Subject: [PATCH 12/13] update to readme --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index cad0698..822206f 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ This README aims to document functionality of backend as well as required steps - [COOP and Managing User Data Load](#coop-and-managing-user-data-load) - [Product Data Load](#product-data-load) - [GeoIP Setup](#geoip-setup) +- [Tags](#tags) - [Development Utils](#development-utils) - [Fake product data generation](#fake-product-data-generation) @@ -257,6 +258,22 @@ Optional: `sudo apt install libmaxminddb0 libmaxminddb-dev mmdb-bin` +## Tags + +Both `Company` and `Product` models make use of tags. + +### Load shopping taxonomy + +To create the initial set of tags, we can use the `addtaxonomy` management command. +Reads the data from `datasets/shop-taxonomy.es-ES.txt` which is from google shopping + + +### Top-level tags + +In order to extract the top level tags for use as categories, we can use the `extractparenttas` management command. +It saves the results to `datasets/top_tags.txt` + + ## Development Utils ### Fake product data generation From d53a49bf4cf5bfa1d63a120112ff094841da7fcf Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 17 Feb 2021 13:13:18 +0000 Subject: [PATCH 13/13] cleanup --- datasets/shop-taxonomy.es-ES.txt | 3 +-- datasets/top_tags.txt | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/datasets/shop-taxonomy.es-ES.txt b/datasets/shop-taxonomy.es-ES.txt index 6633f29..0332dcf 100644 --- a/datasets/shop-taxonomy.es-ES.txt +++ b/datasets/shop-taxonomy.es-ES.txt @@ -1,4 +1,3 @@ -# Google_Product_Taxonomy_Version: 2015-02-19 Alimentación, bebida y tabaco Alimentación, bebida y tabaco/Alimentos Alimentación, bebida y tabaco/Alimentos/Aliños y especias @@ -3786,7 +3785,7 @@ Equipamiento deportivo/Equipamiento para atletismo/Gimnasia/Trampolines Equipamiento deportivo/Equipamiento para atletismo/Hockey sobre hierba y lacrosse Equipamiento deportivo/Equipamiento para atletismo/Hockey sobre hierba y lacrosse/Conjuntos de equipamiento para lacrosse Equipamiento deportivo/Equipamiento para atletismo/Hockey sobre hierba y lacrosse/Equipamiento de protección para hockey sobre hierba y lacrosse -Equipamiento deportivo/Equipamiento para atletismo/Hockey sobre hierba y lacrosse/Equipamiento de protección para hockey sobre hierba y lacrosse/Almohadillas de hombros para lacrosse y hockey sobre hierba +Equipamiento deportivo/Equipamiento para atletismo/Hockey sobre hierba y lacrosse/Equipamiento de protección para hockey sobre hierba y lacrosse/Almohadillas de hombros para lacrosse y hockey sobre hierba Equipamiento deportivo/Equipamiento para atletismo/Hockey sobre hierba y lacrosse/Equipamiento de protección para hockey sobre hierba y lacrosse/Cascos para hockey sobre hierba y lacrosse Equipamiento deportivo/Equipamiento para atletismo/Hockey sobre hierba y lacrosse/Equipamiento de protección para hockey sobre hierba y lacrosse/Guantes para hockey sobre hierba y lacrosse Equipamiento deportivo/Equipamiento para atletismo/Hockey sobre hierba y lacrosse/Equipamiento de protección para hockey sobre hierba y lacrosse/Máscaras y gafas protectoras para hockey sobre hierba y lacrosse diff --git a/datasets/top_tags.txt b/datasets/top_tags.txt index 294d7cb..d09f51d 100644 --- a/datasets/top_tags.txt +++ b/datasets/top_tags.txt @@ -8,7 +8,6 @@ Economía e industria Electrónica Elementos religiosos y ceremoniales Equipamiento deportivo -# Google_Product_Taxonomy_Version: 2015-02-19 Juegos y juguetes Maletas y bolsos de viaje Material de oficina