You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
200 lines
6.7 KiB
200 lines
6.7 KiB
from django.conf import settings |
|
from django.db import models |
|
from django.core.files import File |
|
from django.contrib.auth.models import User |
|
from django.db.models.signals import pre_save, post_save |
|
from django.db.models.signals import pre_delete |
|
from django.dispatch import receiver |
|
from django_auth_ldap.backend import populate_user |
|
from django.utils.translation import ugettext_lazy as _ |
|
from django.utils.translation import ugettext_noop |
|
from django.db import transaction |
|
import PIL |
|
import StringIO |
|
|
|
class Account(models.Model): |
|
user = models.OneToOneField(User) |
|
card_number = models.CharField(max_length=32, unique=True, blank=True, |
|
null=True, verbose_name = _('card number')) |
|
pin = models.CharField(max_length=32, blank=True, verbose_name = _('PIN')) |
|
daily_digest = models.BooleanField(verbose_name = _('daily digest'), default=True) |
|
credit = models.DecimalField(max_digits=5, decimal_places=2, default=0, |
|
verbose_name = _('credit')) |
|
|
|
def __unicode__(self): |
|
return self.user.username |
|
|
|
class Meta: |
|
verbose_name = _('account') |
|
verbose_name_plural = _('accounts') |
|
|
|
@receiver(post_save, sender=User) |
|
def user_post_save_handler(sender, instance, created, **kwargs): |
|
if created: |
|
# We don't have ldap_user on creation, so just add the account |
|
account = Account(user=instance) |
|
account.save() |
|
else: |
|
# When we already have an account, |
|
# we can add the number form LDAP (mongo shit) |
|
if hasattr(instance, 'ldap_user') \ |
|
and instance.ldap_user.attrs.has_key('employeenumber'): |
|
instance.account.card_number = \ |
|
instance.ldap_user.attrs['employeenumber'][0] |
|
instance.account.save() |
|
|
|
@transaction.atomic |
|
def change_credit(self, amount, subject, desc): |
|
# For atomicity fetch current value first |
|
cur = Account.objects.filter(pk=self.pk)[0] |
|
self.credit = cur.credit + amount |
|
self.save() |
|
|
|
trans = Transaction(account=self, subject=subject, |
|
amount=amount, description=desc) |
|
trans.save() |
|
|
|
def buy_products(self, products): |
|
# TODO place it somewhere else |
|
MAX_DEBIT = -35 |
|
BUY_SUBJECT = ugettext_noop('Purchase') |
|
|
|
if min(products.values()) <= 0: |
|
raise ValueError('Non-positive amount in products dict.') |
|
|
|
total_value = sum(map(lambda p: p.price * products[p], products.keys())) |
|
if self.credit - total_value >= MAX_DEBIT: |
|
desc = '' |
|
for product in products.keys(): |
|
if not product.active: |
|
raise ValueError('Trying to buy a disabled product.') |
|
amount = products[product] |
|
|
|
logentry = SalesLogEntry(account=self, product=product, |
|
count=amount, unit_price=product.price) |
|
logentry.save() |
|
|
|
desc += '%d x %s\n' % (amount, product.name) |
|
|
|
self.change_credit(-total_value, BUY_SUBJECT, desc) |
|
return True |
|
else: |
|
return False |
|
|
|
def buy_product(self, product, amount=1): |
|
return self.buy_products({product: amount}) |
|
|
|
def set_pin(self, pin): |
|
# TODO: hash pin |
|
self.pin = pin |
|
self.save() |
|
|
|
def clear_pin(self): |
|
self.pin = '' |
|
self.save() |
|
|
|
def check_pin(self, pin): |
|
return pin == self.pin |
|
|
|
class ProductCategory(models.Model): |
|
name = models.CharField(max_length=32, unique=True, |
|
verbose_name = _('name')) |
|
comment = models.CharField(max_length=128, blank=True, |
|
verbose_name = _('comment')) |
|
|
|
def __unicode__(self): |
|
return "%s (%s)" % (self.name, self.comment) |
|
|
|
class Meta: |
|
verbose_name = _('product category') |
|
verbose_name_plural = _('product categories') |
|
|
|
class Product(models.Model): |
|
name = models.CharField(max_length=32, unique=True, |
|
verbose_name = _('name')) |
|
price = models.DecimalField(max_digits=5, decimal_places=2, |
|
verbose_name = _('price')) |
|
active = models.BooleanField(default = True, verbose_name = _('active')) |
|
category = models.ForeignKey(ProductCategory, blank=True, null=True, |
|
verbose_name = _('category')) |
|
image = models.ImageField(upload_to="products", verbose_name = _('image'), |
|
blank=True, null=True) |
|
image_thumbnail = models.ImageField(upload_to="products_thumb", |
|
verbose_name = _('image'), |
|
blank=True, null=True) |
|
|
|
def __unicode__(self): |
|
return self.name |
|
|
|
class Meta: |
|
verbose_name = _('product') |
|
verbose_name_plural = _('products') |
|
|
|
@receiver(pre_save, sender=Product) |
|
def product_post_save_handler(sender, instance, **kwargs): |
|
img = instance.image |
|
if img: |
|
scaledFile = StringIO.StringIO() |
|
img.open(mode='r') |
|
with img: |
|
scaled = PIL.Image.open(img) |
|
thumbnail_size = getattr(settings, 'THUMBNAIL_SIZE', (150, 150)) |
|
scaled.thumbnail(thumbnail_size, PIL.Image.ANTIALIAS) |
|
scaled.save(scaledFile, 'PNG') |
|
scaledFile.seek(0) |
|
|
|
instance.image_thumbnail.save(img.url, File(scaledFile), save=False) |
|
|
|
|
|
class ProductBarcode(models.Model): |
|
barcode = models.CharField(max_length=32, unique=True, |
|
verbose_name = _('barcode')) |
|
comment = models.CharField(max_length=128, blank=True, |
|
verbose_name = _('comment')) |
|
product = models.ForeignKey(Product, verbose_name = _('product')) |
|
|
|
def __unicode__(self): |
|
return self.barcode |
|
|
|
class Meta: |
|
verbose_name = _('barcode') |
|
verbose_name_plural = _('barcodes') |
|
|
|
class Transaction(models.Model): |
|
account = models.ForeignKey(Account, verbose_name = _('account')) |
|
timestamp = models.DateTimeField(auto_now_add=True, |
|
verbose_name = _('timestamp')) |
|
subject = models.CharField(max_length=32, verbose_name = _('subject')) |
|
description = models.TextField(verbose_name = _('description')) |
|
amount = models.DecimalField(max_digits=5, decimal_places=2, |
|
verbose_name = _('amount')) |
|
|
|
class Meta: |
|
verbose_name = _('transaction') |
|
verbose_name_plural = _('transactions') |
|
|
|
class SalesLogEntry(models.Model): |
|
account = models.ForeignKey(Account, verbose_name = _('account')) |
|
product = models.ForeignKey(Product, verbose_name = _('product')) |
|
count = models.IntegerField(verbose_name = _('count')) |
|
unit_price = models.DecimalField(max_digits=5, decimal_places=2, |
|
verbose_name = _('unit price')) |
|
timestamp = models.DateTimeField(auto_now_add=True, |
|
verbose_name = _('timestamp')) |
|
|
|
def __unicode__(self): |
|
return '%dx %s - %s' % (self.count, self.product, self.account) |
|
class Meta: |
|
verbose_name = _('sales log entry') |
|
verbose_name_plural = _('sales log entries') |
|
|
|
@receiver(pre_delete, sender=SalesLogEntry) |
|
def logentry_pre_delete_handler(sender, instance, **kwargs): |
|
SUBJECT = ugettext_noop('Cancellation') |
|
DESC = '%d x %s' |
|
|
|
instance.account.change_credit( |
|
instance.unit_price * instance.count, |
|
SUBJECT, DESC % (instance.count, instance.product.name) |
|
) |
|
|
|
|