class InheritorModel(AbstractModel): second_field = MoneyField(max_digits=10, decimal_places=2, default_currency='USD')
class ProviderProduct(models.Model): TERNARY_YES_NO_CHOICES = ( ('Unknown', 'Unknown'), ('Yes', 'Yes'), ('No', 'No'), ) # product = models.ForeignKey(Product, on_delete=models.CASCADE) name = models.CharField(max_length=255, verbose_name="Product Name") dateInfoAdded = models.DateTimeField(auto_now_add=True, verbose_name='Record created date') dateInfoUpdated = models.DateTimeField( auto_now=True, verbose_name='Date information updated', help_text="This is automatic.") category = models.ForeignKey(ProductCategory, on_delete=models.PROTECT, verbose_name="Product Category") image = models.ImageField(null=True, blank=True, default=None, upload_to='product_images') provider = models.ForeignKey(Provider, on_delete=models.CASCADE) capacityValue = models.IntegerField(null=True, blank=True, default=None, verbose_name="Capacity (value)") capacityMeasurement = models.ForeignKey( CapacityMeasurement, null=True, blank=True, default=None, on_delete=models.SET_NULL, verbose_name="Capacity (Measurement)") description = models.TextField( null=True, blank=True, default=None, help_text="Discription shown in search view", verbose_name="Product Description") notes = models.TextField(null=True, blank=True, default=None, verbose_name="Additional Notes") packSize = models.TextField( null=True, blank=True, default=None, help_text="Unit size of orders and other details", verbose_name="Packaging Info") ####################################################################### # The following may need to be "Provider Specific" ####################################################################### productLiabilityInsurance = models.CharField( max_length=20, choices=TERNARY_YES_NO_CHOICES, default='Unknown', verbose_name='Has insurance') productLiabilityInsuranceAmount = MoneyField( max_digits=10, decimal_places=0, default_currency='USD', null=True, blank=True, default=None, verbose_name="Product liability Insurance amount") deliveryMethods = models.ManyToManyField( DeliveryMethod, blank=True, verbose_name="Delivery Methods for this product") regionalAvailability = models.ManyToManyField( PoliticalSubregion, blank=True, verbose_name="Regions where this product is available") orderMinimum = MoneyField(max_digits=8, decimal_places=2, default_currency='USD', null=True, blank=True, default=None, verbose_name="Order Minimum") deliveryMinimum = MoneyField(max_digits=8, decimal_places=2, default_currency='USD', null=True, blank=True, default=None, verbose_name="Delivery Minimum") distributors = models.ManyToManyField(Distributor, blank=True) productionPractices = models.ManyToManyField( ProductionPractice, blank=True, verbose_name="Production Practices") def __str__(self): return "%s: %s - %s" % (self.name, str( self.category), str(self.provider)) def to_dict(self): out_dict = self.to_json() out_dict['category'] = self.category out_dict['provider'] = self.provider out_dict[ 'productLiabilityInsuranceAmount'] = self.productLiabilityInsuranceAmount out_dict['deliveryMethods'] = self.deliveryMethods out_dict['regionalAvailability'] = self.regionalAvailability out_dict['orderMinimum'] = self.orderMinimum out_dict['deliveryMinimum'] = self.deliveryMinimum out_dict['distributors'] = self.distributors out_dict['productionPractices'] = self.productionPractices out_dict['capacityMeasurement'] = self.capacityMeasurement out_dict['dateInfoUpdated'] = self.dateInfoUpdated return out_dict @property def image_string(self): if not self.image: if not self.category: image = settings.DEFAULT_CATEGORY_IMAGE else: image = self.category.to_json()['image'] else: image = '/media/%s' % str(self.image) return image def to_json(self): return { 'id': self.pk, 'pk': self.pk, 'name': self.name, 'category': self.category.to_json() if self.category else None, 'image': self.image_string, 'provider': { 'name': self.provider.name, 'id': self.provider.id, 'pk': self.provider.pk } if self.provider else { 'name': None, 'id': None }, 'description': self.description, 'notes': self.notes, 'productLiabilityInsurance': self.productLiabilityInsurance, 'productLiabilityInsuranceAmount': str(self.productLiabilityInsuranceAmount), 'deliveryMethods': [{ 'id': x.id, 'name': x.name } for x in self.deliveryMethods.all()], 'regionalAvailability': [{ 'id': x.id, 'name': x.name } for x in self.regionalAvailability.all()], 'orderMinimum': str(self.orderMinimum), 'deliveryMinimum': str(self.deliveryMinimum), 'distributors': [{ 'id': x.id, 'name': x.name } for x in self.distributors.all()], 'productionPractices': [{ 'id': x.id, 'name': x.name } for x in self.productionPractices.all()], 'capacityValue': self.capacityValue, 'capacityMeasurement': self.capacityMeasurement.to_dict() if self.capacityMeasurement else None, 'dateInfoUpdated': self.dateInfoUpdated.strftime('%D'), } class Meta: verbose_name = 'supplier product' verbose_name_plural = 'supplier products' ordering = ('category', 'provider')
class Transaction(TimeStampedModel): """ Transaction model """ class STATE: INITIAL = 'initial' PENDING = 'pending' SETTLING = 'settling' SETTLED = 'settled' FAILED = 'failed' CANCELED = 'canceled' REFUNDED = 'refunded' @classmethod def as_list(cls): return [ getattr(cls, state) for state in vars(cls).keys() if state[0].isupper() ] @classmethod def as_choices(cls): return ((state, state.capitalize()) for state in cls.as_list()) uuid = models.UUIDField(default=uuid.uuid4) amount = MoneyField(max_digits=14, decimal_places=2, default_currency='USD') state = FSMField(choices=STATE.as_choices(), default=STATE.INITIAL) payment_method = models.ForeignKey('flexible_payments.PaymentMethod', on_delete=models.DO_NOTHING) external_reference = models.CharField(max_length=256, null=True, blank=True) data = JSONField(default=dict, null=True, blank=True) @property def payment_processor(self): return self.payment_method.payment_processor @property def customer(self): return self.payment_method.customer #################################### # Finite State Machine Transitions # #################################### @transition(field=state, source=STATE.INITIAL, target=STATE.PENDING) def process(self): transaction_process.send(sender=self.__class__, transaction=self) pass @transition(field=state, source=[STATE.INITIAL, STATE.PENDING], target=STATE.SETTLED) def settle(self): transaction_settled.send(sender=self.__class__, transaction=self) pass @transition(field=state, source=[STATE.INITIAL, STATE.PENDING], target=STATE.CANCELED) def cancel(self, cancel_code='default', cancel_reason='Unknown cancel reason'): self.cancel_code = cancel_code logger.error(str(cancel_reason)) @transition(field=state, source=[STATE.INITIAL, STATE.PENDING], target=STATE.FAILED) def fail(self, fail_code='default', fail_reason='Unknown fail reason'): self.fail_code = fail_code logger.error(str(fail_reason)) @transition(field=state, source=STATE.SETTLED, target=STATE.REFUNDED) def refund(self, refund_code='default', refund_reason='Unknown refund reason'): self.refund_code = refund_code logger.error(str(refund_reason)) @transaction.atomic() def save(self, *args, **kwargs): # TODO: emit signal? builtin signals for saving models should trigger automatically super(Transaction, self).save(*args, **kwargs)
class WorkOrder(models.Model): class Meta: app_label = 'tenant_foundation' db_table = 'workery_work_orders' verbose_name = _('Work Order') verbose_name_plural = _('Work Orders') default_permissions = () permissions = ( ("can_get_orders", "Can get work orders"), ("can_get_order", "Can get work order"), ("can_post_order", "Can create work order"), ("can_put_order", "Can update work order"), ("can_delete_order", "Can delete work order"), ) objects = WorkOrderManager() id = models.BigAutoField( primary_key=True, default = increment_order_id_number, editable=False, db_index=True ) # # FIELDS # customer = models.ForeignKey( "Customer", help_text=_('The customer of our order.'), related_name="work_orders", on_delete=models.CASCADE ) associate = models.ForeignKey( "Associate", help_text=_('The associate of our order.'), related_name="work_orders", on_delete=models.CASCADE, blank=True, null=True ) description = models.TextField( _("Description"), help_text=_('A description of this job.'), blank=True, null=True, default='', ) assignment_date = models.DateField( _('Assignment Date'), help_text=_('The date that an associate was assigned to the customer.'), blank=True, null=True ) tags = models.ManyToManyField( "Tag", help_text=_('The category tags that this order belongs to.'), blank=True, related_name="%(app_label)s_%(class)s_tags_related", ) is_ongoing = models.BooleanField( _("Is ongoing"), help_text=_('Track whether this order is ongoing job or one-time job.'), default=False, blank=True ) is_home_support_service = models.BooleanField( _("Is Home Support Service"), help_text=_('Track whether this order is a home support service request.'), default=False, blank=True ) start_date = models.DateField( _('Start Date'), help_text=_('The date that this order will begin.'), blank=True, default=get_todays_date ) completion_date = models.DateField( _('Completion Date'), help_text=_('The date that this order was completed.'), blank=True, null=True ) hours = models.DecimalField( _("Hours"), help_text=_('The total amount of hours worked on for this order by the associate.'), default=0, max_digits=7, decimal_places=1, blank=True, null=True ) skill_sets = models.ManyToManyField( "SkillSet", help_text=_('The skill sets that belong to this order.'), blank=True, related_name="%(app_label)s_%(class)s_skill_sets_related", ) type_of = models.PositiveSmallIntegerField( _("Type Of"), help_text=_('The type of job this is.'), default=UNASSIGNED_JOB_TYPE_OF_ID, choices=JOB_TYPE_OF_CHOICES, blank=True, ) indexed_text = models.CharField( _("Indexed Text"), max_length=1024, help_text=_('The searchable content text used by the keyword searcher function.'), blank=True, null=True, db_index=True, unique=True ) comments = models.ManyToManyField( "Comment", help_text=_('The comments belonging to this order made by other people.'), blank=True, through='WorkOrderComment', related_name="%(app_label)s_%(class)s_order_comments_related" ) closing_reason = models.PositiveSmallIntegerField( _("Closing Reason"), help_text=_('The reason for this job order closing.'), blank=True, null=True, default=0, ) closing_reason_other = models.CharField( _("Closing Reason other"), help_text=_('A specific reason this job order was closed.'), max_length=1024, blank=True, null=True, default='', ) latest_pending_task = models.ForeignKey( "TaskItem", help_text=_('The latest pending task of our job order.'), related_name="work_orders", on_delete=models.SET_NULL, blank=True, null=True ) activity_sheet = models.ManyToManyField( "Associate", help_text=_('The activity sheet items related to the associates who accepted or rejected this order.'), blank=True, through='ActivitySheetItem', related_name="%(app_label)s_%(class)s_activity_sheet_items_related" ) # # State # state = FSMField( _('State'), help_text=_('The state of this job order.'), default=WORK_ORDER_STATE.NEW, blank=True, db_index=True, ) # # Satisfaction Survey & Score Fields # was_survey_conducted = models.BooleanField( _("Was Survey Conducted"), help_text=_('Track whether survey was conducted post completion (if completed).'), default=False, blank=True ) was_job_satisfactory = models.BooleanField( _("Was job satisfactory?"), help_text=_('Customer Survey Q1: Was the quality of the work satisfactory?'), default=True, blank=True ) was_job_finished_on_time_and_on_budget = models.BooleanField( _("Was job finished on time and on budget?"), help_text=_('Customer Survey Q2: Was the work completed on time and on budget?'), default=True, blank=True ) was_associate_punctual = models.BooleanField( _("Was associate punctual?"), help_text=_('Customer Survey Q3: Was the Associate Member punctual?'), default=True, blank=True ) was_associate_professional = models.BooleanField( _("Was associate professional?"), help_text=_('Customer Survey Q4: Was the Associate Member professional?'), default=True, blank=True ) would_customer_refer_our_organization = models.BooleanField( _("Would customer refer our organization?"), help_text=_('Customer Survey Q5: Would you refer Over55 to a friend of family member?'), default=True, blank=True ) score = models.PositiveSmallIntegerField( _("Score"), help_text=_('The score number earned at the completion of this date.'), default=0, blank=True, ) # # Financial Fields # was_there_financials_inputted = models.BooleanField( _("Was there financials inputted?"), help_text=_('Track whether financials where inputted.'), default=True, blank=True ) invoice_date = models.DateField( _('Invoice Date'), help_text=_('The date that this order was completed.'), blank=True, null=True ) invoice_ids = models.CharField( _("Invoice ID(s)"), help_text=_('A list of invoice ID values associated with this order.'), max_length=127, blank=True, null=True, default='', ) invoice_quote_amount = MoneyField( _("Invoice Original Quote Amount"), help_text=_('The original quote made by the associate for this job.'), max_digits=10, decimal_places=2, default_currency=WORKERY_APP_DEFAULT_MONEY_CURRENCY, default=Money(0,WORKERY_APP_DEFAULT_MONEY_CURRENCY), blank=True, ) invoice_labour_amount = MoneyField( _("Invoice Labour Costs Amount"), help_text=_('The amount charged for labour by the associate for this job.'), max_digits=10, decimal_places=2, default_currency=WORKERY_APP_DEFAULT_MONEY_CURRENCY, default=Money(0,WORKERY_APP_DEFAULT_MONEY_CURRENCY), blank=True, ) invoice_material_amount = MoneyField( _("Invoice Material Costs Amount"), help_text=_('The amount charged for material costs by the associate for this job.'), max_digits=10, decimal_places=2, default_currency=WORKERY_APP_DEFAULT_MONEY_CURRENCY, default=Money(0,WORKERY_APP_DEFAULT_MONEY_CURRENCY), blank=True, ) invoice_quoted_material_amount = MoneyField( _("Invoice Quoted Material Costs Amount"), help_text=_('The quoted amount to charge for material costs by the associate for this job.'), max_digits=10, decimal_places=2, default_currency=WORKERY_APP_DEFAULT_MONEY_CURRENCY, default=Money(0,WORKERY_APP_DEFAULT_MONEY_CURRENCY), blank=True, ) invoice_quoted_labour_amount = MoneyField( _("Invoice Quoted Labour Costs Amount"), help_text=_('The quoted amount to charge for labour by the associate for this job.'), max_digits=10, decimal_places=2, default_currency=WORKERY_APP_DEFAULT_MONEY_CURRENCY, default=Money(0,WORKERY_APP_DEFAULT_MONEY_CURRENCY), blank=True, ) invoice_total_quote_amount = MoneyField( _("Invoice Total Quoted Amount"), help_text=_('The quoted amount to charge for material costs by the associate for this job.'), max_digits=10, decimal_places=2, default_currency=WORKERY_APP_DEFAULT_MONEY_CURRENCY, default=Money(0,WORKERY_APP_DEFAULT_MONEY_CURRENCY), blank=True, ) invoice_tax_amount = MoneyField( _("Invoice Tax Amount"), help_text=_('The amount charged for taxes by the associate for this job.'), max_digits=10, decimal_places=2, default_currency=WORKERY_APP_DEFAULT_MONEY_CURRENCY, default=Money(0,WORKERY_APP_DEFAULT_MONEY_CURRENCY), blank=True, ) invoice_total_amount = MoneyField( _("Invoice Total Amount"), help_text=_('The total amount charged by the associate for this job.'), max_digits=10, decimal_places=2, default_currency=WORKERY_APP_DEFAULT_MONEY_CURRENCY, default=Money(0,WORKERY_APP_DEFAULT_MONEY_CURRENCY), blank=True, ) invoice_service_fee_amount = MoneyField( _("Invoice Service Fee Amount"), help_text=_('The invoice service fee amount that associate needs to pay.'), max_digits=10, decimal_places=2, default_currency=WORKERY_APP_DEFAULT_MONEY_CURRENCY, default=Money(0,WORKERY_APP_DEFAULT_MONEY_CURRENCY), blank=True, ) invoice_actual_service_fee_amount_paid = MoneyField( _("Invoice Actual Service Fee Amount Paid"), help_text=_('The actual amount paid by the associate for service fee for this job.'), max_digits=10, decimal_places=2, default_currency=WORKERY_APP_DEFAULT_MONEY_CURRENCY, default=Money(0,WORKERY_APP_DEFAULT_MONEY_CURRENCY), blank=True, ) invoice_service_fee = models.ForeignKey( "WorkOrderServiceFee", help_text=_('The service fee applied by the franchise on the total cost of this job order which will be paid by the associate member.'), related_name="work_orders", on_delete=models.SET_NULL, blank=True, null=True ) invoice_service_fee_payment_date = models.DateField( _('Invoice Service Fee Payment Date'), help_text=_('The date when the service fee was paid by the associate.'), blank=True, null=True, db_index=True ) invoice_balance_owing_amount = MoneyField( _("Invoice Balance Owing Amount"), help_text=_('The amount remaining to be paid by the associate for service fee for this job.'), max_digits=10, decimal_places=2, default_currency=WORKERY_APP_DEFAULT_MONEY_CURRENCY, default=Money(0,WORKERY_APP_DEFAULT_MONEY_CURRENCY), blank=True, ) visits = models.PositiveSmallIntegerField( _("Visits"), help_text=_('The the number of visits that were made between the customer and associate for this particular work order.'), default=1, blank=True, validators=[ MinValueValidator(1), MaxValueValidator(100) ], ) # # ONGOING WORK ORDER # ongoing_work_order = models.ForeignKey( "OngoingWorkOrder", help_text=_('The ongoing work order that this work order is a part of.'), related_name="work_orders", on_delete=models.SET_NULL, blank=True, null=True ) # # SYSTEM # created = models.DateTimeField(auto_now_add=True, db_index=True) created_by = models.ForeignKey( SharedUser, help_text=_('The user whom created this order.'), related_name="created_work_orders", on_delete=models.SET_NULL, blank=True, null=True ) created_from = models.GenericIPAddressField( _("Created from"), help_text=_('The IP address of the creator.'), blank=True, null=True ) created_from_is_public = models.BooleanField( _("Is the IP "), help_text=_('Is creator a public IP and is routable.'), default=False, blank=True ) last_modified = models.DateTimeField(auto_now=True) last_modified_by = models.ForeignKey( SharedUser, help_text=_('The user whom last modified this order.'), related_name="last_modified_work_orders", on_delete=models.SET_NULL, blank=True, null=True ) last_modified_from = models.GenericIPAddressField( _("Last modified from"), help_text=_('The IP address of the modifier.'), blank=True, null=True ) last_modified_from_is_public = models.BooleanField( _("Is the IP "), help_text=_('Is modifier a public IP and is routable.'), default=False, blank=True ) # # FUNCTIONS # def __str__(self): return str(self.pk) def get_skill_sets_string(self): # Attach all the skill sets that are associated with each job. skill_set_count = self.skill_sets.count() - 1 skill_set_string = "" for i, skill_set in enumerate(self.skill_sets.all()): skill_set_string += skill_set.sub_category if i != skill_set_count: skill_set_string += "|" else: pass # Skip last return skill_set_string # def get_pretty_state(self): # return dict(self.WORK_ORDER_STATE).get(self.state) def get_pretty_status(self): """ Function returns the job status in a more user-friendly format. """ if self.state == WORK_ORDER_STATE.PENDING: return 'Pending' elif self.state == WORK_ORDER_STATE.CANCELLED: if self.closing_reason == 2: return "Cancelled - Quote was too high" elif self.closing_reason == 3: return "Cancelled - Job completed by someone else" elif self.closing_reason == 5: return "Cancelled - Work no longer needed" elif self.closing_reason == 6: return "Cancelled - Client not satisfied with Associate" elif self.closing_reason == 7: return "Cancelled - Client did work themselves" elif self.closing_reason == 8: return "Cancelled - No Associate available" elif self.closing_reason == 9: return "Cancelled - Work environment unsuitable" elif self.closing_reason == 10: return "Cancelled - Client did not return call" elif self.closing_reason == 11: return "Cancelled - Associate did not have necessary equipment" elif self.closing_reason == 12: return "Cancelled - Repair not possible" elif self.closing_reason == 13: return "Cancelled - Could not meet deadline" elif self.closing_reason == 14: return "Cancelled - Associate did not call client" elif self.closing_reason == 15: return "Cancelled - Member issue" elif self.closing_reason == 16: return "Cancelled - Client billing issue" else: return "Cancelled - Other: "+str(self.closing_reason_other) elif self.state == WORK_ORDER_STATE.ONGOING: return 'Ongoing' elif self.state == WORK_ORDER_STATE.IN_PROGRESS: return 'In Progress' elif self.state == WORK_ORDER_STATE.COMPLETED_BUT_UNPAID: return 'Completed but unpaid' elif self.state == WORK_ORDER_STATE.COMPLETED_AND_PAID: return 'Completed and paid' elif self.state == WORK_ORDER_STATE.ARCHIVED: return 'Archived' elif self.state == WORK_ORDER_STATE.DECLINED: return 'Declined' elif self.state == WORK_ORDER_STATE.NEW: return 'New' else: return self.state return None def pretty_closing_reason(self): if self.closing_reason == 2: return "Quote was too high" elif self.closing_reason == 3: return "Job completed by someone else" elif self.closing_reason == 5: return "Work no longer needed" elif self.closing_reason == 6: return "Client not satisfied with Associate" elif self.closing_reason == 7: return "Client did work themselves" elif self.closing_reason == 8: return "No Associate available" elif self.closing_reason == 9: return "Work environment unsuitable" elif self.closing_reason == 10: return "Client did not return call" elif self.closing_reason == 11: return "Associate did not have necessary equipment" elif self.closing_reason == 12: return "Repair not possible" elif self.closing_reason == 13: return "Could not meet deadline" elif self.closing_reason == 14: return "Associate did not call client" elif self.closing_reason == 15: return "Member issue" elif self.closing_reason == 16: return "Client billing issue" else: return "Other: "+str(self.closing_reason_other) """ Override the `save` function to support save cached searchable terms. """ def save(self, *args, **kwargs): ''' The following code will populate our indexed_custom search text with the latest model data before we save. ''' search_text = str(self.id) if self.description: search_text += " " + self.description if self.customer: if self.customer.organization: search_text += " " + self.customer.organization.name if self.customer.given_name: search_text += " " + self.customer.given_name if self.customer.middle_name: search_text += " " + self.customer.middle_name if self.customer.last_name: search_text += " " + self.customer.last_name if self.customer.email: search_text += " " + self.customer.email if self.customer.telephone: search_text += " " + phonenumbers.format_number(self.customer.telephone, phonenumbers.PhoneNumberFormat.NATIONAL) search_text += " " + phonenumbers.format_number(self.customer.telephone, phonenumbers.PhoneNumberFormat.INTERNATIONAL) search_text += " " + phonenumbers.format_number(self.customer.telephone, phonenumbers.PhoneNumberFormat.E164) if self.customer.other_telephone: search_text += " " + phonenumbers.format_number(self.customer.other_telephone, phonenumbers.PhoneNumberFormat.NATIONAL) search_text += " " + phonenumbers.format_number(self.customer.other_telephone, phonenumbers.PhoneNumberFormat.INTERNATIONAL) search_text += " " + phonenumbers.format_number(self.customer.other_telephone, phonenumbers.PhoneNumberFormat.E164) if self.description: search_text += " " + self.description if self.associate: if self.associate.given_name: search_text += " " + self.associate.given_name if self.associate.middle_name: search_text += " " + self.associate.middle_name if self.associate.last_name: search_text += " " + self.associate.last_name if self.associate.email: search_text += " " + self.associate.email if self.associate.telephone: search_text += " " + phonenumbers.format_number(self.associate.telephone, phonenumbers.PhoneNumberFormat.NATIONAL) search_text += " " + phonenumbers.format_number(self.associate.telephone, phonenumbers.PhoneNumberFormat.INTERNATIONAL) search_text += " " + phonenumbers.format_number(self.associate.telephone, phonenumbers.PhoneNumberFormat.E164) if self.associate.other_telephone: search_text += " " + phonenumbers.format_number(self.associate.other_telephone, phonenumbers.PhoneNumberFormat.NATIONAL) search_text += " " + phonenumbers.format_number(self.associate.other_telephone, phonenumbers.PhoneNumberFormat.INTERNATIONAL) search_text += " " + phonenumbers.format_number(self.associate.other_telephone, phonenumbers.PhoneNumberFormat.E164) if self.description: search_text += " " + self.description if self.invoice_ids: search_text += " " + str(self.invoice_ids) self.indexed_text = Truncator(search_text).chars(1024) ''' Run our `save` function. ''' super(WorkOrder, self).save(*args, **kwargs)
class SkipTheDishesOrder(models.Model): account = models.ForeignKey('Account', on_delete=models.CASCADE) order_number = models.PositiveIntegerField(unique=True) status = models.CharField(max_length=32) type = models.CharField(max_length=32) time_placed = models.DateTimeField() time_collected = models.DateField(null=True) payment_method = models.CharField(max_length=64) food_subtotal = MoneyField(max_digits=19, decimal_places=4, default_currency='CAD') food_hst = MoneyField(max_digits=19, decimal_places=4, default_currency='CAD') skip_vouchers = MoneyField(max_digits=19, decimal_places=4, default_currency='CAD') gross_earnings = MoneyField(max_digits=19, decimal_places=4, default_currency='CAD') restaurant_subsidy = MoneyField(max_digits=19, decimal_places=4, default_currency='CAD') skip_subsidy = MoneyField(max_digits=19, decimal_places=4, default_currency='CAD') adjustment_details = models.TextField(blank=True) adjustments = MoneyField(max_digits=19, decimal_places=4, default_currency='CAD') courier_delay = models.DurationField() courier_delay_contribution = MoneyField(max_digits=19, decimal_places=4, default_currency='CAD') courier_tip = MoneyField(max_digits=19, decimal_places=4, default_currency='CAD') delivery_fee = MoneyField(max_digits=19, decimal_places=4, default_currency='CAD') delivery_hst = MoneyField(max_digits=19, decimal_places=4, default_currency='CAD') def __str__(self): return f"[{self.time_placed}] {self.order_number} ({self.type})"
class ModelWithChoicesMoneyField(models.Model): money = MoneyField( max_digits=10, decimal_places=2, currency_choices=[('USD', 'US Dollars'), ('ZWN', 'Zimbabwian')], )
class courses(models.Model): def courseName(self): return "Course " + self.name # Returns a random subject, level, and alternate classroom in the form: # 'Algebra-4001-B' # @Param void # @Return str def randomCourseName(): subjects = [ 'Algebra', 'Accounting', 'Archaeology', 'Biodiversity', 'Business', 'Algorithms', 'LinearAlgebra', 'Calculus', 'Chemistry', 'DataStructures', 'PolySci', 'Cardiovascular', 'Celtic', 'Hungarian', 'ComputerScience', 'Economics', 'Education', 'History', 'English', 'Wellbeing', 'Engineering', 'Film', 'Law', 'Psychology', 'Physics', 'Philisophy', 'Music', 'Mathematics', 'Astronomy', 'Statistics', 'Theater', 'Translation', 'Sociology', 'Theology', 'VeterinaryMedicine' ] alternates = ['A', 'B', 'C', 'D', 'E', 'F'] levels = ['0', '1', '2', '3', '4'] return choice(subjects) + '-' + ''.join( [choice(levels) for _ in range(4)]) + '-' + choice(alternates) # Returns a random professor first and last name using the following list, i.e.: # 'Angela Lizard' # @Param void # @Return str def randomProfName(): names = [ "Tommy", "Bill", "Janet", "Bill", "Stacy", "Spider", "Moth", "Butterfly", "Lizard", "Rabbit", "Mouse", "Gorilla", "Giraffe", 'Abigail', 'Alexandra', 'Alison', 'Amanda', 'Amelia', 'Amy', 'Andrea', 'Angela', 'Anna', 'Anne', 'Audrey', 'Ava', 'Bella', 'Bernadette', 'Carol', 'Caroline', 'Carolyn', 'Chloe', 'Claire', 'Deirdre', 'Diana', 'Diane', 'Donna', 'Dorothy', 'Elizabeth', 'Ella', 'Emily', 'Emma', 'Adam', 'Adrian', 'Alan', 'Alexander', 'Andrew', 'Anthony', 'Austin', 'Benjamin', 'Blake', 'Boris', 'Brandon', 'Brian', 'Cameron', 'Carl', 'Charles', 'Christian', 'Christopher', 'Colin', 'Connor', 'Dan', 'David', 'Dominic', 'Dylan', 'Edward', 'Eric', 'Evan', 'Frank', 'Gavin', 'Gordon', 'Harry', 'Ian', 'Isaac' ] return choice(names) + ' ' + choice(names) # @TODO Should change to only randomize hour then M/W/F vs. T/H/S # This function will return a random datetime between two datetime objects. # @Param datetime, datetime (date range start, end) # @Return datetime (random date in the range) def randomDatetime(start, end): delta = end - start int_delta = (delta.days * 24 * 60 * 60) + delta.seconds random_second = randrange(int_delta) return str(start + timedelta(seconds=random_second)) # Python fiddle, called sing_sen_maker() by them # Makes a random senctence from the different parts of speech. Uses a SINGULAR subject # Used to build course descriptions # @Param void # @Return string def randSentenceGen(): s_nouns = [ "A dude", "My mom", "The king", "Some guy", "A cat with rabies", "A sloth", "Your homie", "This cool guy my gardener met yesterday", "Superman" ] p_nouns = [ "These dudes", "Both of my moms", "All the kings of the world", "Some guys", "All of a cattery's cats", "The multitude of sloths living under your bed", "Your homies", "Like, these, like, all these people", "Supermen" ] s_verbs = [ "eats", "kicks", "gives", "treats", "meets with", "creates", "hacks", "configures", "spies on", "encourages", "meows on", "flees from", "tries to automate", "explodes" ] p_verbs = [ "eat", "kick", "give", "treat", "meet with", "create", "hack", "configure", "spy on", "encourages", "meow on", "flee from", "try to automate", "explode" ] infinitives = [ "to make a pie.", "for no apparent reason.", "because the sky is green.", "for a disease.", "to be able to make toast explode.", "to know more about archeology." ] string = "" for i in range(5): # Map could be fun here # Explicit for readability string += choice(s_nouns) + " " string += choice(s_verbs) + " " string += choice(s_nouns).lower() + " " or choice( p_nouns).lower() + " " string += choice(infinitives) + " " return string # '2017-05-01 2017 18:55:35' semester_start = datetime(2017, 5, 1, 18, 55, 35) # Oct 1, 2017 18:55:35 semester_end = datetime(2017, 10, 1, 18, 55, 35) # FIELDS name = models.CharField(default=randomCourseName(), unique=True, max_length=120) # Why use datetime? Should standardize semester length, randomize hour then M/W/F vs. T/H/S # These are only one-time courses datetimes = models.DateTimeField( default=randomDatetime(semester_start, semester_end)) # datetimes = models.DateTimeField(default = randomDateTime()) professors = models.CharField(default=randomProfName(), max_length=120) cost = MoneyField(max_digits=4, decimal_places=0, default=randint(50, 9000), default_currency='USD') description = models.TextField(default=randSentenceGen()) # NOT USED # Replaced by django-money # @property # def cost(self): # return '$%s' %self.cost # unique key def __unicode__(self): return self.name
class DateTimeModel(models.Model): field = MoneyField(max_digits=10, decimal_places=2) created = models.DateTimeField(null=True, blank=True)
class ModelIssue300(models.Model): money = models.ForeignKey(DateTimeModel, on_delete=models.CASCADE) price = MoneyField(max_digits=10, decimal_places=2, default_currency='EUR', default=Decimal('0.0'))
class NullMoneyFieldModel(models.Model): field = MoneyField(max_digits=10, decimal_places=2, null=True, default_currency='USD', blank=True)
class ModelWithCustomManager(models.Model): field = MoneyField(max_digits=10, decimal_places=2) manager = money_manager(MoneyManager())
class SimpleModel(models.Model): money = 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 RevisionedModel(models.Model): amount = MoneyField(max_digits=10, decimal_places=2, default_currency='USD')
class ModelWithDefaultAsOldMoney(models.Model): money = MoneyField(default=OldMoney('0.01', 'RUB'), max_digits=10, decimal_places=2)
class ModelWithValidation(models.Model): balance = MoneyField(max_digits=10, decimal_places=2, validators=[MinValueValidator(Money(100, 'GBP'))])
class ModelWithTwoMoneyFields(models.Model): amount1 = MoneyField(max_digits=10, decimal_places=2) amount2 = MoneyField(max_digits=10, decimal_places=3)
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 Contratado(Pessoa): # basicas con_matricula = models.CharField(db_column='con_matricula', primary_key=True, max_length=30) estabelecimento = models.ForeignKey('empregador.Estabelecimento', on_delete=models.CASCADE) lotacao = models.ForeignKey('empregador.Lotacao', on_delete=models.CASCADE) funcao = models.ForeignKey('empregador.Funcao', on_delete=models.CASCADE) sindicato = models.ForeignKey('empregador.Sindicato', on_delete=models.CASCADE) # trabalhistas con_tipo_reg_trabalhista = models.CharField( max_length=3, choices=TIPO_REGIME_TRABALHISTA, db_column='con_tipo_reg_trabalhista') con_tipo_reg_previdenciario = models.CharField( max_length=4, choices=TIPO_REGIME_PREVIDENCIARIO, db_column='con_tipo_reg_previdenciario') con_regime_jornada = models.CharField(max_length=1, choices=REGIME_DE_JORNADA, db_column='con_regime_jornada') con_natureza_atividade = models.CharField( max_length=1, choices=NATUREZA_DA_ATIVIDADE, db_column='con_natureza_atividade') con_categoria = models.CharField(max_length=1, choices=CATEGORIA, db_column='con_categoria') # info_contrato con_data_admissao = models.DateField(db_column='con_data_admissao', null=True, blank=True) con_tipo_contrato = models.CharField(db_column='con_tipo_contrato', max_length=1, blank=True, null=True, choices=TIPO_CONTRATO_TRABALHO) con_tipo_admissao = models.CharField(db_column='con_tipo_admissao', max_length=1, blank=True, null=True, choices=TIPO_ADMISSAO, default='A') con_unidade_salario = models.CharField(db_column='con_unidade_salario', max_length=1, choices=UNIDADE_SALARIO, default='M') con_indicativo_admissao = models.CharField( db_column='con_indicativo_admissao', max_length=1, choices=INDICATIVO_ADMISSAO, default='N') con_salario_mensal = MoneyField(db_column='con_salario_mensal', max_digits=10, decimal_places=2, default_currency='BRL', null=True, blank=True) con_calcular_dsr = models.BooleanField(db_column='con_calcular_dsr', default=True) con_receber_fgts = models.BooleanField(db_column='con_receber_fgts', default=True) # outra empresa con_vinculo_outra_empresa = models.CharField( max_length=1, db_column='con_vinculo_outra_empresa', null=True, blank=True, choices=VINCULO_COM_OUTRA_EMPRESA) con_cnpj_outra_empresa = models.CharField( max_length=14, db_column='con_cnjp_outra_empresa', null=True, blank=True) con_remuneracao_outra_empresa = MoneyField( db_column='con_remuneracao_outra_empresa', max_digits=10, decimal_places=2, default_currency='BRL', null=True, blank=True) class Meta: ordering = ['-con_matricula'] db_table = 'CONTRATADOS' verbose_name = 'Contratado' verbose_name_plural = 'Contratados' def __str__(self): return self.pes_nome
class ModelWithDefaultAsInt(models.Model): money = MoneyField(default=123, max_digits=10, decimal_places=2, default_currency='GHS')
class Property(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) address = map_fields.AddressField(max_length=200, unique=True) geolocation = map_fields.GeoLocationField(max_length=100) property_type = models.CharField(choices=PROPERTY_CHOICES, max_length=2) bought_for = MoneyField( max_digits=20, decimal_places=2, default_currency='USD', null=True, blank=True, help_text="Total value of the property at the moment of purchse") image_url = models.URLField(null=True) owned_since = models.DateField() property_taxes = MoneyField(max_digits=20, decimal_places=2, default_currency='USD', null=True, blank=True, help_text="per month") insurance = MoneyField(max_digits=20, decimal_places=2, default_currency='USD', null=True, blank=True, help_text="per month") # Zillow fields zpid = models.IntegerField(null=True, blank=True) zillow_url = models.URLField(null=True, blank=True) rental_estimated_value = MoneyField(max_digits=20, decimal_places=2, default_currency='USD', null=True, blank=True) estimated_value = MoneyField( max_digits=20, decimal_places=2, default_currency='USD', null=True, blank=True, help_text= "Value generated automatically by zillow, but you can edit freely") def save(self, *args, **kwargs): if not self.estimated_value: self.estimated_value = get_estimated_value(self) self.image_url = get_property_image(self) return super().save(*args, **kwargs) def get_net_cashflow(self): return self.tenant.rent_payment - ( self.loan.monthly_payment + self.insurance + self.property_taxes) def get_total_expenses(self): return self.loan.monthly_payment + self.insurance + self.property_taxes def get_absolute_url(self): return reverse("property_edit", kwargs={"pk": self.pk}) def __str__(self): return str(self.address) class Meta: verbose_name_plural = 'properties' ordering = ['id']
class ModelWithDefaultAsStringWithCurrency(models.Model): money = MoneyField(default='123 USD', max_digits=10, decimal_places=2) class Meta: verbose_name = 'model_default_string_currency'
class Charge(models.Model): service = models.CharField(max_length=8) charge = MoneyField(max_digits=10, decimal_places=2, default_currency='TZS')
class ModelWithDefaultAsString(models.Model): money = MoneyField(default='123', max_digits=10, decimal_places=2, default_currency='PLN')
class Model(models.Model): field = MoneyField(**field_kwargs) class Meta: app_label = 'test'
class ModelWithDefaultAsFloat(models.Model): money = MoneyField(default=12.05, max_digits=10, decimal_places=2, default_currency='PLN')
class Provider(models.Model): TERNARY_YES_NO_CHOICES = ( ('Unknown', 'Unknown'), ('Yes', 'Yes'), ('No', 'No'), ) name = models.CharField(max_length=255, verbose_name="Supplier Name") outreachConductor = models.CharField( max_length=255, blank=True, null=True, default=None, verbose_name='Outreach conducted by', help_text="The name of the teammate who reached out to this supplier") dateInfoAdded = models.DateTimeField(auto_now_add=True, verbose_name='Record created date') dateInfoUpdated = models.DateTimeField( auto_now=True, verbose_name='Date information updated', help_text="This is automatic.") soldToSchoolsBefore = models.CharField( max_length=20, choices=TERNARY_YES_NO_CHOICES, default='Unknown', verbose_name='This supplier has sold to schools before') schoolsSoldTo = models.ManyToManyField( School, blank=True, verbose_name='Schools this supplier has done business with before') description = models.TextField(blank=True, null=True, default=None, verbose_name="Brief Description", help_text="2-3 Sentences") primaryContactFirstName = models.CharField( max_length=100, blank=True, null=True, default=None, verbose_name="Primary contact's first name") primaryContactLastName = models.CharField( max_length=100, blank=True, null=True, default=None, verbose_name="Primary contact's last name") businessAddressLine1 = models.CharField( max_length=255, verbose_name="Business Address Line 1", blank=True, null=True, default=None) businessAddressLine2 = models.CharField( max_length=255, blank=True, null=True, default=None, verbose_name="Business Address Line 2") businessAddressCity = models.CharField( max_length=255, verbose_name="Business Address City") businessAddressState = models.ForeignKey( PoliticalRegion, on_delete=models.PROTECT, verbose_name="Business Address State", related_name="providerBusinessAddresses") businessAddressZipCode = models.CharField( max_length=25, verbose_name="Business Address Zip Code", blank=True, null=True, default=None) businessCounty = models.ForeignKey( PoliticalSubregion, on_delete=models.SET_NULL, blank=True, null=True, default=None, verbose_name="Business County Location", related_name="providerBusinessCountyLocation") physicalAddressIsSame = models.BooleanField( default=False, verbose_name="Physical address is the same as business address") physicalAddressLine1 = models.CharField( max_length=255, blank=True, null=True, default=None, verbose_name="Physical Address Line 1") physicalAddressLine2 = models.CharField( max_length=255, blank=True, null=True, default=None, verbose_name="Physical Address Line 2") physicalAddressCity = models.CharField( max_length=255, blank=True, null=True, default=None, verbose_name="Physical Address City") physicalAddressState = models.ForeignKey( PoliticalRegion, on_delete=models.SET_NULL, blank=True, null=True, default=None, verbose_name="Physical Address State", related_name="providerPhysicalAddresses") physicalAddressZipCode = models.CharField( max_length=25, blank=True, null=True, default=None, verbose_name="Physical Address Zip Code") physicalCounty = models.ForeignKey( PoliticalSubregion, on_delete=models.SET_NULL, blank=True, null=True, default=None, verbose_name="Physical County Location", related_name="providerPhysicalCountyLocation") officePhone = PhoneNumberField(verbose_name="Office Phone", blank=True, null=True, default=None) cellPhone = PhoneNumberField(blank=True, null=True, default=None, verbose_name="Cell Phone") email = models.EmailField(max_length=255, null=True, blank=True, default=None) websiteAddress = models.URLField( max_length=255, null=True, blank=True, default=None, verbose_name="Website Address", help_text= "Try to include either http:// (good) or https:// (better if available)" ) preferredLanguage = models.ManyToManyField( Language, blank=True, verbose_name='Preferred contact language') preferredContactMethod = models.ManyToManyField( ContactMethod, blank=True, verbose_name='Preferred contact method') identities = models.ManyToManyField(Identity, blank=True) notes = models.TextField(null=True, blank=True, default=None, verbose_name="Additional Notes") ####################################################################### # The following may need to be "Provider-Product Specific" ####################################################################### productLiabilityInsurance = models.CharField( max_length=20, choices=TERNARY_YES_NO_CHOICES, default='Unknown', verbose_name='This supplier has product liability insurance') productLiabilityInsuranceAmount = MoneyField( max_digits=10, decimal_places=0, default_currency='USD', null=True, blank=True, default=None, verbose_name="Product Liability Insurance Amount") deliveryMethods = models.ManyToManyField(DeliveryMethod, blank=True, verbose_name='Delivery Methods') regionalAvailability = models.ManyToManyField( PoliticalSubregion, blank=True, verbose_name='Regions where product is available') orderMinimum = MoneyField(max_digits=8, decimal_places=2, default_currency='USD', null=True, blank=True, default=None, verbose_name='Order Minimum') deliveryMinimum = MoneyField(max_digits=8, decimal_places=2, default_currency='USD', null=True, blank=True, default=None, verbose_name='Delivery Minimum') distributors = models.ManyToManyField(Distributor, blank=True) productionPractices = models.ManyToManyField( ProductionPractice, blank=True, verbose_name='Production Practices') class Meta: verbose_name = "supplier" verbose_name_plural = "suppliers" ordering = ( 'name', 'dateInfoUpdated', ) @property def components_offered(self): component_ids = [] for product in self.providerproduct_set.all(): for component in product.category.usdaComponentCategories.all(): if component.id not in component_ids: component_ids.append(component.id) return ComponentCategory.objects.filter(id__in=component_ids) @property def product_categories(self): product_categories = {} for product in self.providerproduct_set.all().order_by('name'): product_ancestor_category = product.category.get_prime_ancestor() if not product_ancestor_category.name in product_categories.keys(): product_categories[product_ancestor_category.name] = { 'object': product_ancestor_category, 'products': [], 'descriptions_present': False, 'pack_size_present': False, 'notes_present': False } if product.description: product_categories[product_ancestor_category. name]['descriptions_present'] = True if product.packSize: product_categories[ product_ancestor_category.name]['pack_size_present'] = True if product.notes: product_categories[ product_ancestor_category.name]['notes_present'] = True product_name = product.name if ',' in product_name and product_name.split( ',')[0].lower() == product_ancestor_category.name.lower(): product_name = ','.join(product_name.split(',')[1:]) product_categories[ product_ancestor_category.name]['products'].append({ 'variety': product_name, 'form': product.category.name, 'description': product.description, 'pack_size': product.packSize, 'notes': product.notes, 'usda_meal_components': ', '.join([ x.name for x in product.category.componentCategories.all() ]), }) ordered_categories = [] category_keys = [x for x in product_categories.keys()] category_keys.sort() for category_key in category_keys: ordered_categories.append(product_categories[category_key]) return ordered_categories @property def dateUpdated(self): monthNames = [ 'None', 'Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'June', 'July', 'Aug.', 'Sep.', 'Oct.', 'Nov.', 'Dec.', ] updateString = '{month} {day}, {year}'.format( month=monthNames[self.dateInfoUpdated.month], day=self.dateInfoUpdated.day, year=self.dateInfoUpdated.year) return updateString def get_address_string(self, locationType=None, fullAddress=True): if locationType == 'Business': fields = [ self.businessAddressLine1, self.businessAddressLine2 if fullAddress else None, self.businessAddressCity, self.businessAddressState.to_dict()['initialism'] if self.businessAddressState else None, self.businessAddressZipCode, ] elif locationType == 'Physical': if self.physicalAddressIsSame: address = self.get_address_string('Business', fullAddress=fullAddress) if not address == None: return address fields = [ self.physicalAddressLine1, self.physicalAddressLine2 if fullAddress else None, self.physicalAddressCity, self.physicalAddressState.to_dict()['initialism'] if self.physicalAddressState else None, self.physicalAddressZipCode, ] else: return self.get_address_string('Business') return ', '.join([x for x in fields if not x == None]) def geocode(self, locationType='Physical'): address_string = self.get_address_string(locationType=locationType) if len(address_string) > 1: try: results = geocoder.mapbox(address_string, key=settings.MAPBOX_TOKEN) except Exception as e: print(e) results = None if not results or len(results) < 1 or results.error: address_string = self.get_address_string( locationType=locationType, fullAddress=False) results = geocoder.mapbox(address_string, key=settings.MAPBOX_TOKEN) return results else: return [] def get_county(self, locationType='Physical'): if locationType == 'Business': county_field = self.businessCounty else: county_field = self.physicalCounty if not county_field: county_record = None for geocode_hit in self.geocode(locationType=locationType): geocode = geocode_hit.json try: if 'raw' in geocode.keys() and 'district' in geocode[ 'raw'].keys() and 'state' in geocode.keys(): district = geocode['raw']['district'] state = geocode['state'] if district and state and '' not in [ district, state ] and 'County' in district: county_name = ' '.join(district.split(' ')[0:-1]) county_record = PoliticalSubregion.objects.get( name=county_name, region__name=state) break except Exception as e: pass if county_record: if locationType == 'Business': self.businessCounty = county_record else: self.physicalCounty = county_record self.save() county_field = county_record return county_field def to_json(self): products = [x.to_json() for x in self.providerproduct_set.all()] product_categories = [] for product in self.providerproduct_set.all(): product_ancestor_category = product.category.get_prime_ancestor( ).to_json() is_dupe = False for category in product_categories: if product_ancestor_category == category: is_dupe = True if not is_dupe: product_categories.append(product_ancestor_category) physicalCounty = self.physicalCounty if not physicalCounty == None: physicalCounty = physicalCounty.to_dict() businessCounty = self.businessCounty if not businessCounty == None: businessCounty = businessCounty.to_dict() return { 'id': self.id, 'pk': self.pk, 'name': self.name, 'outreachConductor': self.outreachConductor, 'dateInfoAdded': self.dateInfoAdded.strftime('%D'), 'dateInfoUpdated': self.dateInfoUpdated.strftime('%D'), 'soldToSchoolsBefore': self.soldToSchoolsBefore, 'description': self.description, 'primaryContactFirstName': self.primaryContactFirstName, 'primaryContactLastName': self.primaryContactLastName, 'businessAddressLine1': self.businessAddressLine1, 'businessAddressLine2': self.businessAddressLine2, 'businessAddressCity': self.businessAddressCity, 'businessAddressState': self.businessAddressState.to_dict() if self.businessAddressState else None, 'businessAddressZipCode': self.businessAddressZipCode, 'businessCounty': businessCounty, 'physicalAddressIsSame': self.physicalAddressIsSame, 'physicalAddressLine1': self.physicalAddressLine1, 'physicalAddressLine2': self.physicalAddressLine2, 'physicalAddressCity': self.physicalAddressCity, 'physicalAddressState': self.physicalAddressState.to_dict() if self.physicalAddressState else None, 'physicalAddressZipCode': self.physicalAddressZipCode, 'physicalCounty': physicalCounty, 'officePhone': self.officePhone.as_national if self.officePhone else None, 'cellPhone': self.cellPhone.as_national if self.cellPhone else None, 'email': self.email, 'websiteAddress': self.websiteAddress, 'identities': [x.to_dict() for x in self.identities.all()], 'notes': self.notes, ####################################################################### # The following may need to be "Provider-Product Specific" ####################################################################### 'productLiabilityInsurance': self.productLiabilityInsurance, 'productLiabilityInsuranceAmount': str(self.productLiabilityInsuranceAmount) if (self.productLiabilityInsuranceAmount and not self.productLiabilityInsuranceAmount == None) else None, 'deliveryMethods': [{ 'id': x.id, 'name': x.name } for x in self.deliveryMethods.all()], 'regionalAvailability': [{ 'id': x.id, 'name': x.name } for x in self.regionalAvailability.all()], 'orderMinimum': str(self.orderMinimum), 'deliveryMinimum': str(self.deliveryMinimum), 'distributors': [{ 'id': x.id, 'name': x.name } for x in self.distributors.all()], 'productionPractices': [{ 'id': x.id, 'name': x.name } for x in self.productionPractices.all()], 'products': products, 'product_categories': product_categories, } def to_dict(self): product_categories = [] for product in self.providerproduct_set.all(): product_ancestor_category = product.category.get_prime_ancestor() if not product_ancestor_category in product_categories: product_categories.append(product_ancestor_category) out_dict = self.to_json() out_dict['dateInfoAdded'] = self.dateInfoAdded out_dict['dateInfoUpdated'] = self.dateInfoUpdated out_dict['businessAddressState'] = self.businessAddressState out_dict['physicalAddressState'] = self.physicalAddressState out_dict['identities'] = self.identities out_dict[ 'productLiabilityInsuranceAmount'] = self.productLiabilityInsuranceAmount out_dict['deliveryMethods'] = self.deliveryMethods out_dict['regionalAvailability'] = self.regionalAvailability out_dict['orderMinimum'] = self.orderMinimum out_dict['deliveryMinimum'] = self.deliveryMinimum out_dict['distributors'] = self.distributors out_dict['productionPractices'] = self.productionPractices out_dict['products'] = self.providerproduct_set.all() out_dict['product_categories'] = product_categories return out_dict def __str__(self): return self.name
class ModelWithDefaultAsDecimal(models.Model): money = MoneyField(default=Decimal('0.01'), max_digits=10, decimal_places=2, default_currency='CHF')
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, NGN), 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 __str__(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('feather: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 == 'feather.utils.validation_simple': attributes.append('{0}: {1}'.format(attribute_name, attribute.value)) elif attribute.attribute.validation == 'feather.utils.validation_yesno': attributes.append(attribute_name) else: if attribute.attribute.validation == 'feather.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 AbstractModel(models.Model): money = MoneyField(max_digits=10, decimal_places=2, default_currency='USD') m2m_field = models.ManyToManyField(ModelWithDefaultAsInt) class Meta: abstract = True