diff --git a/back_latienda/permissions.py b/back_latienda/permissions.py
index 4d9cb9f..d4726cf 100644
--- a/back_latienda/permissions.py
+++ b/back_latienda/permissions.py
@@ -1,7 +1,25 @@
from rest_framework import permissions
-class IsCreator(permissions.BasePermission):
+class IsCompanyOwner(permissions.BasePermission):
+ """
+ Grant permission if request.user.company same as obj.id
+ """
+
+ def has_object_permission(self, request, view, obj):
+ if obj is not None:
+ # allow if authenticated and method is safe
+ if request.method in permissions.SAFE_METHODS:
+ return True
+
+ # admins always have permission
+ if request.user.is_staff is True:
+ return True
+ # permission if user is the object's creator
+ return obj == request.user.company
+ return False
+
+class IsProductOwner(permissions.BasePermission):
"""
Grant permission if request.user same as obj.creator
"""
@@ -16,10 +34,9 @@ class IsCreator(permissions.BasePermission):
if request.user.is_staff is True:
return True
# permission if user is the object's creator
- return obj.creator == request.user
+ return obj.company == request.user.company
return False
-
class IsStaff(permissions.BasePermission):
"""
Grant permission if request.user.is_staff is True
diff --git a/back_latienda/urls.py b/back_latienda/urls.py
index 8349a64..513cdf4 100644
--- a/back_latienda/urls.py
+++ b/back_latienda/urls.py
@@ -47,6 +47,7 @@ urlpatterns = [
path('api/v1/companies/sample/', company_views.random_company_sample , name='company-sample'),
path('api/v1/search/companies/', company_views.CompanySearchViewSet.as_view({'get': 'list'}) , name='company-search'),
path('api/v1/purchase_email/', product_views.purchase_email, name='purchase-email'),
+ path('api/v1/sync_shop/', product_views.sync_shop, name='purchase-email'),
path('api/v1/products/all_categories/', product_views.all_categories, name='all-categories'),
path('api/v1/stats/me/', stat_views.track_user, name='user-tracker'),
path('api/v1/autocomplete/category-tag/', product_views.CategoryTagAutocomplete.as_view(), name='category-autocomplete'),
diff --git a/companies/views.py b/companies/views.py
index 59452d0..b112e10 100644
--- a/companies/views.py
+++ b/companies/views.py
@@ -19,7 +19,7 @@ from companies.models import Company
from companies.serializers import CompanySerializer
from utils.tag_filters import CompanyTagFilter
from rest_framework import filters
-from back_latienda.permissions import IsCreator, IsSiteAdmin
+from back_latienda.permissions import IsCompanyOwner, IsSiteAdmin
from utils import woocommerce
@@ -27,7 +27,7 @@ from utils import woocommerce
class CompanySearchViewSet(viewsets.ModelViewSet):
queryset = Company.objects.filter(is_validated=True).order_by('-created')
serializer_class = CompanySerializer
- permission_classes = [IsAuthenticatedOrReadOnly, IsCreator]
+ permission_classes = [IsAuthenticatedOrReadOnly, IsCompanyOwner]
filter_backends = (filters.SearchFilter, )
# search_fields = ['company_name__unaccent__icontains', 'short_name__unaccent__icontains']
search_fields = ['@company_name', '@short_name']
@@ -36,7 +36,7 @@ class CompanySearchViewSet(viewsets.ModelViewSet):
class CompanyViewSet(viewsets.ModelViewSet):
queryset = Company.objects.filter(is_validated=True).order_by('-created')
serializer_class = CompanySerializer
- permission_classes = [IsAuthenticatedOrReadOnly, IsCreator]
+ permission_classes = [IsAuthenticatedOrReadOnly, IsCompanyOwner]
filterset_class = CompanyTagFilter
def perform_create(self, serializer):
diff --git a/core/models.py b/core/models.py
index 89d995f..1672174 100644
--- a/core/models.py
+++ b/core/models.py
@@ -57,7 +57,7 @@ class CustomUser(AbstractBaseUser, PermissionsMixin):
notify = models.BooleanField('Notificar', default=False, null=True)
provider = models.CharField('Proveedor', max_length=1000, blank=True, null=True) # red social de registro
email_verified = models.BooleanField('Email verificado', default=False, null=True)
- company = models.ForeignKey(Company, null=True, on_delete=models.DO_NOTHING, related_name='custom_user')
+ company = models.ForeignKey(Company, null=True, blank=True, on_delete=models.DO_NOTHING, related_name='custom_user')
is_active = models.BooleanField('Activo', default=True)
is_staff = models.BooleanField('Empleado',default=False )
diff --git a/geo/views.py b/geo/views.py
index ac6e94a..9a04e75 100644
--- a/geo/views.py
+++ b/geo/views.py
@@ -1,6 +1,6 @@
from rest_framework import viewsets
-from back_latienda.permissions import IsCreator, ReadOnly
+from back_latienda.permissions import ReadOnly
from . import models
from . import serializers
diff --git a/history/views.py b/history/views.py
index 1ca0c52..ffff720 100644
--- a/history/views.py
+++ b/history/views.py
@@ -10,9 +10,12 @@ from back_latienda.permissions import IsStaff
class HistorySyncViewSet(viewsets.ModelViewSet):
- queryset = HistorySync.objects.all()
+ model = HistorySync
serializer_class = HistorySyncLogSerializer
permission_classes = [IsAuthenticated,]
def perform_create(self, serializer):
serializer.save(creator=self.request.user)
+
+ def get_queryset(self):
+ return self.model.objects.filter(company=self.request.user.company).order_by('-created')
\ No newline at end of file
diff --git a/products/views.py b/products/views.py
index 2aef5a9..357503b 100644
--- a/products/views.py
+++ b/products/views.py
@@ -30,8 +30,9 @@ from products.models import Product, CategoryTag
from products.serializers import ProductSerializer, TagFilterSerializer, SearchResultSerializer
from companies.models import Company
from stats.models import StatsLog
-from back_latienda.permissions import IsCreator, IsSiteAdmin, ReadOnly
+from back_latienda.permissions import IsProductOwner, IsSiteAdmin, ReadOnly
from .utils import extract_search_filters, ranked_product_search, product_loader, get_related_products
+from utils.woocommerce import migrate_shop_products
from utils.tag_serializers import TaggitSerializer
from utils.tag_filters import ProductTagFilter, ProductOrderFilter
@@ -48,7 +49,7 @@ logging.basicConfig(
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.filter(active=True).order_by('-created')
serializer_class = ProductSerializer
- permission_classes = [IsAuthenticatedOrReadOnly, IsCreator]
+ permission_classes = [IsAuthenticatedOrReadOnly, IsProductOwner]
filter_backends = [DjangoFilterBackend, OrderingFilter]
filterset_class = ProductTagFilter
@@ -71,7 +72,7 @@ class MyProductsViewSet(viewsets.ModelViewSet):
"""
model = Product
serializer_class = ProductSerializer
- permission_classes = [IsAuthenticated]
+ permission_classes = [IsAuthenticated, IsProductOwner]
def get_queryset(self):
return self.model.objects.filter(company=self.request.user.company).order_by('-created')
@@ -403,3 +404,32 @@ def all_categories(request):
all_categories.append(instance.name)
return Response(data=all_categories)
+
+@api_view(['POST'])
+@permission_classes([IsAuthenticated,])
+def sync_shop(request):
+ print(request.data)
+ url = request.data.get('url')
+ key = request.data.get('key')
+ secret = request.data.get('secret')
+ print(f"Starting migration...")
+ response = migrate_shop_products(url, key, secret, request.user )
+ print(f"Products created: {len(response['new_products'])}")
+ print(response["error"])
+ if response["error"]:
+ message = render_to_string('sync_failed.html', {})
+ # send email to company
+ subject = "Estado de la sincronización"
+ email = EmailMessage(subject, message, to=[request.user.email])
+ email.content_subtype = "html"
+ email.send()
+ else:
+ message = render_to_string('sync_success.html', {
+ 'new_products': len(response['new_products'])
+ })
+ # send email to company
+ subject = "Estado de la sincronización"
+ email = EmailMessage(subject, message, to=[request.user.email])
+ email.content_subtype = "html"
+ email.send()
+ return Response()
diff --git a/templates/sync_failed.html b/templates/sync_failed.html
new file mode 100644
index 0000000..e4518c0
--- /dev/null
+++ b/templates/sync_failed.html
@@ -0,0 +1,678 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Se ha producido un error en la sincronización
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tu sincronización de productos desde tu tienda online ha finalizado con un error.
+
+
+ Comprueba tus credenciales y URL e inténtalo de nuevo. Si el error persiste, contacta con nosotros.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2021 La Tienda.coop
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/templates/sync_success.html b/templates/sync_success.html
new file mode 100644
index 0000000..c5d6b7b
--- /dev/null
+++ b/templates/sync_success.html
@@ -0,0 +1,678 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sincronización realizada con éxito
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tu sincronización de productos desde tu tienda online ha finalizado con éxito.
+
+
+ Se han creado {{count}} productos nuevos.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2021 La Tienda.coop
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/utils/woocommerce.py b/utils/woocommerce.py
index 11a947e..c241f30 100644
--- a/utils/woocommerce.py
+++ b/utils/woocommerce.py
@@ -65,15 +65,29 @@ def create_imported_product(info, company, history, user):
# alternative method
serializer = ProductSerializer(data=instance_data)
if serializer.is_valid():
- try:
- new = Product.objects.create(**serializer.validated_data)
- new.tags = tags
- new.attributes = attributes
- new.save()
- except Exception as e:
- logging.error(f"Could not create product instance: {str(e)}")
- return None
+ # try:
+ # new = Product.objects.create(**serializer.validated_data)
+ # new.tags = tags
+ # new.attributes = attributes
+ # new.save()
+ # except Exception as e:
+ # logging.error(f"Could not create product instance: {str(e)}")
+ # return None
+ new, created = Product.objects.get_or_create(
+ company=company,
+ creator=user if user is not None else None,
+ history=history,
+ url=instance_data['url'],
+ stock=instance_data['stock'],
+ name=instance_data['name'],
+ description=instance_data['description'],
+ sku=instance_data['sku'],
+ price=instance_data['price']
+ )
+ new.tags = tags
+ new.attributes = attributes
+ new.save()
if len(info['images']) > 0:
try:
# get image
@@ -109,11 +123,13 @@ def migrate_shop_products(url, key, secret, user=None, 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()
+ company = Company.objects.filter(shop_link=url).first()
if not company:
logging.error(f"Could not find Company with URL: {url}")
@@ -122,8 +138,11 @@ def migrate_shop_products(url, key, secret, user=None, version="wc/v3"):
new_products = []
page = 1
+ attemps = 0
+ error = False
# list products
while True:
+
try:
response = wcapi.get('products/', params={'per_page': 10, 'page': page})
page += 1
@@ -131,15 +150,19 @@ def migrate_shop_products(url, key, secret, user=None, version="wc/v3"):
products = response.json()
elif response.status_code == 401:
logging.error(f"{response.status_code} [{response.url}]: {response.json()}")
- return None
+ error = True
else:
logging.error(f"Could not load products from {response.url}: [{response.status_code}]")
print(f"Could not load products fom {response.url}: [{response.status_code}]")
- return None
+ error = True
except requests.exceptions.ReadTimeout as e:
logging.error(f"Timeout reading backend: {str(e)}")
# skip and try next
- continue
+ attemps += 1
+ if attemps>4:
+ break
+ else:
+ continue
# exit loop if no more products
if not products:
break
@@ -149,7 +172,6 @@ def migrate_shop_products(url, key, secret, user=None, version="wc/v3"):
company=company,
sync_date=datetime.datetime.now(),
)
-
counter = 0
for product in products:
# check if exists
@@ -169,11 +191,12 @@ def migrate_shop_products(url, key, secret, user=None, version="wc/v3"):
# update history.quantity
history.quantity = counter
history.save()
+
logging.info(f"Products created: {len(new_products)}")
print(f"Products created: {len(new_products)}")
- return new_products
+ return {"new_products": new_products, "error": error}