class RecurringLineItem(models.Model): """Extra information needed for a recurring line item, such as a subscription. To make a trial, put the trial price, tax, etc. into the parent LineItem, and mark this object trial=True, trial_length=xxx """ lineitem = models.OneToOneField(LineItem, verbose_name=_("Line Item"), primary_key=True, related_name="recurdetails") recurring = models.BooleanField( _("Recurring Billing"), help_text= _("Customer will be charged the regular product price on a periodic basis." ), default=False) recurring_price = CurrencyField("Recurring Price", default=Decimal('0.00'), max_digits=18, decimal_places=2) recurring_shipping = CurrencyField("Recurring Shipping Price", default=Decimal('0.00'), max_digits=18, decimal_places=2) recurring_times = models.PositiveIntegerField( _("Recurring Times"), help_text= _("Number of payments which will occur at the regular rate. (optional)" ), default=0) expire_length = models.PositiveIntegerField( _("Duration"), help_text=_("Length of each billing cycle"), null=True, blank=True) trial = models.BooleanField(_("Trial?"), default=False) trial_price = CurrencyField("Trial Price", default=Decimal('0.00'), max_digits=18, decimal_places=2) trial_length = models.PositiveIntegerField( _("Trial length"), help_text="Number of subscription units for the trial", default=0) trial_times = models.PositiveIntegerField( _("Trial Times"), help_text="Number of trial cycles", default=1) SUBSCRIPTION_UNITS = (('DAY', _('Days')), ('MONTH', _('Months'))) expire_unit = models.CharField(_("Expire Unit"), max_length=5, choices=SUBSCRIPTION_UNITS, default="DAY", null=False) SHIPPING_CHOICES = ( ('0', _('No Shipping Charges')), ('1', _('Pay Shipping Once')), ('2', _('Pay Shipping Each Billing Cycle')), )
class PaymentBase(models.Model): method = models.CharField(_("Payment Method"), max_length=25, blank=True) amount = CurrencyField(_("amount"), max_digits=18, decimal_places=2, blank=True, null=True) time_stamp = models.DateTimeField(_("timestamp"), blank=True, null=True) transaction_id = models.CharField(_("Transaction ID"), max_length=45, blank=True, null=True) details = models.CharField(_("Details"), max_length=255, blank=True, null=True) reason_code = models.CharField(_('Reason Code'), max_length=255, blank=True, null=True) def save(self, *args, **kwargs): if not self.pk: self.time_stamp = datetime.now() super(PaymentBase, self).save(*args, **kwargs) class Meta: abstract = True
class Tariff(models.Model): """ digits - префикс передномером 4367890 name - напрвление Austria-mobile Hutchison 3G tariff_plan - номер к какому тарифному плану относится смотреть id TariffPlan """ digits = models.CharField(_(u'Digits'), max_length=45, blank=True, help_text=_(u'matching digits')) code = models.PositiveIntegerField(_(u'Code'), default=0) # TODO: напрвление name = models.CharField(_(u'Направление'), max_length=200, blank=True) country_code = models.IntegerField(_(u'Country Code'), default=0) name_lcr = models.CharField(_(u'Направление по базе LCR'), max_length=200, blank=True) rate = CurrencyField(_(u"Стоимость"), max_digits=18, decimal_places=6, default=Decimal("0.0"), display_decimal=6) #price = MoneyField(max_digits=18, decimal_places=2, default=Money(0, Currency.objects.get_default())) price = models.DecimalField(_(u'Price'), default=Decimal("0"), max_digits=18, decimal_places=6) price_currency = models.CharField(_(u'Currency name'), max_length=3, default="USD") tariff_plan = models.ForeignKey('TariffPlan', related_name='tpg') #tariff = models.ForeignKey(TariffPlan) date_start = models.DateField(_(u'Date Start'), default=datetime.date.today()) date_end = models.DateField(_(u'Date End'), default=datetime.date.max) enabled = models.BooleanField(_(u'Enable'), default=True) weeks = models.SmallIntegerField(_(u'Week'), default=0) time_start = models.TimeField(_(u'Time Start'), default=datetime.datetime.strptime("00:00", "%H:%M")) time_end = models.TimeField(_(u'Time End'), default=datetime.datetime.strptime("23:59", "%H:%M")) cash_min = CurrencyField(_(u"Плата за соединение"), max_digits=18, decimal_places=2, default=Decimal("0.0"), display_decimal=2) time_round = models.SmallIntegerField(_(u'Округление'), default=1, help_text=_(u'Округляем время если 1 то до секунды, 60 до минуты, 30 то полминуты')) operator_type = models.CharField(_(u'Тип'), choices=OPERATOR_TYPE_CHOICES, max_length=1, default='N') #SmallIntegerField(_(u'Тип'), choices=, default=0, help_text=_(u'период за который снимается абонентская плата')) objects =TariffManager() active_objects = GenericManager( enabled = True ) # only active entries inactive_objects = GenericManager( enabled = False ) # only inactive entries class Meta: #ordering = [] db_table = 'tariff' verbose_name, verbose_name_plural = _(u"Тариф"), _(u"Тарифы") def __unicode__(self): return self.name @models.permalink def get_absolute_url(self): return ('Tariff', [self.id]) @property def enabled_date(self): """docstring for enable_date""" de = '' if ru_strftime(format=u"%Y", date=self.date_end) != "9999": de = u" по %s" % ru_strftime(format=u"%d.%m.%Y", date=self.date_end) return u"c {0}{1}".format(ru_strftime(format=u"%d.%m.%Y", date=self.date_start), de) def rate_currency(self): """docstring for rate_currency""" return "%(rate)0.2f %(currency)s" % {'rate': self.rate, 'currency': self.currency} rate_currency.short_description = _(u'Цена 1 мин.') @property def currency(self): return u'у.е.'
class TariffPlan(models.Model): """ Тарифный план Для загрузки тарифного плана из cvs файла необходимо установить его формат Например tariff_format = ;|digits,name,tariff_rate,tariff,date_start=%d.%m.%Y 00:00,date_end ; - разделитель далее через запятую перечисляются поля для заполнения ВНИМАНИЕ все поля обязательны rate стоимость 1 минуты 0.338700 date_start - Дата начала 01.12.08 date_end - Дата окончания 31.12.99 если есть пустая колонка то вставте other если формат даты отличается то необходимо указать формат date_start=%d.%m.%Y 00:00 """ name = models.CharField(_(u'Name'), max_length=80) cash_min = CurrencyField(_(u"Плата за соединение"), max_digits=18, decimal_places=2, default=Decimal("0.00"), display_decimal=2) fee = CurrencyField(_(u"Абонплата"), max_digits=18, decimal_places=2, default=Decimal("0.00"), display_decimal=2) fee_period = models.SmallIntegerField(_(u'Период'), choices=FEE_TARIFF_CHOICES, default=0, help_text=_(u'период за который снимается абонентская плата')) activation = CurrencyField(_(u"Активация"), max_digits=18, decimal_places=2, default=Decimal("0.00"), display_decimal=4, help_text=_(u'стоимость активации тарифного плана')) limit_day = models.IntegerField(_(u'Лимит в День'), default=0, help_text=_(u'Лимит безплатных минут в день 0 - без ограничений')) limit_month = models.IntegerField(_(u'Лимит в Месяц'), default=0, help_text=_(u'Лимит безплатных минут в месяц 0 - без ограничений')) date_start = models.DateField(_(u'Date Start'), default=datetime.date.today()) date_end = models.DateField(_(u'Date End'), default=datetime.date.max) pay_round = models.SmallIntegerField(_(u'Округление'), default=1, help_text=_(u'Округляем стоимость разговора если 1 то до копейки для цен не поумолчанию')) enabled = models.BooleanField(_(u'Enable'), default=True) primary = models.BooleanField(_(u'По умолчанию'), default=False) site = models.ForeignKey(Site, default=1, verbose_name=_('Site')) #tariff_format = models.CharField(_(u'Tariff Format'), default="delimiter=';'time_format='%d.%m.%Y 00:00'lcr|country_code|special_digits|name|rate", max_length=250, help_text=_(u'Формат CSV файла для загрузки тарифного плана')) description = models.CharField(_(u'Description'), blank=True, max_length=240) objects = models.Manager() # default manager must be always on first place! It's used as default_manager active_objects = GenericManager( enabled = True ) # only active entries inactive_objects = GenericManager( enabled = False ) # only inactive entries class Meta: ordering = ['-primary'] db_table = 'tariff_plan' verbose_name, verbose_name_plural = _(u"Тарифный план"), _(u"Тарифные планы") def __unicode__(self): return self.name @models.permalink def get_absolute_url(self): return ('Tarif', [self.id]) def fee_view(self): """docstring for fee_view""" if self.fee_period != 0: return "%(rate)0.2f %(currency)s/%(fp)s/" % {'rate': self.fee, 'currency': self.currency, 'fp': self.get_fee_period_display()} else: return self.get_fee_period_display() fee_view.short_description = _(u'Абонплата') def cash_currency(self): """docstring for rate_currency""" return "%(rate)0.2f %(currency)s" % {'rate': self.cash_min, 'currency': self.currency} cash_currency.short_description = _(u'Плата за соединение.') @property def currency(self): return u'у.е.' @property def enabled_date(self): """docstring for enable_date""" de = '' if ru_strftime(format=u"%Y", date=self.date_end) != "9999": de = u" по %s" % ru_strftime(format=u"%d.%m.%Y", date=self.date_end) return u"c {0}{1}".format(ru_strftime(format=u"%d.%m.%Y", date=self.date_start), de)
class LineItem(models.Model): """A single line item in a purchase. This is optional, only needed for certain gateways such as Google or PayPal.""" sku = models.CharField(_("SKU"), max_length=7, default="1") purchase = models.ForeignKey(Purchase, verbose_name=_("Purchase"), related_name="lineitems") ordering = models.PositiveIntegerField(_('Ordering'), default=0) name = models.CharField(_('Item'), max_length=100) description = models.TextField(_('Description'), blank=True) quantity = models.DecimalField(_("Quantity"), max_digits=18, decimal_places=6, default=Decimal('1')) unit_price = CurrencyField(_("Unit price"), max_digits=18, decimal_places=10) sub_total = CurrencyField(_("Line item price"), max_digits=18, decimal_places=10) shipping = CurrencyField(_("Shipping price"), max_digits=18, decimal_places=10, default=Decimal('0.00')) discount = CurrencyField(_("Line item discount"), max_digits=18, decimal_places=10, default=Decimal('0.00')) tax = CurrencyField(_("Line item tax"), max_digits=18, decimal_places=10, default=Decimal('0.00')) total = CurrencyField(_("Total"), max_digits=18, decimal_places=2, default=Decimal('0.00')) class Meta: ordering = ('ordering', ) @property def int_quantity(self): return self.quantity.quantize(Decimal('1'), ROUND_UP) @property def is_recurring(self): recur = False try: if self.recurdetails and self.recurdetails is not None: recur = True except RecurringLineItem.DoesNotExist: pass return recur def recalc(self): """Recalculate totals""" self.sub_total = self.quantity * self.unit_price self.total = self.sub_total - self.discount + self.tax + self.shipping def __unicode__(self): return "LineItem: %s - %d" % (self.name, self.total)
class Purchase(models.Model): """ Collects information about an order and tracks its state. """ site = models.ForeignKey(Site, verbose_name=_('Site')) client_pk = models.PositiveIntegerField(_(u'Client ID'), null=True) client_ct = models.ForeignKey(ContentType, verbose_name=_(u'Client type'), null=True) client = GenericForeignKey('client_ct', 'client_pk') orderno = models.CharField(_("Order Number"), max_length=20) first_name = models.CharField(_("First name"), max_length=30) last_name = models.CharField(_("Last name"), max_length=30) email = models.EmailField(_("Email"), max_length=75, default="") phone = models.CharField(_("Phone Number"), max_length=30, default="") ship_street1 = models.CharField(_("Street"), max_length=80, default="") ship_street2 = models.CharField(_("Street"), max_length=80, default="") ship_city = models.CharField(_("City"), max_length=50, default="") ship_state = models.CharField(_("State"), max_length=50, default="") ship_postal_code = models.CharField(_("Zip Code"), max_length=30, default="") ship_country = models.CharField(_("Country"), max_length=2, default="") bill_street1 = models.CharField(_("Street"), max_length=80, default="") bill_street2 = models.CharField(_("Street"), max_length=80, default="") bill_city = models.CharField(_("City"), max_length=50, default="") bill_state = models.CharField(_("State"), max_length=50, default="") bill_postal_code = models.CharField(_("Zip Code"), max_length=30, default="") bill_country = models.CharField(_("Country"), max_length=2, default="") sub_total = CurrencyField(_("Subtotal"), max_digits=18, decimal_places=2, blank=True, null=True, display_decimal=4) tax = CurrencyField(_("Tax"), max_digits=18, decimal_places=2, blank=True, null=True, display_decimal=4) shipping = CurrencyField(_("Shipping Cost"), max_digits=18, decimal_places=2, blank=True, null=True, display_decimal=4) total = CurrencyField(_("Total"), max_digits=18, decimal_places=2, display_decimal=4) time_stamp = models.DateTimeField(_("Timestamp"), blank=True, null=True) objects = PurchaseManager() def __unicode__(self): return "Purchase #%s on Order #%s" % (self.id, self.orderno) @property def authorized_remaining(self): """Returns the total value of all un-captured authorizations""" auths = [p.amount for p in self.authorizations.filter(complete=False)] if auths: amount = reduce(operator.add, auths) else: amount = Decimal('0.00') return amount @property def credit_card(self): """Return the credit card associated with this payment. """ for payment in self.payments.order_by('-time_stamp'): try: return payment.creditcard except CreditCardDetail.DoesNotExist: pass return None @property def full_bill_street(self, delim="\n"): """ Return both billing street entries separated by delim. Note - Use linebreaksbr filter to convert to html in templates. """ if self.bill_street2: address = self.bill_street1 + delim + self.bill_street2 else: address = self.bill_street1 return mark_safe(address) def get_pending(self, method, raises=True): pending = self.paymentspending.filter(method__exact=method) if pending.count() > 0: return pending[0] elif raises: raise PaymentPending.DoesNotExist(method) return None @property def partially_paid(self): remaining = self.remaining return remaining > 0 and remaining < self.total def recalc(self): if self.lineitems.count() > 0: subtotal = Decimal('0.00') shipping = Decimal('0.00') tax = Decimal('0.00') for item in self.lineitems.all(): subtotal += item.sub_total shipping += item.shipping tax += item.tax self.sub_total = subtotal zero = Decimal('0.00') if shipping > zero and self.shipping == zero: self.shipping = shipping if self.shipping == None: self.shipping = zero if tax > zero and self.tax == zero: self.tax = tax if self.tax == None: self.tax = zero self.total = self.sub_total + self.tax + self.shipping log.debug( "Purchase #%s recalc: sub_total=%s, shipping=%s, tax=%s, total=%s", self.id, self.sub_total, self.shipping, self.tax, self.total) def recurring_lineitems(self): """Get all recurring lineitems""" subscriptions = [ item for item in self.lineitems.all() if item.is_recurring ] return subscriptions @property def remaining(self): """Return the total less the payments and auths""" return self.total - self.total_payments - self.authorized_remaining def save(self, **kwargs): """ Copy addresses from contact. If the order has just been created, set the create_date. """ if not self.pk: self.time_stamp = datetime.now() try: site = self.site except Site.DoesNotExist: site = None if not site: self.site = Site.objects.get_current() super(Purchase, self).save(**kwargs) @property def total_payments(self): """Returns the total value of all completed payments""" payments = [p.amount for p in self.payments.filter(success=True)] if payments: amount = reduce(operator.add, payments) else: amount = Decimal('0.00') log.debug("total payments for %s=%s", self, amount) return amount
class Balance(models.Model): """(Balance description)""" #accountcode = models.OneToOneField(User, verbose_name=_(u'username'), parent_link=True, primary_key=True) #accountcode = models.OneToOneField(User, verbose_name=_(u'username'), blank=False, related_name="balances") accountcode = AutoOneToOneField(User, verbose_name=_(u'username'), primary_key=True) #accountcode = models.ForeignKey(Contact) #cash = models.DecimalField(_("Balance"), max_digits=18, decimal_places=2) #cash = models.DecimalField(_("Balance"), max_digits=18, decimal_places=2, default=Decimal("0.00")) cash = CurrencyField(_("Balance"), max_digits=18, decimal_places=6, default=Decimal("0.00"), display_decimal=2) tariff = models.ForeignKey(TariffPlan, default=1, verbose_name=_('Tariff Plan'), related_name='tariffplangroup') enabled = models.BooleanField(_(u'Enable'), default=True) objects = BalanceManager( ) # default manager must be always on first place! It's used as default_manager active_objects = GenericManager(enabled=True) # only active entries inactive_objects = GenericManager(enabled=False) # only inactive entries timelimit = models.FloatField(_(u'Limit'), blank=False, default=0, help_text=_(u'Time limit')) credit = CurrencyField( _("Discount Amount"), decimal_places=2, display_decimal=2, max_digits=8, default=Decimal("0.0"), help_text=_(u'Total sum for which credit is extended for calls')) #credit = models.DecimalField(_(u'Credit'), max_digits=18, decimal_places=2, default=Decimal('0.0'), help_text=_(u'Total sum for which credit is extended for calls')) site = models.ForeignKey(Site, default=1, verbose_name=_('Site')) class Meta: #ordering = [] db_table = 'balance' verbose_name, verbose_name_plural = _(u"Balance"), _(u"Balances") permissions = (("api_view", "Can api view"), ) # def __unicode__(self): # return self.accountcode.username @models.permalink def get_absolute_url(self): return ('Balance', [self.id]) @property def vcash(self): if self.credit > Decimal('0'): cash = self.cash + self.credit return "{0:0.2f}".format(cash) else: return "{0:0.2f}".format(self.cash) @property def vcredit(self): if self.credit > Decimal('0'): return "{0:0f}".format(self.credit) else: return None def cash_currency(self): """docstring for rate_currency""" return u"{0:0.2f} {1}".format(self.cash, self.currency) cash_currency.short_description = _(u'Баланс') # def username(self): # #return "<a href='/admin/auth/user/{2}/'>{0} {1}</a>".format(self.accountcode.first_name, self.accountcode.last_name, self.accountcode.pk) # return "{0} {1}".format(self.accountcode.first_name, self.accountcode.last_name) # username.short_description = _(u'Имя Фамилия') # # def last_login(self): # return self.accountcode.last_login # last_login.short_description = _('last login') # # def date_joined(self): # return self.accountcode.date_joined # date_joined.short_description = _('date joined') # # def accountcode_name(self): # return self.accountcode.username # accountcode_name.short_description = _('username') @property def currency(self): return u'у.е.' @property def is_positiv(self): if self.cash > Decimal('0'): return True else: return False @property def is_tariff(self): tcash = "{0:0.2f}{1}".format(self.cash + self.credit, self.credit) if len(tcash) > 9: return False else: return True def cash_add(self, amount): if Decimal(amount) > 0: self.cash += Decimal(amount) else: self.cash -= Decimal(amount) def cash_del(self, amount): if Decimal(amount) > 0: self.cash -= Decimal(amount) else: self.cash += Decimal(amount)