############################################################################# # Copyright (C) 2007 William Waites <ww@styx.org> # # Copyright (C) 2007 Dmytri Kleiner <dk@trick.ca> # # Copyright (C) 2007 Haagenti Group Inc. # # # # This program is free software; you can redistribute it and#or modify # # it under the terms of the GNU General Public License as # # published by the Free Software Foundation; either version 2 of the # # License, or (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public # # License along with this program; if not, write to the # # Free Software Foundation, Inc., # # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################# from django.db import models from django.utils.translation import gettext_lazy as _ from django.contrib.forex.models import Currency from django.contrib.billing.utilities import pFloat, getattr_anyhow from account import Account, Consumer from receipt import Receipt from rate import Rating from billable import DeferRecord __all__ = ['ItemRecord'] class ItemRecordManager(models.Manager): def get_or_create(self, detail, *av, **kw): try: item = self.get(hexdigest = detail.hexdigest) return item, False except self.model.DoesNotExist: item = self.create(detail, *av, **kw) return item, True def create(self, detail, receipt = None, **kw): item = self.model(hexdigest = detail.hexdigest) if receipt: item.receipt = receipt self._update(item, detail, **kw) def update(self, item, detail, **kw): item = self.get(hexdigest = detail.hexdigest) self._update(item, detail, **kw) def _update(self, item, detail, sync = True): def _getattr(detail, attr): if hasattr(detail._meta.billing, attr): attr = getattr(detail._meta.billing, attr) return getattr_anyhow(detail, attr) for attrname in ('consumer', 'chargeDescription', 'chargeTime'): attr = _getattr(detail, attrname) setattr(item, attrname, attr) rateplan = item.consumer.account.rateplan chargeType = _getattr(detail, 'chargeType') chargeCurrency = _getattr(detail, 'chargeCurrency') if not isinstance(detail, models.Model): raise ValueError('%s must be a model' % (detail,)) implementation = '.'.join((detail._meta.app_label, detail._meta.object_name)) try: item.rate = rateplan.rating_set.get(implementation=implementation, chargeType=chargeType) except rateplan.rating_set.model.DoesNotExist: raise DeferRecord("%s has no rating for %s(%s)" % (item.consumer.account, implementation, chargeType)) if callable(detail.charge): charge = detail.charge(item.rate) else: charge = detail.charge for attrname in ('chargedUnits', 'chargeableUnits'): attr = _getattr(detail, attrname) setattr(item, attrname, attr) item.charge = charge * Currency.objects.quote(item.consumer.account.currency, chargeCurrency, item.chargeTime) item.save(sync = sync) return item class ItemRecord(models.Model): class Admin: list_display = ('chargeTime', 'rate', 'consumer', 'chargeDescription', 'charge') list_display_links = ('chargeDescription',) list_filter = ('rate',) search_fields = ('chargeDescription',) date_hierarchy = 'chargeTime' class Meta: ordering = ('-chargeTime',) get_latest_by = 'chargeTime' verbose_name = _('Billable Item') verbose_name_plural = _('Billable Items') __module__ = 'django.contrib.billing.models' hexdigest = models.CharField(maxlength=40) consumer = models.ForeignKey(Consumer, verbose_name = _('Consumer')) receipt = models.ForeignKey(Receipt) rate = models.ForeignKey(Rating) charge = models.DecimalField(max_digits=16, decimal_places=4, default="0.0", verbose_name = _('Charge')) chargeTime = models.DateTimeField(verbose_name = _('Time')) chargeableUnits = models.IntegerField(default = 1, verbose_name = _('Chargeable Units')) chargedUnits = models.IntegerField(default = 1, verbose_name = _('Charged Units')) chargeDescription = models.CharField(blank=True, maxlength=256, verbose_name = _('Description')) objects = ItemRecordManager() def detail(self): if not self.id: self.save() detail = self.rate.get(hexdigest = self.hexdigest) while True: if hasattr(detail, 'detail'): detail = getattr(detail, 'detail') elif callable(detail): detail = detail() else: break return detail def save(self, sync = True): if not self.id: try: self.receipt except Receipt.DoesNotExist: self.receipt = self.consumer.account.receiptForMonth(self.chargeTime) if self.receipt.issued: raise self.receipt.AlreadyIssued super(ItemRecord, self).save() if sync: self.receipt._refresh() def delete(self, sync = True): if self.receipt.issued: raise self.receipt.AlreadyIssued for detail in self.details(): detail.unrecord() receipt = self.receipt super(ItemRecord, self).delete() if sync: receipt._refresh() def __str__(self): return '%s @ %.02f' % (self.chargeDescription, self.charge,)