from django.db import models
from django.utils.html import format_html
from django.contrib.postgres.fields import HStoreField, ArrayField
from taggit.managers import TaggableManager
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from mptt.models import MPTTModel, TreeForeignKey, TreeManyToManyField
from djrichtextfield.models import RichTextField
from django_editorjs_fields import EditorJsJSONField # Django >= 3.1
from django_editorjs_fields import EditorJsTextField
from filebrowser.fields import FileBrowseField
import qrcode
import base64
import uuid
from django.conf import settings
from django_google_maps.fields import AddressField, GeoLocationField
from phonenumber_field.modelfields import PhoneNumberField
# Create your models here.
PROCESS = "process"
STATUS_CHOICES = [
('process', 'Process'),
('fn', 'Finished'),
('purchase', 'Purchase')
]
GENDER_CHOICES = [
('na', 'N/A'),
('lgbt', 'LGBT'),
('male', 'Male'),
('female', 'Female'),
]
MENU_GROUP_CHOICES = [
('primary', 'Primary'),
('footer', 'Footer'),
('secondary', 'Secondary'),
]
class Profile(models.Model):
STORE_OWNER = 1
CHEF = 2
EMPLOYEE = 3
ROLE_CHOICES = (
(STORE_OWNER, 'Store Owner'),
(CHEF, 'Chef'),
(EMPLOYEE, 'Employee'),
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
location = models.CharField(max_length=30, blank=True)
birthdate = models.DateField(null=True, blank=True)
role = models.PositiveSmallIntegerField(choices=ROLE_CHOICES, null=True, blank=True)
store = models.ForeignKey('Store', on_delete=models.CASCADE, null=True, blank=False)
def __str__(self): # __unicode__ for Python 2
return self.user.username
@receiver(post_save, sender=User)
def create_or_update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
else:
try:
instance.profile.save()
except:
Profile.objects.create(user=instance)
class GeneralField(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
class Meta:
abstract = True
class ProcesslField(models.Model):
inProcess = models.CharField(max_length=100, blank=True, null=True)
status = models.CharField(max_length=100,choices=STATUS_CHOICES,default=PROCESS)
class Meta:
abstract = True
class MenuItem(GeneralField, models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField(blank=True, null=True)
store = models.ForeignKey('Store', on_delete=models.CASCADE)
qrCode = models.FileField(blank=True, null=True, upload_to='uploads/%Y/%m/%d/')
featureImage = models.ImageField(upload_to='uploads/%Y/%m/%d/', blank=True, null=True)
description = models.TextField(blank=True, null=True)
'''
photos = ArrayField(
models.FileField(upload_to='uploads/%Y/%m/%d/'),
size=8,blank=True,null=True)
'''
def __str__(self):
return self.name
def save(self, *args, **kwargs):
self.qrCode.name = self.genCode()
super(MenuItem, self).save(*args, **kwargs)
@property
def qrImage(self):
if self.qrCode:
return format_html('
', self.qrCode.url)
else:
return "-"
def genCode(self):
img = qrcode.make(f"{self.store.name}#{self.name}#{self.id}")
rid = uuid.uuid4().hex
path = settings.MEDIA_ROOT+f"/qr/{rid}.png"
rpath = f"qr/{rid}.png"
img.save(path)
return rpath
class Ingredient(GeneralField, models.Model):
name = models.CharField(max_length=200)
qty = models.DecimalField(decimal_places=2, max_digits=5)
unit = models.CharField(max_length=10)
comment = models.TextField(blank=True, null=True)
menu = models.ForeignKey('MenuItem', on_delete=models.CASCADE)
class Store(GeneralField, models.Model):
name = models.CharField(max_length=100, blank=False, null=False, default="Unititled")
addressText = models.TextField(blank=True, null=True)
province = models.CharField(max_length=100, blank=True, null=True)
storeType = models.CharField("Store Type", max_length=100, blank=True, null=True)
qrCode = models.FileField(blank=True, null=True, upload_to='uploads/%Y/%m/%d/')
description = models.TextField(blank=True, null=True)
address = AddressField(max_length=100, null=True, blank=True)
geolocation = GeoLocationField(blank=True, null=True)
logo = models.ImageField(blank=True, null=True, upload_to='uploads/%Y/%m/%d/')
phone_number = PhoneNumberField(blank=True, null=True)
fax_number = PhoneNumberField(blank=True, null=True)
lineId = models.CharField(max_length=100, blank=True, null=True)
email = models.EmailField(max_length=200, blank=True, null=True)
'''
photos = ArrayField(
models.FileField(upload_to='uploads/%Y/%m/%d/'),
size=8,blank=True,null=True)
'''
def __str__(self):
return f"{self.name}"
def save(self, *args, **kwargs):
self.qrCode.name = self.genCode()
super(Store, self).save(*args, **kwargs)
@property
def qrImage(self):
if self.qrCode:
return format_html('
', self.qrCode.url)
else:
return "-"
def genCode(self):
img = qrcode.make(f"{self.name}#{self.id}")
rid = uuid.uuid4().hex
path = settings.MEDIA_ROOT+f"/qr/{rid}.png"
rpath = f"qr/{rid}.png"
img.save(path)
return rpath
class Table(GeneralField, models.Model):
store = models.ForeignKey('Store', on_delete=models.CASCADE)
code = models.CharField(max_length=100, default="N\A")
nSeats = models.IntegerField(default=1)
occupy = models.BooleanField(default=False)
qrCode = models.FileField(blank=True, null=True, upload_to='uploads/%Y/%m/%d/')
def __str__(self):
return f"{self.code}"
def save(self, *args, **kwargs):
self.qrCode.name = self.genCode()
super(Table, self).save(*args, **kwargs)
@property
def qrImage(self):
if self.qrCode:
return format_html('
', self.qrCode.url)
else:
return "-"
def genCode(self):
img = qrcode.make(f"{self.store.name}#{self.code}")
rid = uuid.uuid4().hex
path = settings.MEDIA_ROOT+f"/qr/{rid}.png"
rpath = f"qr/{rid}.png"
img.save(path)
return rpath
class BookingTable(GeneralField, models.Model):
table = models.ForeignKey(Table, on_delete=models.CASCADE)
onDate = models.DateField(null=True)
onTime = models.TimeField(null=True)
note = models.TextField(blank=True, null=True)
store = models.ForeignKey('Store', on_delete=models.CASCADE, null=True)
qrCode = models.FileField(blank=True, null=True, upload_to='uploads/%Y/%m/%d/')
def __str__(self):
return f"{self.table}@{self.onDate}({self.note})"
def save(self, *args, **kwargs):
self.qrCode.name = self.genCode()
super(BookingTable, self).save(*args, **kwargs)
@property
def qrImage(self):
if self.qrCode:
return format_html('
', self.qrCode.url)
else:
return "-"
def genCode(self):
img = qrcode.make(f"{self.store.name}#{self.table.code}#{self.onDate}@{self.onTime}")
rid = uuid.uuid4().hex
path = settings.MEDIA_ROOT+f"/qr/{rid}.png"
rpath = f"qr/{rid}.png"
img.save(path)
return rpath
class Order(GeneralField, models.Model):
PURCHASE = 'purchase'
table = models.ForeignKey(Table, null=True, on_delete=models.SET_NULL)
note = models.TextField(blank=True, null=True)
store = models.ForeignKey('Store', on_delete=models.SET_NULL, default=None, null=True)
#items = models.ManyToManyField(MenuItem)
qrCode = models.FileField(blank=True, null=True, upload_to='uploads/%Y/%m/%d/')
def save(self, *args, **kwargs):
self.qrCode.name = self.genCode()
super(Order, self).save(*args, **kwargs)
@property
def qrImage(self):
if self.qrCode:
return format_html('
', self.qrCode.url)
else:
return "-"
def genCode(self):
img = qrcode.make(f"{self.store.name}#{self.table.code}#{self.id}")
rid = uuid.uuid4().hex
path = settings.MEDIA_ROOT+f"/qr/{rid}.png"
rpath = f"qr/{rid}.png"
img.save(path)
return rpath
class OrderItem(GeneralField, models.Model):
item = models.ForeignKey(MenuItem, on_delete=models.CASCADE)
qty = models.IntegerField(default=1)
order = models.ForeignKey(Order, on_delete=models.CASCADE)
note = models.TextField(blank=True, null=True)
store = models.ForeignKey('Store', on_delete=models.SET_NULL, default=None, null=True)
@property
def store_items(self):
return MenuItem.objects.filter(store = order.store)
class StoreFile(GeneralField, models.Model):
store = models.ForeignKey('Store', on_delete=models.CASCADE)
storeFile = models.FileField(upload_to='uploads/%Y/%m/%d/')
tags = TaggableManager(blank=True)
class MenuFile(GeneralField, models.Model):
menuItem = models.ForeignKey('MenuItem', on_delete=models.CASCADE, null=True)
menuFile = models.FileField(upload_to='uploads/%Y/%m/%d/')
tags = TaggableManager(blank=True)
class Setting(GeneralField, models.Model):
store = models.OneToOneField(Store, on_delete=models.CASCADE, primary_key=True)
data = HStoreField(blank=True, null=True)
note = models.CharField(max_length=200, blank=True, null=True)
class UIMenu(GeneralField,MPTTModel, models.Model):
name = models.CharField(max_length=200)
parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
group = models.CharField(choices=MENU_GROUP_CHOICES, max_length=200, default='primary')
url = models.CharField(max_length=200)
icon = models.CharField(max_length=100, blank=True, null=True, default='file')
store = models.ForeignKey('Store', on_delete=models.CASCADE, default=None, null=True)
nOrder = models.IntegerField(default=1)
class MPTTMeta:
order_insertion_by = ['-nOrder']
def __str__(self):
return f"{self.name}"
class PostCategory(MPTTModel, models.Model):
name = models.CharField(max_length=200)
parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
class MPTTMeta:
order_insertion_by = ['name']
def __str__(self):
return f"{self.name}"
class Post(GeneralField, models.Model):
title = models.CharField(max_length=200)
content = RichTextField(blank=True)
description = models.TextField(blank=True, null=True)
store = models.ForeignKey('Store', on_delete=models.CASCADE, default=None, null=True)
category = TreeManyToManyField(PostCategory, blank=True, null=True)
featureImage = models.ImageField(upload_to='uploads/%Y/%m/%d/', blank=True, null=True)
tags = TaggableManager(blank=True)
relateMenus = models.ManyToManyField('MenuItem', blank=True, null=True)
#photos = ArrayField(models.ImageField(upload_to='uploads/%Y/%m/%d/'), blank=True, null=True)
@property
def cats(self):
return ",".join([ c.name for c in self.category.all()])
def __str__(self):
return f"{self.title}"
class PostFile(GeneralField, models.Model):
post = models.ForeignKey('Post', on_delete=models.CASCADE)
file = models.FileField(upload_to='uploads/%Y/%m/%d/')
tags = TaggableManager(blank=True)
class Customer(GeneralField, models.Model):
fullName = models.CharField(max_length=200)
email = models.EmailField(blank=True, null=True)
lineId = models.CharField(max_length=100, blank=True, null=True)
gender = models.CharField(choices=GENDER_CHOICES, default='na', max_length=40)
store = models.ForeignKey('Store', on_delete=models.CASCADE, default=None, null=True)
qrCode = models.FileField(blank=True, null=True, upload_to='uploads/%Y/%m/%d/')
def save(self, *args, **kwargs):
self.qrCode.name = self.genCode()
super(Customer, self).save(*args, **kwargs)
@property
def qrImage(self):
if self.qrCode:
return format_html('
', self.qrCode.url)
else:
return "-"
def genCode(self):
img = qrcode.make(f"{self.fullName}#{self.email}#{self.lineId}#{self.store.name}")
rid = uuid.uuid4().hex
path = settings.MEDIA_ROOT+f"/qr/{rid}.png"
rpath = f"qr/{rid}.png"
img.save(path)
return rpath
class Message(GeneralField, MPTTModel, models.Model):
subject = models.CharField(max_length=255)
email = models.EmailField()
lineId = models.CharField(max_length=200, blank=True, null=True)
body = models.TextField()
reply = models.TextField(blank=True, null=True)
store = models.ForeignKey("Store", on_delete=models.CASCADE)
parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
tel = PhoneNumberField(blank=True, null=True)
messageFile = models.FileField(blank=True, null=True, upload_to='uploads/%Y/%m/%d/')
def __str__(self):
return f"{self.subject} {self.created_at}"
class Code(GeneralField, models.Model):
store = models.OneToOneField('Store', on_delete=models.CASCADE, default=None, null=True)
jsCode = models.TextField(blank=True)
cssCode = models.TextField(blank=True)
pluginCode = models.TextField(blank=True)
# body_default = models.TextField()
# body_editorjs = EditorJsJSONField(
# plugins=[
# "@editorjs/image",
# "@editorjs/header",
# "editorjs-github-gist-plugin",
# "@editorjs/code@2.6.0", # version allowed :)
# "@editorjs/list@latest",
# "@editorjs/inline-code",
# "@editorjs/table",
# '@editorjs/raw',
# '@editorjs/embed',
# ],
# ) # Django >= 3.1
# body_editorjs_text = EditorJsTextField()
# image = FileBrowseField("Image", max_length=200, directory="images/", extensions=[".jpg"], blank=True)
# document = FileBrowseField("PDF", max_length=200, directory="documents/", extensions=[".pdf",".doc"], blank=True)
# code = models.TextField(blank=True)