Skip to content
Snippets Groups Projects
Commit e3a60062 authored by Marc Taylor's avatar Marc Taylor
Browse files

Merge branch 'orders' into 'main'

Orders

See merge request !14
parents 4656710a f01febd2
No related branches found
No related tags found
1 merge request!14Orders
from django.contrib import admin
from .models import Category, Product, Profile
from .models import Category, Product, Profile, Order, OrderItem
# Register your models here.
admin.site.register(Product)
admin.site.register(Category)
admin.site.register(Profile)
\ No newline at end of file
admin.site.register(Profile)
admin.site.register(Order)
admin.site.register(OrderItem)
\ No newline at end of file
from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import gettext_lazy as _
from django.db.models.functions import Now
# Create your models here.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, unique=True)
credit = models.IntegerField(default=0)
user = models.OneToOneField(User, on_delete=models.CASCADE, unique=True)
credit = models.IntegerField(default=0)
class Category(models.Model):
name = models.CharField(max_length=100)
image = models.ImageField(upload_to="products/", default='posts/default.jpg')
name = models.CharField(max_length=100)
image = models.ImageField(upload_to="products/", default='posts/default.jpg')
def __str__(self):
return self.name
def __str__(self):
return self.name
class Product(models.Model):
user_id = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
image = models.ImageField(upload_to="products/", default='posts/default.jpg')
price = models.DecimalField(max_digits=5, decimal_places=2, null=True)
rent_price = models.DecimalField(max_digits=5, decimal_places=2, null=True)
name = models.CharField(max_length=200)
size = models.CharField(max_length=50)
def __str__(self):
return self.name
# CATEGORY_CHOICES = [
# "Christmas",
# "Halloween",
# "College",
# "Easter",
# "Disco",
# "Afterski",
# "Whiteparty",
# "Bachelor",
# "Ice hockey",
# "Football",
# "Valentines Day",
# "Hawaii",
# "Vacation",
# "Kräftskiva",
# "Midsommar",
# "October fest"
# ]
\ No newline at end of file
user_id = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
image = models.ImageField(upload_to="products/", default='posts/default.jpg')
price = models.DecimalField(max_digits=5, decimal_places=2, null=True)
rent_price = models.DecimalField(max_digits=5, decimal_places=2, null=True)
name = models.CharField(max_length=200)
size = models.CharField(max_length=50)
def __str__(self):
return self.name
class Order(models.Model):
buyer_id = models.ForeignKey(User, on_delete=models.CASCADE)
date = models.DateTimeField(auto_now_add=True)
total_price = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
def update_total_price(self):
self.total_price = sum(item.total_price for item in self.orderitem_set.all())
self.save()
class OrderItem(models.Model):
order_id = models.ForeignKey(Order, on_delete=models.CASCADE)
product_id = models.ForeignKey(Product, on_delete=models.CASCADE)
orderType = models.CharField(max_length=10, choices={'buy':'buy', 'rent': 'rent'})
days = models.IntegerField(default=0)
class Meta:
constraints = [
models.UniqueConstraint(fields=['order_id', 'product_id'], name='unique_order_product')
]
# myapp/serializers.py
from rest_framework import serializers
from .models import Product, Profile, Category
from .models import Product, Profile, Category, Order, OrderItem
from django.contrib.auth.models import User
from django.contrib.auth import authenticate, get_user_model
from django.core.exceptions import ValidationError
......@@ -51,11 +51,23 @@ class UserLoginSerializer(serializers.Serializer):
class UserRegisterSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
def create(self, clean_data):
user_obj = User.objects.create_user(username=clean_data['username'], email=clean_data['email'], password=clean_data['password'])
user_obj.username = clean_data['username']
user_obj.save()
return user_obj
\ No newline at end of file
class Meta:
model = User
fields = '__all__'
def create(self, clean_data):
user_obj = User.objects.create_user(username=clean_data['username'], email=clean_data['email'], password=clean_data['password'])
user_obj.username = clean_data['username']
user_obj.save()
return user_obj
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = '__all__'
class OrderItemSerializer(serializers.ModelSerializer):
class Meta:
model = OrderItem
fields = '__all__'
\ No newline at end of file
......@@ -18,4 +18,7 @@ urlpatterns = [
path('home/', views.HomeView.as_view(), name='home'),
path('getproducts/', views.ProductView.as_view(), name='product'),
path('hometry/', views.HomeViewTry.as_view(), name="try"),
path('order/', views.OrderView.as_view(), name='order'),
path('orderItem/', views.OrderItemView.as_view(), name='order_item'),
]
......@@ -3,8 +3,8 @@ from rest_framework import viewsets, status, permissions
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.authentication import SessionAuthentication
from .models import Product, Category, Profile
from .serializers import ProductSerializer, CategorySerializer, ProfileSerializer, UserSerializer, UserLoginSerializer, UserRegisterSerializer
from .models import Product, Category, Profile, Order, OrderItem
from .serializers import ProductSerializer, CategorySerializer, ProfileSerializer, UserSerializer, UserLoginSerializer, UserRegisterSerializer, OrderSerializer, OrderItemSerializer
from django.contrib.auth.models import User
from .validations import *
......@@ -19,7 +19,7 @@ from django.contrib.auth import login, logout
class HomeView(APIView):
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
permission_classes = [permissions.IsAuthenticated]
def get(self, request):
print(request)
......@@ -141,7 +141,6 @@ class ProductView(APIView):
return Response(serializer.data, status=status.HTTP_200_OK)
except:
return Response(status=status.HTTP_404_NOT_FOUND)
# def post(self, request, user_id):
# try:
# data = request.data.copy()
......@@ -153,4 +152,45 @@ class ProductView(APIView):
# return Response(serializer.data, status=status.HTTP_201_CREATED)
# return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# except Exception as e:
# return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
\ No newline at end of file
# return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
class OrderView(APIView):
permission_classes = [permissions.IsAuthenticated]
def get(self, request):
orders = Order.objects.all()
serializer = OrderSerializer(orders, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
def post(self, request):
try:
data = request.data.copy()
user = User.objects.filter(id=data['user_id']).first()
order = Order(buyer_id = user, total_price=data['total_price'])
order.save()
serializer = OrderSerializer(order)
return Response({'order': serializer.data}, status=status.HTTP_200_OK)
except:
return Response(status=status.HTTP_400_BAD_REQUEST)
class OrderItemView(APIView):
permission_classes = [permissions.IsAuthenticated]
def post(self, request):
try:
data = request.data.copy()
order = Order.objects.filter(id=data['order_id']).first()
product = Product.objects.filter(id=data['product_id']).first()
order_item = OrderItem(
order_id=order,
product_id=product,
orderType=data['orderType'],
days=data['days']
)
order_item.save()
serializer = OrderItemSerializer(order_item)
return Response({'order': serializer.data}, status=status.HTTP_200_OK)
except:
return Response(status=status.HTTP_400_BAD_REQUEST)
\ No newline at end of file
......@@ -146,7 +146,6 @@ const [loadingUser, setLoadingUser] = useState(true);
const fetchUser = async () => {
try {
const result = await getLoggedInUser();
console.log('userrrr:', result.id);
setUser(result.id);
// You can perform additional actions here, like updating the UI
} catch (error) {
......@@ -164,12 +163,9 @@ const [loadingUser, setLoadingUser] = useState(true);
const fetchProducts = async () => {
try {
const result = await getAllProducts();
console.log('All Products:', result);
if (user) {
console.log('User ID:', user);
const filteredProducts = result.data.filter(product => product.user_id === user);
console.log('Filtered Products:', filteredProducts);
setProducts(filteredProducts);
} else {
console.warn('User ID is null or undefined');
......
......@@ -2,6 +2,7 @@ import React, { useState } from 'react';
import { useCart } from './CartProvider';
import { List, ListItem, ListItemText, IconButton, Typography, Button, Dialog, DialogContent, DialogTitle, TextField, DialogActions, Box } from '@mui/material';
import DeleteIcon from '@mui/icons-material/Delete';
import { orderItem, createOrder } from '../utils/api';
const Cart = () => {
const { cartItems, removeFromCart } = useCart();
......@@ -30,8 +31,14 @@ const Cart = () => {
setOpenCheckout(false);
};
const handleCheckout = () => {
const handleCheckout = async () => {
// Handle the checkout process here
const totalPrice = getTotalPrice(cartItems);
const orderID = await createOrder(totalPrice);
for (const item of cartItems){
const type = item.type === 'hyr' ? 'rent': 'buy';
await orderItem(orderID, item.id, type, item.days)
}
alert('Checkout successful!');
handleCheckoutClose();
};
......@@ -53,7 +60,13 @@ const Cart = () => {
secondary={
<>
<img src={item.imageUrl} alt="Product" style={{ maxHeight: '50px' }} />
<Typography variant="body2">Typ: {item.type}</Typography>
<Typography variant="body2">
{
item.type === 'hyr' ?
`Hyrs i ${item.days} ${item.days === '1' ? 'dag': 'dagar'}`:
'Köpes'
}
</Typography>
</>
}
/>
......@@ -68,7 +81,9 @@ const Cart = () => {
</Button>
</Box>
)}
<Typography variant='h4' align="center" marginTop={2}>
Totalpris: {getTotalPrice(cartItems)} kr
</Typography>
<Dialog open={openCheckout} onClose={handleCheckoutClose}>
<DialogTitle>Checkout</DialogTitle>
<DialogContent>
......@@ -135,3 +150,16 @@ const Cart = () => {
export default Cart;
/* HelpFunctions for cart*/
const getTotalPrice = (allItems) => {
let totalPrice = 0;
for (const item of allItems) {
console.log(item, totalPrice)
if (item.type === 'hyr'){
totalPrice += parseFloat(item.price) * item.days;
} else {
totalPrice += parseFloat(item.price)
}
}
return totalPrice;
}
......@@ -2,6 +2,7 @@
import React, {useState} from 'react';
import { Card, CardContent, CardMedia, Typography, Dialog, DialogContent, Button } from '@mui/material';
import TextField from '@mui/material/TextField'
import { styled } from '@mui/system';
import { useCart } from './CartProvider'
......@@ -16,9 +17,12 @@ const AnimatedCard = styled(Card)({
const Product = ({ id, imageUrl, price, rentPrice, name, size }) => {
const [open, setOpen] = useState(false);
const {addToCart} = useCart();
const [showRentField, setShowRentField] = useState(false);
const [rentDays, setRentDays] = useState('');
const handleOpen = () => {
setOpen(true);
setShowRentField(false)
};
const handleClose = () => {
......@@ -31,15 +35,20 @@ const Product = ({ id, imageUrl, price, rentPrice, name, size }) => {
handleClose(); // Close the dialog after adding to cart (optional)
};
const handleRentClick = () => {
setShowRentField(true);
}
const handleRent = () => {
// Add rent logic here
addToCart({ id, imageUrl, price: rentPrice, type: 'hyr' });
addToCart({ id, imageUrl, price: rentPrice, type: 'hyr', days: rentDays});
setShowRentField(false)
handleClose(); // Close the dialog after adding to cart
};
const handleBuy = () => {
// Add buy logic here
addToCart({ id, imageUrl, price, type: 'köp' });
addToCart({ id, imageUrl, price, type: 'köp', days: 0});
handleClose(); // Close the dialog after adding to cart
};
......@@ -74,7 +83,16 @@ const Product = ({ id, imageUrl, price, rentPrice, name, size }) => {
<DialogContent>
<img src={imageUrl} alt="Product Image" style={{ maxWidth: '100%' }} />
</DialogContent>
<Button variant="contained" color="primary" onClick={handleRent}>
{showRentField && (
<TextField
label="Number of Days"
value={rentDays}
onChange={(e) => setRentDays(e.target.value)}
fullWidth
style={{ marginTop: 16 }}
/>
)}
<Button variant="contained" color="secondary" onClick={showRentField ? handleRent : handleRentClick} style={{ marginTop: 16 }}>
Hyr
</Button>
<Button variant="contained" color="secondary" onClick={handleBuy} style={{ marginTop: 16 }}>
......
......@@ -47,7 +47,6 @@ export const addProduct = async (img, price, rentPrice, name, size, userID) => {
'Authorization': `Bearer ${TOKEN}`
},
});
console.log('Added product successfully:', response.data);
return response.status
} catch (error) {
console.error('Error in adding product:', error)
......@@ -105,4 +104,44 @@ export const getAllProducts = async () => {
console.log('not auth', e)
return false;
}
}
\ No newline at end of file
}
export const createOrder = async (totalPrice) => {
const user = await getLoggedInUser();
try {
const result = await axios.post('http://127.0.0.1:8000/themeApp/order/', {
'user_id': user.id,
'total_price': totalPrice,
},{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${TOKEN}`
}
});
return result.data.order.id;
} catch (e) {
console.error('Error: ', e)
}
}
export const orderItem = async (orderID, productID, orderType, days=0) => {
try {
const result = await axios.post(`${API_BASE_URL}/themeApp/orderItem/`, {
'order_id': orderID,
'product_id': productID,
'orderType': orderType,
'days': days,
}, {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${TOKEN}`,
}
}
);
console.log('orderItem result:', result);
return result.status
} catch (e) {
console.error('Error: ', e);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment