class User(AbstractUser): is_teacher = models.BooleanField(default=False) is_student = models.BooleanField(default=False) is_admin = models.BooleanField(default=False) school = models.ForeignKey(School, on_delete=models.CASCADE, null=True) date_of_birth = models.DateField(null=True) student_class = models.ForeignKey(Class, on_delete=models.CASCADE, related_name='studentprofile', null=True) academic_year = models.ForeignKey(AcademicYear, on_delete=models.CASCADE, related_name='student_profile', null=True) CHR = 'Christian' MUS = 'Muslim' OTH = "Other" rel = ( (CHR, 'Christian'), (MUS, 'Muslim'), (OTH, 'Other'), ) religion = models.CharField(max_length=100, choices=rel, null=True) # Teacher Specific date_employed = models.DateField(null=True) subject = models.ManyToManyField(Subject) salary = MoneyField(max_digits=10, decimal_places=2, default_currency='NGN', null=True, blank=True) phone_no = models.CharField(max_length=50, null=True) classes = models.ManyToManyField(Class) admission_date = models.DateField(null=True, blank=True) # Student Specific mother_name = models.CharField(max_length=50, null=True) mother_number = models.CharField(max_length=50, null=True) father_name = models.CharField(max_length=50, null=True) father_number = models.CharField(max_length=50, null=True) address = models.CharField(max_length=100, null=True) MALE = 'Male' FEMALE = 'Female' sex = ( (MALE, 'Male'), (FEMALE, 'Female'), ) gender = models.CharField(max_length=100, choices=sex, null=True) image = models.ImageField(default='default-profile-picture.jpg', upload_to=user_upload, null=True) def __str__(self): return self.username def save(self, *args, **kwargs): super().save(*args, **kwargs)
class ModelWithVanillaMoneyField(models.Model): money = MoneyField(max_digits=10, decimal_places=2)
class ModelWithDefaultAsStringWithCurrency(models.Model): money = MoneyField(default='123 USD', max_digits=10, decimal_places=2)
class Order(AbstractPeriod, CommonInfo, ValidationMixin): """The order class.""" filler: Type = OrderAutoFiller copy_contacts: Callable[["Order"], None] = copy_contacts_from_order_to_user notifier: Callable[["Order", bool], None] = notify_order_update validators: List[Callable[["Order"], None]] = [ orders_validators.validate_order_dates, orders_validators.validate_order_status, orders_validators.validate_order_client, orders_validators.validate_order_client_location, orders_validators.validate_order_service_location, orders_validators.validate_order_availability, ] objects: OrdersManager = OrdersManager() STATUS_NOT_CONFIRMED: str = "not_confirmed" STATUS_CONFIRMED: str = "confirmed" STATUS_PAID: str = "paid" STATUS_COMPLETED: str = "completed" STATUS_CANCELED: str = "canceled" STATUS_CHOICES = [ (STATUS_NOT_CONFIRMED, _("not confirmed")), (STATUS_CONFIRMED, _("confirmed")), (STATUS_PAID, _("paid")), (STATUS_COMPLETED, _("completed")), (STATUS_CANCELED, _("canceled")), ] service: "Service" = models.ForeignKey( "services.Service", on_delete=models.PROTECT, related_name="orders", verbose_name=_("service"), ) service_location: "ServiceLocation" = models.ForeignKey( "services.ServiceLocation", on_delete=models.PROTECT, related_name="orders", verbose_name=_("service location"), null=True, blank=True, ) client_location: "UserLocation" = models.ForeignKey( "users.UserLocation", on_delete=models.SET_NULL, related_name="orders", verbose_name=_("client location"), null=True, blank=True, ) client: "User" = models.ForeignKey( "users.User", on_delete=models.PROTECT, related_name="orders", verbose_name=_("user"), ) status = models.CharField( _("status"), max_length=20, choices=STATUS_CHOICES, default=STATUS_NOT_CONFIRMED, ) note = models.CharField( _("note"), null=True, blank=True, max_length=255, ) price = MoneyField( max_digits=settings.D8B_MONEY_MAX_DIGITS, decimal_places=settings.D8B_MONEY_DECIMAL_PLACES, verbose_name=_("price"), null=True, blank=True, validators=[MinMoneyValidator(0)], db_index=True, ) is_another_person = models.BooleanField( default=False, verbose_name=_("Order for another person?"), db_index=True, ) first_name = models.CharField( _("first name"), max_length=30, null=False, blank=True, ) last_name = models.CharField( _("last name"), max_length=150, null=False, blank=True, ) phone = PhoneNumberField( _("phone"), blank=True, null=True, db_index=True, ) def full_clean(self, exclude=None, validate_unique=True): """Validate the object.""" self.filler(self).fill() return super().full_clean(exclude, validate_unique) def clean(self): """Validate the object.""" self.filler(self).fill() return super().clean() def save(self, **kwargs): """Save the object.""" is_created = not bool(self.pk) self.filler(self).fill() super().save(**kwargs) self.copy_contacts() self.notifier(is_created) @property def duration(self) -> float: """Return the order duration.""" delta = self.end_datetime - self.start_datetime return delta.total_seconds() / 60 def __str__(self) -> str: """Return the string representation.""" return f"#{self.pk}: {super().__str__()}" class Meta(CommonInfo.Meta): """The metainformation.""" abstract = False
class Produce(models.Model): name = models.CharField(max_length=255) about = models.TextField(blank=True) category = models.ForeignKey(Category, null=True, blank=True, on_delete=models.PROTECT) is_fresh = models.BooleanField( default=False, verbose_name='Fresh', help_text=_('This is a fresh product (i.e. unprocessed).')) is_glutenfree = models.BooleanField( default=False, verbose_name='Gluten-free', help_text=_('Check if this product is free of gluten.')) is_dairyfree = models.BooleanField( default=False, verbose_name='Dairy-free', help_text=_('Milk is not part of this produce.')) is_nutsfree = models.BooleanField( default=False, verbose_name='Nut-free', help_text=_('Nuts are not part of this produce.')) is_vegan = models.BooleanField( default=False, verbose_name='Vegan', help_text=_('This is not an animal product.')) QUANTITYCHOICE = ( ('kg', 'Kilogram'), ('g', 'Gram'), ('l', 'Litre'), ('b', 'Bushel'), ) price_quantity = models.CharField(max_length=2, choices=QUANTITYCHOICE, null=True, blank=True) price_chf = MoneyField(max_digits=10, decimal_places=2, default_currency='CHF', null=True, blank=True) image = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') labels = models.ManyToManyField( Label, blank=True, help_text=_('What special modes of production were used.')) farms = models.ManyToManyField( Farm, blank=True, related_name='produce', help_text=_('Where is this produce available.')) panels = [ FieldPanel('name'), FieldPanel('farms'), MultiFieldPanel( [ FieldPanel('category'), FieldPanel('about'), ImageChooserPanel('image'), FieldPanel('price_chf'), FieldPanel('price_quantity'), ], heading="Details", classname="col5", ), MultiFieldPanel( [ FieldPanel('is_fresh'), FieldPanel('is_glutenfree'), FieldPanel('is_dairyfree'), FieldPanel('is_nutsfree'), FieldPanel('is_vegan'), FieldPanel('labels'), ], heading="Features", classname="col7", ), ] api_fields = [ APIField('name'), APIField('about'), APIField('category'), APIField('image_thumb', serializer=ImageRenditionField('width-160', source='image')), APIField('image_full', serializer=ImageRenditionField('width-800', source='image')), APIField('labels'), APIField('farms'), ] api_meta_fields = [ 'is_fresh', 'is_glutenfree', 'is_dairyfree', 'is_nutsfree', 'is_vegan', ] def __str__(self): return self.name class Meta: verbose_name_plural = 'Produce'
class ModelWithNonMoneyField(models.Model): money = MoneyField(max_digits=10, decimal_places=2, default_currency='USD') desc = models.CharField(max_length=10)
class InheritorModel(AbstractModel): second_field = MoneyField(max_digits=10, decimal_places=2, default_currency='USD')
class RevisionedModel(models.Model): amount = MoneyField(max_digits=10, decimal_places=2, default_currency='USD')
class InheritedModel(BaseModel): second_field = MoneyField(max_digits=10, decimal_places=2, default_currency='USD')
class MoneyFieldClass(models.Model): """Create a MoneyField datatype to be able to allow serialization""" amount = MoneyField(max_digits=8, decimal_places=2)
class EducationalNeed(models.Model): uuid = models.UUIDField(default=uuid.uuid4, editable=False) date_uuid = models.CharField(max_length=100, blank=True, null=True) user = models.ForeignKey('auth.User') pub_date = models.DateField(default=timezone.now) title = models.CharField(max_length=200) permanent_address = models.TextField() hide_permanent_address = models.BooleanField(default=True) additional_mobile_number = models.CharField( max_length=20, blank=True, null=True, validators=[ RegexValidator(regex='^[0-9]*$', message='Please use only numeric characters.') ]) hide_mobile_number = models.BooleanField(default=True) additional_phone_number = models.CharField( max_length=20, blank=True, null=True, validators=[ RegexValidator(regex='^[0-9]*$', message='Please use only numeric characters.') ]) hide_phone_number = models.BooleanField(default=True) current_address = models.TextField() hide_current_address = models.BooleanField(default=True) college_school_address = models.TextField() college_school_contact_details = models.CharField(max_length=200) view_count = models.IntegerField(default=0) amount_required = MoneyField(max_digits=10, decimal_places=2, default_currency='INR', blank=True, null=True) requirement_description = RichTextField() youtube_url = models.URLField(blank=True, null=True) closed = models.BooleanField(default=False) # Define choices for communication_mode field PHONE = 'PH' MOBILE = 'MO' EMAIL = 'EM' COMMUNICATION_MODE_CHOICES = ( (PHONE, 'Phone'), (MOBILE, 'Mobile'), (EMAIL, 'E-mail'), ) communication_mode = models.CharField( max_length=2, choices=COMMUNICATION_MODE_CHOICES, default=PHONE, ) verified = models.BooleanField(default=False) def __str__(self): return 'Educational Need {}'.format(str(self.pk)) def save(self, *args, **kwargs): if not self.date_uuid: self.date_uuid = self.pub_date.strftime('%Y/%m/%d/') + str( self.uuid) super().save(*args, **kwargs) def create_youtube_embed_link(self): return str(self.youtube_url).replace('watch?v=', 'embed/')
class AdvertisingCampaign(models.Model): name = models.CharField(max_length=128) account = models.ForeignKey('accounts.Account') venue_account = models.ForeignKey('accounts.VenueAccount', blank=True, null=True, on_delete=models.SET_NULL) all_of_canada = models.BooleanField() regions = models.ManyToManyField(Region) budget = MoneyField(max_digits=10, decimal_places=2, default_currency='CAD') ammount_spent = MoneyField(max_digits=18, decimal_places=10, default_currency='CAD') enough_money = models.BooleanField(default=False) started = models.DateTimeField(auto_now=True, auto_now_add=True) ended = models.DateTimeField(auto_now=False, auto_now_add=False, null=True, blank=True) active_from = models.DateTimeField('active to', null=True, blank=True, auto_now=False, auto_now_add=False) active_to = models.DateTimeField('active to', null=True, blank=True, auto_now=False, auto_now_add=False) website = models.URLField() free = models.BooleanField(default=False) objects = money_manager(models.Manager()) admin = AdminAdvertisingCampaignManager() with_unused_money = AdvertisingCampaignWithUnsusedMoney() active = ActiveAdvertisingCampaign() expired = ExpiredAdvertisingCampaign() def save(self, *args, **kwargs): if self.enough_money and self.ammount_spent >= self.budget and self.budget > Money( 0, CAD): inform_user_that_money_was_spent(self) if self.ammount_spent >= self.budget: self.enough_money = False else: self.enough_money = True super(AdvertisingCampaign, self).save(*args, **kwargs) return self def __unicode__(self): return self.name def ammount_remaining(self): return self.budget - self.ammount_spent def regions_representation(self): return ", ".join(self.regions.all().values_list("name", flat=True)) def is_active(self): now = datetime.datetime.now() return (self.enough_money or self.free) and ( not self.active_from or self.active_from < now) and (not self.active_to or self.active_to > now) def is_finished(self): return self.active_to and self.active_to < datetime.datetime.now() def is_future(self): return self.active_from and self.active_from > datetime.datetime.now()
class Model(models.Model): field = MoneyField(**field_kwargs) class Meta: app_label = 'test'
class OrderItem(Timestampable, Annotatable, models.Model): order = models.ForeignKey('shop.Order', null=False, on_delete=models.CASCADE, related_name='order_items') item = models.ForeignKey('shop.Item', null=True, on_delete=models.PROTECT, related_name='order_items') option_items = models.ManyToManyField('shop.Item', related_name='order_items_as_option') # note: duplicates in options and addons are ok, represents quantity addon_items = models.ManyToManyField('shop.Item', related_name='order_items_as_addon') quantity = models.DecimalField(default=1, decimal_places=2, max_digits=8) is_ad_hoc_item = models.BooleanField(default=False) ad_hoc_name = models.CharField(max_length=100, default="", blank=True) ad_hoc_price = MoneyField(max_digits=8, decimal_places=2, null=True, blank=True, default_currency='THB') # MODEL PROPERTIES @property def price(self): logging.debug("calculating price .. again") if self.ad_hoc_price: return self.ad_hoc_price.amount * self.quantity total_amount = self.item.price.amount # add options for option_item in self.option_items.all(): total_amount += (option_item.option_price.amount or option_item.price.amount) # add price.amount for each addon, excluding free addons free_counters = {} for addon_item in self.addon_items.all(): item_addon_group_membership = addon_item.item_addon_group_memberships.filter( addon_group__item_id=self.item_id).order_by( 'custom_addon_price') # order by custom price so free_addon_count is applied to non-custom items first # if never free, find price by hierarchy if item_addon_group_membership.is_never_free: total_amount += ( item_addon_group_membership.custom_addon_price.amount or item_addon_group_membership.addon_group.per_addon_price. amount or item_addon_group_membership.item.price.amount) continue # check against possible addon_free_count and add price if/when necessary addon_group = item_addon_group_membership.addon_group if addon_group.id in free_counters: free_counters[addon_group.id] -= 1 else: free_counters[ addon_group.id] = addon_group.addon_free_count or 0 free_counters[addon_group.id] -= 1 if free_counters[addon_group.id] < 0: total_amount += ( item_addon_group_membership.custom_addon_price.amount or item_addon_group_membership.addon_group.per_addon_price. amount or item_addon_group_membership.item.price.amount) return Money( round(total_amount * self.quantity, 2), # finally round off to nearest 2 decimal places self.item.price.currency) # MODEL FUNCTIONS def get_cart_index_string(self): index_string = f"i{self.item.id}" for option_item in self.option_items.order_by('id'): index_string += f"+o{option_item.id}" for addon_item in self.addon_items.order_by('id'): index_string += f"+a{addon_item.id}" return index_string def get_quantity_display(self): return f'{self.quantity:.0f}' if (self.quantity % 1 == 0) else f'{self.quantity:.2f}' def get_price_amount_display(self): price_amount = self.price.amount return f'{price_amount:.0f}' if (price_amount % 1 == 0) else f'{price_amount:.2f}'
class ModelWithDefaultAsMoney(models.Model): money = MoneyField(default=moneyed.Money('0.01', 'RUB'), max_digits=10, decimal_places=2)
class SimpleModel(models.Model): money = MoneyField(max_digits=10, decimal_places=2, default_currency='USD')
class ModelWithTwoMoneyFields(models.Model): amount1 = MoneyField(max_digits=10, decimal_places=2) amount2 = MoneyField(max_digits=10, decimal_places=3)
class NullMoneyFieldModel(models.Model): field = MoneyField(max_digits=10, decimal_places=2, null=True, default_currency='USD', blank=True)
class AbstractModel(models.Model): money = MoneyField(max_digits=10, decimal_places=2, default_currency='USD') m2m_field = models.ManyToManyField(ModelWithDefaultAsInt) class Meta: abstract = True
class ModelWithCustomManager(models.Model): field = MoneyField(max_digits=10, decimal_places=2) manager = money_manager(MoneyManager())
class BankPayment(models.Model): """Bank payment.""" identifier = models.TextField(verbose_name=_('Payment ID')) uuid = models.UUIDField(unique=True, editable=False, default=uuid.uuid4) payment_type = models.TextField(choices=PAYMENT_TYPE_CHOICES, default=PaymentType.TRANSFER, verbose_name=_('Payment type')) account = models.ForeignKey(BankAccount, on_delete=models.CASCADE, verbose_name=_('Destination account')) create_time = models.DateTimeField(auto_now_add=True, db_index=True, verbose_name=_('Create time')) transaction_date = models.DateField(null=True, db_index=True, verbose_name=_('Transaction date')) counter_account_number = models.TextField(blank=True, verbose_name=_('Counter account number')) counter_account_name = models.TextField(blank=True, verbose_name=_('Counter account name')) amount = MoneyField(max_digits=64, decimal_places=CURRENCY_PRECISION, verbose_name=_('Amount')) description = models.TextField(blank=True, verbose_name=_('Description')) state = models.TextField(choices=PAYMENT_STATE_CHOICES, default=PaymentState.READY_TO_PROCESS, db_index=True, verbose_name=_('Payment state')) card_payment_state = models.TextField(blank=True, verbose_name=_('Card payment state')) processing_error = models.TextField(choices=PROCESSING_ERROR_CHOICES, null=True, blank=True, verbose_name=_('Automatic processing error')) # Payment symbols (specific for Czech Republic and Slovak Republic). constant_symbol = models.CharField(max_length=10, blank=True, verbose_name=_('Constant symbol')) variable_symbol = models.CharField(max_length=10, blank=True, verbose_name=_('Variable symbol')) specific_symbol = models.CharField(max_length=10, blank=True, verbose_name=_('Specific symbol')) processor = models.TextField(verbose_name=_('Processor'), blank=True) card_handler = models.TextField(verbose_name=_('Card handler'), blank=True) class Meta: """Model Meta class.""" unique_together = ('identifier', 'account') verbose_name = _('Bank payment') verbose_name_plural = _('Bank payments') constraints = [ CheckConstraint(check=Q(payment_type=PaymentType.TRANSFER) & ~Q(counter_account_number__exact='') | Q(payment_type=PaymentType.CARD_PAYMENT, counter_account_number__exact=''), name='payment_counter_account_only_for_transfer') ] def __str__(self): """Return string representation of bank payment.""" return self.identifier def clean(self): """Check whether payment currency is the same as currency of related bank account.""" if self.account.currency != self.amount.currency.code: raise ValidationError('Bank payment {} is in different currency ({}) than bank account {} ({}).'.format( self.identifier, self.amount.currency.code, self.account, self.account.currency )) super().clean() @property def advance_invoice(self): """Return advance invoice if it exists.""" invoices = self.invoices.filter(invoice_type=InvoiceType.ADVANCE) return invoices.first() @property def objective(self): """Return processed payment objective.""" if self.processor: return get_processor_objective(self.processor) else: return '' objective.fget.short_description = _('Objective') # type: ignore @classmethod def objective_choices(self): """Return payment processor default objectives choices.""" choices = BLANK_CHOICE_DASH.copy() for proc_name in SETTINGS.processors: proc = get_processor_instance(proc_name) choices.append((proc_name, proc.default_objective)) return choices @classmethod def from_payment_data_class(cls, payment: Payment): """Convert Payment data class from teller to Django model.""" result = cls(identifier=payment.identifier, transaction_date=payment.transaction_date, counter_account_number=cls._value_or_blank(payment.counter_account), counter_account_name=cls._value_or_blank(payment.name), amount=payment.amount, description=cls._value_or_blank(payment.description), constant_symbol=cls._value_or_blank(payment.constant_symbol), variable_symbol=cls._value_or_blank(payment.variable_symbol), specific_symbol=cls._value_or_blank(payment.specific_symbol)) return result @staticmethod def _value_or_blank(value: Optional[str]) -> str: return '' if value is None else value
class ModelWithVanillaMoneyField(models.Model): money = MoneyField(max_digits=10, decimal_places=2) second_money = MoneyField(max_digits=10, decimal_places=2, default_currency='EUR') integer = models.IntegerField(default=0)
class Offer(models.Model): application_id = models.DecimalField(verbose_name="application_id", max_digits=100, decimal_places=0, primary_key=True) nr = models.CharField(verbose_name="number", max_length=100, blank=True, null=True) title = models.CharField(verbose_name="title", max_length=255, blank=True, null=True) status = models.CharField(verbose_name='Status', max_length=255, choices=ENTSCHEIDUNG_STATUS, default='Betätigt') contact_reference = models.ForeignKey(to=Contact, related_name='offers', on_delete=models.CASCADE) contact = models.CharField(verbose_name="contact", max_length=255, blank=True, null=True) contact_number = models.CharField(verbose_name="contact_number", max_length=255, blank=True, null=True) project = models.CharField(verbose_name="project", max_length=100, blank=True, null=True) contact_person_name = models.CharField(verbose_name="contact_person_name", max_length=100, blank=True, null=True) seller = models.CharField(verbose_name='seller', max_length=100, blank=True, null=True) currency = models.CharField(verbose_name="currency", max_length=100, blank=True, null=True) net_amount = MoneyField(verbose_name="net_amount", max_digits=14, decimal_places=2, default_currency='CHF') gross_amount = MoneyField(verbose_name="gross_amount", max_digits=14, decimal_places=2, default_currency='CHF') date = models.DateField(verbose_name="date", blank=True, null=True) due_date = models.DateField(verbose_name="due_date", blank=True, null=True) bank_account = models.CharField(verbose_name='bank_account', max_length=255, blank=True, null=True) created = models.DateTimeField(auto_now_add=True, null=True) updated = models.DateTimeField(auto_now=True, null=True) def __str__(self): return f"{self.application_id}: {self.title} - {self.status}" if self.title is not None else f"{self.application_id}: {self.status}"
class ModelWithDefaultAsStringWithCurrency(models.Model): money = MoneyField(default='123 USD', max_digits=10, decimal_places=2) class Meta: verbose_name = 'model_default_string_currency'
class Listing(models.Model): title = models.CharField(max_length=100, verbose_name=_('Title')) slug = models.SlugField(max_length=100, unique=True, blank=False, verbose_name=_('Slug')) description = models.TextField(verbose_name=_('Description'), null=True, blank=True) price = MoneyField(default=Money(0, USD), max_digits=12, decimal_places=2, verbose_name=_('Price')) location = models.ForeignKey(Location, null=True, blank=True) type = models.CharField(_('Listing Type'), max_length=30, choices=TYPES) offer = models.CharField(max_length=10, choices=OFFERS, verbose_name=_('Offer')) active = models.BooleanField(_('Active'), default=False) featured = models.BooleanField(default=False, verbose_name=_('Featured')) baths = models.PositiveIntegerField(_('Bathrooms'), default=0, null=True, blank=True) beds = models.PositiveIntegerField(_('Bedrooms'), default=0, null=True, blank=True) size = models.PositiveIntegerField(_('Size(m2)'), default=0, null=True, blank=True) coords = models.CharField(max_length=255, default='19.000000,-70.400000', verbose_name=_('Coords'), null=True, blank=True) agent = models.ForeignKey(Agent, null=True, blank=True, verbose_name=_('Agent')) contact = models.ForeignKey(Contact, null=True, blank=True) notes = models.TextField(max_length=500, verbose_name=_('Private Notes'), null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('Created')) last_modified = models.DateTimeField(auto_now=True, verbose_name=_('Last Modified')) objects = ListingManager() @property def main_image(self): im = self.images.all() if im.count(): return im[0] return None @property def image_list(self): return [{ 'title': image.name, 'url': image.absolute_url, 'order': image.order } for image in self.images.all()] @property def address(self): return self.get_address() def get_address(self): if self.location is None: return _('No location provided') return self.location def __unicode__(self): return self.title class Meta: verbose_name = _('Listing') verbose_name_plural = _('Listings') ordering = [ '-pk', ] def save(self, **kwargs): self._generate_valid_slug() super(Listing, self).save(**kwargs) def _generate_valid_slug(self): if not self.is_valid_slug(): slug = slugify(self.title) while Listing.objects.filter(slug=slug).exclude( id=self.id).exists(): slug_parts = slug.split('-') if slug_parts[-1].isdigit(): slug_parts[-1] = '%s' % (int(slug_parts[-1]) + 1) else: slug_parts.append('2') slug = '-'.join(slug_parts) self.slug = slug def is_valid_slug(self): if self.slug is None or len(self.slug) < 10: return False match = re.match('[^\w\s-]', self.slug) if not match: return False return self.slug == slugify(self.slug) @property def absolute_url(self): return self.get_absolute_url() def get_absolute_url(self): return reverse('property_details', args=[self.slug]) def get_features(self): attributes = [] for attribute in self.attributelisting_set.all(): attribute_name = _(attribute.attribute.name) if attribute.attribute.validation == 'realestate.listing.utils.validation_simple': attributes.append('{0}: {1}'.format(attribute_name, attribute.value)) elif attribute.attribute.validation == 'realestate.listing.utils.validation_yesno': attributes.append(attribute_name) else: if attribute.attribute.validation == 'realestate.listing.utils.validation_integer': attributes.append('{0} {1}'.format(attribute.value, attribute_name)) else: attributes.append('{0:.2f} {1}'.format( Decimal(attribute.value), attribute_name)) return attributes @property def nearby(self): return Listing.objects.active(location=self.location).exclude( id=self.id).order_by('?') @property def has_baths_or_beds(self): return self.should_have_beds or self.should_have_baths @property def suggested(self): qs = Listing.objects.active(type=self.type) price = self.price lh = price * .90 rh = price * 1.10 if self.has_baths_or_beds: if self.should_have_baths: qs = qs.filter(baths=self.baths) if self.should_have_beds: qs = qs.filter(beds=self.beds) if qs.count() == 0: qs = Listing.objects.active(type=self.type, price__range=(lh, rh)) else: qs = qs.filter(price__range=(lh, rh)) return qs.exclude(id=self.id).order_by('?') @property def should_have_beds(self): return self.type in ( 'house', 'penthouse', 'apartment', 'villa', ) @property def should_have_baths(self): return 'land' not in self.type @property def on_sale(self): return Deal.objects.on_sale(listing__in=(self, )).exists() @property def code(self): if self.agent is not None: agent = self.agent prefix = '{0}{1}'.format(agent.first_name[0], agent.last_name[0]) return '{0}{1:04}'.format(prefix, self.id).upper() rent_or_sale = 'v' if self.offer in ('buy-rent', 'buy') else 'r' return '{0}{1:04x}'.format(rent_or_sale, self.id).upper()
class ModelWithDefaultAsFloat(models.Model): money = MoneyField(default=12.05, max_digits=10, decimal_places=2, default_currency='PLN')
class ModelWithDefaultAsInt(models.Model): money = MoneyField(default=123, max_digits=10, decimal_places=2, default_currency='GHS')
class ModelWithDefaultAsDecimal(models.Model): money = MoneyField(default=Decimal('0.01'), max_digits=10, decimal_places=2, default_currency='CHF')
class ModelWithDefaultAsString(models.Model): money = MoneyField(default='123', max_digits=10, decimal_places=2, default_currency='PLN')
class Membership(models.Model): """ Organization memberships. Pending: In discussion that we really confident will lead to membership Out of signatures: Agreement has been sent out for signatures (membership eminent) Active: Agreement has been signed and term of agreement has started Dormant: Agreement has been signed but term of agreement has not started Expired: Term of agreement has ended Lead: Interest in membership has been expressed, but an agreement may or may not be likely Stale: At one point was pending or lead, but a membership does now not seem likely """ PENDING = 'PD' OUT4SIGNATURES = 'OS' ACTIVE = 'AC' DORMANT = 'DT' EXPIRED = 'EX' LEAD = 'LD' STALE = 'ST' STATUS_CHOICES = ( (PENDING, 'Pending'), (OUT4SIGNATURES, 'Out for Signatures'), (ACTIVE, 'Active'), (DORMANT, 'Dormant'), (EXPIRED, 'Expired'), (LEAD, 'Lead'), (STALE, 'Stale'), ) NEW = 'N' RENEWAL = 'R' OTHER = 'O' NEW_RENEW_CHOICES = ((NEW, 'New'), (RENEWAL, 'Renewal'), (OTHER, 'Other')) PAID = 'PD' SENT = 'ST' REQUESTED = 'RQ' NOT_READY = 'NR' NUMFOCUS = 'NF' INVOICE_REQUEST = ( (PAID, 'Paid'), (SENT, 'Sent'), (REQUESTED, 'Requested'), (NOT_READY, 'Not ready to request'), (NUMFOCUS, 'Request from NumFOCUS'), ) COMPLETE = 'CP' SCHEDULED = 'SD' # PENDING = 'PD' Already defined SCHINPROGRESS = 'SP' EVENT_STATUS = ((COMPLETE, 'Complete'), (SCHEDULED, 'Scheduled'), (PENDING, 'Pending'), (SCHINPROGRESS, 'Scheduling in Progress')) organization = models.ForeignKey(Organization, on_delete=models.CASCADE, help_text='Long form name of member') member_type = models.ForeignKey(Term, on_delete=models.CASCADE, help_text='Type of membership') status = models.CharField('Status', max_length=2, choices=STATUS_CHOICES, default=LEAD, help_text='Current status of membership') new_renew = models.CharField( 'New or renew?', max_length=1, choices=NEW_RENEW_CHOICES, default=NEW, help_text='Is it a new membership or is it a renewal?') hubspot = models.URLField('Hubspot link', help_text='Hubspot link to member', blank=True, null=True) annual_fee = MoneyField('Annual fee', max_digits=10, decimal_places=2, default_currency='USD', help_text='Annual Fee paid in USD') paid_in_full = models.BooleanField( 'Paid in full?', help_text='Did they pay all their membership up-front?') # term calculated field: expires - start_date in years start_date = models.DateField( 'Starting date', help_text='The starting date for the membership') expires = models.DateField( 'Expiring date', help_text='Calculated as start date plus membership term duration') agreement = models.URLField( 'Agreement Github link', help_text='GitHub repo link for agreement text', blank=True, null=True) invoice_request = models.CharField('Invoice request', max_length=2, choices=INVOICE_REQUEST, help_text='Status of invoice', blank=True, null=True) event_status = models.CharField( 'Event status', max_length=2, choices=EVENT_STATUS, default=PENDING, help_text='Have we held instructor training for them yet?', blank=True, null=True) event = models.URLField('Event', help_text='URLs in AMY for Training event', blank=True, null=True) notes = GenericRelation(Note) def __str__(self): return "{} {} {}".format(self.organization, self.member_type, self.status)