From ebd35baad1f4de8f913a24a235d41fb4de6ad4a8 Mon Sep 17 00:00:00 2001 From: Essa Ahmed <65098575+kitaro8@users.noreply.github.com> Date: Sat, 6 Nov 2021 22:49:02 +0300 Subject: [PATCH] '05-commerce' --- account/migrations/0002_alter_user_options.py | 17 ++ commerce/controllers.py | 255 ++++++++++-------- commerce/models.py | 13 +- commerce/schemas.py | 50 +++- config/urls.py | 4 +- requirements.txt | 10 +- 6 files changed, 232 insertions(+), 117 deletions(-) create mode 100644 account/migrations/0002_alter_user_options.py diff --git a/account/migrations/0002_alter_user_options.py b/account/migrations/0002_alter_user_options.py new file mode 100644 index 0000000..ca095bc --- /dev/null +++ b/account/migrations/0002_alter_user_options.py @@ -0,0 +1,17 @@ +# Generated by Django 3.2.5 on 2021-11-04 08:07 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='user', + options={'verbose_name': 'user', 'verbose_name_plural': 'users'}, + ), + ] diff --git a/commerce/controllers.py b/commerce/controllers.py index a8a551a..25da359 100644 --- a/commerce/controllers.py +++ b/commerce/controllers.py @@ -1,30 +1,35 @@ -import random -import string from typing import List - -from django.contrib.auth import get_user_model +import string +import random +from django.contrib.auth.models import User from django.db.models import Q from django.shortcuts import get_object_or_404 from ninja import Router from pydantic import UUID4 -from account.authorization import GlobalAuth -from commerce.models import Product, Category, City, Vendor, Item, Order, OrderStatus -from commerce.schemas import ProductOut, CitiesOut, CitySchema, VendorOut, ItemOut, ItemSchema, ItemCreate -from config.utils.schemas import MessageOut +from account.authorization import GlobalAuth, get_tokens_for_user +from django.contrib.auth import get_user_model, authenticate + + +from commerce.models import Product, Category, City, Vendor, Item, Address, Order, OrderStatus +from commerce.schemas import MessageOut, ProductOut, CitiesOut, CitySchema, VendorOut, ItemOut, ItemSchema, ItemCreate, AddressOut, AddressCreate, OrderOut, orderstatus, checkout + +User = get_user_model() + products_controller = Router(tags=['products']) address_controller = Router(tags=['addresses']) +city_controller = Router(tags=['cities']) vendor_controller = Router(tags=['vendors']) order_controller = Router(tags=['orders']) +checkout_controller = Router(tags=['checkout']) -User = get_user_model() @vendor_controller.get('', response=List[VendorOut]) def list_vendors(request): return Vendor.objects.all() - +# ===================products============================= @products_controller.get('', response={ 200: List[ProductOut], 404: MessageOut @@ -58,73 +63,50 @@ def list_products( return products_qs -""" -# product = Product.objects.all().select_related('merchant', 'category', 'vendor', 'label') - # print(product) - # - # order = Product.objects.all().select_related('address', 'user').prefetch_related('items') - - # try: - # one_product = Product.objects.get(id='8d3dd0f1-2910-457c-89e3-1b0ed6aa720a') - # except Product.DoesNotExist: - # return {"detail": "Not found"} - # print(one_product) - # - # shortcut_function = get_object_or_404(Product, id='8d3dd0f1-2910-457c-89e3-1b0ed6aa720a') - # print(shortcut_function) - - # print(type(product)) - # print(product.merchant.name) - # print(type(product.merchant)) - # print(type(product.category)) - - -Product <- Merchant, Label, Category, Vendor - -Retrieve 1000 Products form DB - -products = Product.objects.all()[:1000] (select * from product limit 1000) - -for p in products: - print(p) - -for every product, we retrieve (Merchant, Label, Category, Vendor) records - -Merchant.objects.get(id=p.merchant_id) (select * from merchant where id = 'p.merchant_id') -Label.objects.get(id=p.label_id) (select * from merchant where id = 'p.label_id') -Category.objects.get(id=p.category_id) (select * from merchant where id = 'p.category_id') -Vendor.objects.get(id=p.vendor_id) (select * from merchant where id = 'p.vendor_id') - -4*1000+1 - -Solution: Eager loading - -products = (select * from product limit 1000) +# ===================address========================= +@address_controller.get('', response=List[AddressOut]) +def list_addresses(request): + return Address.objects.all() -mids = [p1.merchant_id, p2.merchant_id, ...] -[p1.label_id, p2.label_id, ...] -. -. -. -select * from merchant where id in (mids) * 4 for (label, category and vendor) +@address_controller.post('add-addresses', auth=GlobalAuth(), response={ + 200: AddressOut +}) +def create_address(request, address_in: AddressCreate): + current_user = get_object_or_404(User, id=request.auth['pk']) + address = Address(**address_in.dict(), user= current_user) + address.save() + return 200, address -4+1 -""" +@address_controller.put('update-addresses/{id}', response={ + 200: AddressOut +}) +def update_address(request,id: UUID4, address_in: AddressCreate): + address = get_object_or_404(Address, id=id) + address.work_address = address_in.work_address + address.address1 = address_in.address1 + address.address2 = address_in.address2 + address.city_id = address_in.city_id + address.phone = address_in.phone + address.save() + return 200, address -@address_controller.get('') -def list_addresses(request): - pass +@address_controller.delete('delete-addresses/{id}', auth=GlobalAuth(), response={ + 204: MessageOut +}) +def delete_address(request, id: UUID4): + current_user = get_object_or_404(User, id=request.auth['pk']) + address = get_object_or_404(Address, id=id, user= current_user) + address.delete() -# @products_controller.get('categories', response=List[CategoryOut]) -# def list_categories(request): -# return Category.objects.all() + return 204, {'detail': 'Address deleted!'} -@address_controller.get('cities', response={ +# =============city=================== +@city_controller.get('cities', response={ 200: List[CitiesOut], 404: MessageOut }) @@ -137,7 +119,7 @@ def list_cities(request): return 404, {'detail': 'No cities found'} -@address_controller.get('cities/{id}', response={ +@city_controller.get('cities/{id}', response={ 200: CitiesOut, 404: MessageOut }) @@ -145,7 +127,7 @@ def retrieve_city(request, id: UUID4): return get_object_or_404(City, id=id) -@address_controller.post('cities', response={ +@city_controller.post('cities', response={ 201: CitiesOut, 400: MessageOut }) @@ -155,7 +137,7 @@ def create_city(request, city_in: CitySchema): return 201, city -@address_controller.put('cities/{id}', response={ +@city_controller.put('cities/{id}', response={ 200: CitiesOut, 400: MessageOut }) @@ -166,7 +148,7 @@ def update_city(request, id: UUID4, city_in: CitySchema): return 200, city -@address_controller.delete('cities/{id}', response={ +@city_controller.delete('cities/{id}', response={ 204: MessageOut }) def delete_city(request, id: UUID4): @@ -174,13 +156,80 @@ def delete_city(request, id: UUID4): city.delete() return 204, {'detail': ''} +# ==================order============================== +@order_controller.post('create-order', auth=GlobalAuth(), response=MessageOut) +def create_order(request): + current_user = get_object_or_404(User, id=request.auth['pk']) + user_items=Item.objects.filter(user=current_user,ordered=False) + if user_items: + order = Order.objects.create( + user=User.objects.first(), + status=OrderStatus.objects.get(is_default=True), + ref_code = ''.join(random.sample(string.ascii_letters+string.digits,6)), + ordered=False) + user_items.update(ordered=True) + order.items.add(*user_items) + order.total =order.order_total + order.save() + return {'detail': 'order created'} + else: + return {'detail': 'cart is empty'} + + + + +@order_controller.get('Orders', response={ + 200: List[OrderOut], + 404: MessageOut +}) +def orderout(request): + orderout = Order.objects.all() + + if orderout: + return orderout + + return 404, {'detail': 'Not found'} + + +""" +[ + { + "NEW_id": "dcb384f7-98de-4b35-9451-22f8975218df" + }, + { + "REFUNDED_id": "5357bec5-4ce1-45b6-8700-2c9986fa7f2b" + }, + { + "COMPLETED_id": "5c8f472e-79a1-46fa-900f-3c975dd71d6c" + }, + { + "SHIPPED_id": "87d1f525-bf34-4469-8bd0-7437ea3915a0" + }, + { + "PROCESSING_id": "a1207dc4-1052-4ee9-bff7-da67397aeee4" + } +] +""" +@checkout_controller.put('checkout', response={ + 200: OrderOut +}) +def checkout(request,id: UUID4, checkout_in: checkout): + checkout = get_object_or_404(Order, id=id) + checkout.address_id = checkout_in.address_id + checkout.note = checkout_in.note + checkout.ordered = True + checkout.save() + return 200, checkout + + -@order_controller.get('cart', response={ +@order_controller.get('cart', auth=GlobalAuth(), response={ 200: List[ItemOut], 404: MessageOut }) def view_cart(request): - cart_items = Item.objects.filter(user=User.objects.first(), ordered=False) + current_user = get_object_or_404(User, id=request.auth['pk']) + cart_items = Item.objects.filter(user=current_user, ordered=False) if cart_items: return cart_items @@ -188,26 +237,28 @@ def view_cart(request): return 404, {'detail': 'Your cart is empty, go shop like crazy!'} -@order_controller.post('add-to-cart', response={ +@order_controller.post('add-to-cart', auth=GlobalAuth(), response={ 200: MessageOut, # 400: MessageOut }) def add_update_cart(request, item_in: ItemCreate): + current_user = get_object_or_404(User, id=request.auth['pk']) try: - item = Item.objects.get(product_id=item_in.product_id, user=User.objects.first()) + item = Item.objects.get(product_id=item_in.product_id, user=current_user) item.item_qty += 1 item.save() except Item.DoesNotExist: - Item.objects.create(**item_in.dict(), user=User.objects.first()) + Item.objects.create(**item_in.dict(), user=current_user) return 200, {'detail': 'Added to cart successfully'} -@order_controller.post('item/{id}/reduce-quantity', response={ +@order_controller.post('item/{id}/reduce-quantity', auth=GlobalAuth(), response={ 200: MessageOut, }) def reduce_item_quantity(request, id: UUID4): - item = get_object_or_404(Item, id=id, user=User.objects.first()) + current_user = get_object_or_404(User, id=request.auth['pk']) + item = get_object_or_404(Item, id=id, user=current_user) if item.item_qty <= 1: item.delete() return 200, {'detail': 'Item deleted!'} @@ -217,41 +268,25 @@ def reduce_item_quantity(request, id: UUID4): return 200, {'detail': 'Item quantity reduced successfully!'} -@order_controller.delete('item/{id}', response={ + +@order_controller.post('item/{id}/increase-quantity', auth=GlobalAuth(), response={ + 200: MessageOut, +}) +def increase_item_quantity(request, id: UUID4): + current_user = get_object_or_404(User, id=request.auth['pk']) + item = get_object_or_404(Item, id=id, user=current_user) + item.item_qty += 1 + item.save() + + return 200, {'detail': 'Item quantity increased successfully!'} + + +@order_controller.delete('item/{id}', auth=GlobalAuth(), response={ 204: MessageOut }) def delete_item(request, id: UUID4): - item = get_object_or_404(Item, id=id, user=User.objects.first()) + current_user = get_object_or_404(User, id=request.auth['pk']) + item = get_object_or_404(Item, id=id, user=current_user) item.delete() return 204, {'detail': 'Item deleted!'} - - -def generate_ref_code(): - return ''.join(random.sample(string.ascii_letters + string.digits, 6)) - - -@order_controller.post('create-order', auth=GlobalAuth(), response=MessageOut) -def create_order(request): - ''' - * add items and mark (ordered) field as True - * add ref_number - * add NEW status - * calculate the total - ''' - - order_qs = Order.objects.create( - user=User.objects.first(), - status=OrderStatus.objects.get(is_default=True), - ref_code=generate_ref_code(), - ordered=False, - ) - - user_items = Item.objects.filter(user=User.objects.first()).filter(ordered=False) - - order_qs.items.add(*user_items) - order_qs.total = order_qs.order_total - user_items.update(ordered=True) - order_qs.save() - - return {'detail': 'order created successfully'} diff --git a/commerce/models.py b/commerce/models.py index b0446b8..6bc8982 100644 --- a/commerce/models.py +++ b/commerce/models.py @@ -4,11 +4,18 @@ from django.contrib.auth import get_user_model from django.db import models -from config.utils.models import Entity - User = get_user_model() +class Entity(models.Model): + class Meta: + abstract = True + + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + created = models.DateTimeField(editable=False, auto_now_add=True) + updated = models.DateTimeField(editable=False, auto_now=True) + + class Product(Entity): name = models.CharField(verbose_name='name', max_length=255) description = models.TextField('description', null=True, blank=True) @@ -75,7 +82,7 @@ class Item(Entity): ordered = models.BooleanField('ordered', default=False) def __str__(self): - return self.product.name + return f'{self.item_qty}' class OrderStatus(Entity): diff --git a/commerce/schemas.py b/commerce/schemas.py index 5d68396..417fe22 100644 --- a/commerce/schemas.py +++ b/commerce/schemas.py @@ -4,10 +4,11 @@ from ninja.orm import create_schema from pydantic import UUID4 -from commerce.models import Product, Merchant - +from commerce.models import Product, Merchant, Address, Order, OrderStatus +class MessageOut(Schema): + detail: str class UUIDSchema(Schema): @@ -91,3 +92,48 @@ class ItemOut(UUIDSchema, ItemSchema): pass +class AddressSchema(Schema): + work_address:bool = False + address1:str + address2:str + city: CitiesOut + phone:str + +class AddressOut(UUIDSchema, AddressSchema): + user_id:UUID4 + + + +class AddressCreate(Schema): + work_address: bool + address1: str + address2: str + city_id: UUID4 + phone: str + + + + +class orderstatus(UUIDSchema): + pass + + + +class OrderSchema(Schema): + address_id:UUID4=None + note:str=None + total:str + status:orderstatus + ref_code:str + ordered:bool + + +class OrderOut(UUIDSchema, OrderSchema): + user_id:UUID4 + + +class checkout(Schema): + address_id:UUID4 + note:str + status:UUID4 + ordered:bool \ No newline at end of file diff --git a/config/urls.py b/config/urls.py index 3851026..eff661c 100644 --- a/config/urls.py +++ b/config/urls.py @@ -19,7 +19,7 @@ from ninja import NinjaAPI from account.controllers import account_controller -from commerce.controllers import products_controller, address_controller, vendor_controller, order_controller +from commerce.controllers import products_controller, address_controller, vendor_controller, order_controller, city_controller, checkout_controller from config import settings api = NinjaAPI() @@ -28,6 +28,8 @@ api.add_router('addresses', address_controller) api.add_router('vendors', vendor_controller) api.add_router('orders', order_controller) +api.add_router('cities', city_controller) +api.add_router('checkout', checkout_controller) api.add_router('auth', account_controller) urlpatterns = [ diff --git a/requirements.txt b/requirements.txt index 5d025cd..52d6bd8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,16 @@ asgiref==3.4.1 Django==3.2.8 django-ninja==0.16.1 +dnspython==2.1.0 +ecdsa==0.17.0 +email-validator==1.1.3 +idna==3.3 Pillow==8.4.0 +pyasn1==0.4.8 pydantic==1.8.2 +python-jose==3.3.0 pytz==2021.3 +rsa==4.7.2 +six==1.16.0 sqlparse==0.4.2 -typing-extensions==3.10.0.2 +typing-extensions==3.10.0.2 \ No newline at end of file