class Errata(models.Model): created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) # TODO: If we seperate the Errata application from the CMS, the books will need to be store differently. `book` will be removed, `openstax_book` will store as string book = models.ForeignKey(Book, on_delete=models.PROTECT) openstax_book = models.CharField(max_length=255, null=True, blank=True, editable=False) is_assessment_errata = models.CharField( max_length=100, choices=YES_NO_CHOICES, blank=True, null=True, ) assessment_id = models.CharField(max_length=255, null=True, blank=True) status = models.CharField( max_length=100, choices=ERRATA_STATUS, default=NEW, ) resolution = models.CharField( max_length=100, choices=ERRATA_RESOLUTIONS, blank=True, null=True, ) duplicate_id = models.ForeignKey('self', related_name='duplicate_report', null=True, blank=True, on_delete=models.PROTECT) reviewed_date = models.DateField(blank=True, null=True, editable=False) corrected_date = models.DateField(blank=True, null=True) archived = models.BooleanField(default=False) junk = models.BooleanField( default=False, help_text= 'Flagging the erratum as junk will automatically flag it for archive as well.' ) location = models.TextField(blank=True, null=True) additional_location_information = models.TextField(blank=True, null=True) detail = models.TextField() resolution_notes = models.TextField( blank=True, null=True, help_text= 'Leaving the resolution notes blank will allow the field to auto-fill with the appropriate text based on status/resolution selections.' ) resolution_date = models.DateField(blank=True, null=True) internal_notes = models.TextField( blank=True, null=True, help_text= 'Only users with errata admin access can view and edit the contents of this field.' ) error_type = models.CharField(max_length=100, choices=ERRATA_ERROR_TYPES, blank=True, null=True) error_type_other = models.CharField(max_length=255, blank=True, null=True) number_of_errors = models.PositiveIntegerField(default=1) resource = models.CharField(max_length=100, choices=ERRATA_RESOURCES, blank=True, null=True) resource_other = models.CharField(max_length=255, blank=True, null=True) # TODO: We are keeping the Foreign Key to the local user until the migrations to production are complete, then remove submitted_by and submitter_email_address submitted_by = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL) submitter_email_address = models.EmailField(blank=True, null=True) submitted_by_account_id = models.IntegerField( blank=True, null=True, validators=[MinValueValidator(0), is_user_blocked]) accounts_user_email = models.CharField(max_length=255, null=True, blank=True) accounts_user_name = models.CharField(max_length=255, null=True, blank=True) accounts_user_faculty_status = models.CharField(max_length=255, null=True, blank=True) file_1 = models.FileField(upload_to='errata/user_uploads/1/', blank=True, null=True) file_2 = models.FileField(upload_to='errata/user_uploads/2/', blank=True, null=True) # @property # def user_email(self): # try: # user = get_user_info(self.submitted_by_account_id) # return user['email'] # except: # return None # # @property # def user_name(self): # try: # user = get_user_info(self.submitted_by_account_id) # return user['fullname'] # except: # return None # # @property # def user_faculty_status(self): # try: # user = get_user_info(self.submitted_by_account_id) # return user['faculty_status'] # except: # return None @property def accounts_link(self): try: return format_html( '<a href="{}/admin/users/{}/edit" target="_blank">OpenStax Accounts Link</a>' .format(settings.ACCOUNTS_URL, self.submitted_by_account_id)) except: return None @property def short_detail(self): return truncatewords(self.detail, 15) def clean(self): if self.status == 'Completed' and not self.resolution or self.status == 'Reviewed' and not self.resolution: raise ValidationError({ 'resolution': 'Resolution is required if status is completed or reviewed.' }) if (self.status == 'Editorial Review' or self.status == 'Andrew Editorial Review' or self.status == 'Anthony Editorial Review' or self.status == 'Reviewed' or self.status == 'Completed') and not self.is_assessment_errata: raise ValidationError({ 'is_assessment_errata': 'You must specify if this is an assessment errata.' }) if (self.status == 'Completed' and self.resolution == 'Duplicate') and not self.duplicate_id: raise ValidationError({ 'duplicate_id': 'You must specify the duplicate report ID when resolution is marked duplicate.' }) def save(self, *args, **kwargs): # update instance dates if self.resolution: self.resolution_date = timezone.now() if self.status == "Reviewed": self.reviewed_date = timezone.now() if self.status == "Completed" and self.resolution != "Will Not Fix": self.corrected_date = timezone.now() # book updated field is being used front-end to show google the content is being maintained Book.objects.filter(pk=self.book.pk).update(updated=now()) # prefill resolution notes based on certain status and resolutions if self.resolution == "Duplicate" and not self.resolution_notes: self.resolution_notes = "This is a duplicate of report <a href='https://openstax.org/errata/" + str( self.duplicate_id.id) + "'>" + str( self.duplicate_id.id) + "</a>." if self.resolution == "Not An Error" and not self.resolution_notes: self.resolution_notes = "Our reviewers determined this was not an error." if self.resolution == "Will Not Fix" and not self.resolution_notes: self.resolution_notes = "Our reviewers determined the textbook meets scope, sequence, and accuracy requirements as is. No change will be made." if self.resolution == "Major Book Revision" and not self.resolution_notes: self.resolution_notes = "Our reviewers determined this would require a significant book revision. While we cannot make this change at this time, we will consider it for future editions of this book." if (self.status == "Reviewed" or self.status == "Completed" ) and self.resolution == "Approved" and not self.resolution_notes: self.resolution_notes = "Our reviewers accepted this change." if self.status == "Completed" and self.resolution == "Sent to Customer Support" and not self.resolution_notes: self.resolution_notes = "Thank you for this feedback. Your report has been escalated to our Support team. A member of the Support team will contact you with further details." if self.resolution == 'Technical Error' and not self.resolution_notes: self.resolution_notes = 'This a technical error and the proper departments have been notified so that it can be fixed. Thank you for your submission.' if self.resolution == 'More Information Requested' and not self.resolution_notes: self.resolution_notes = 'Thank you for the feedback. Unfortunately, our reviewers were unable to locate this error. Please submit a new report with additional information, such as a link to the relevant content, or a screenshot.' if self.resolution == 'Partner Product' and not self.resolution_notes: self.resolution_notes = 'This issue is occurring on a platform that is not managed by OpenStax. We will make our best efforts to get this resolved; however, we suggest reporting this issue within the platform you are using.' #auto filling a couple of fields if it is clear that it is an assessment errata based on the text that tutor fills into the additional_location_information field if self.additional_location_information and self.resource == 'OpenStax Tutor' and ( '@' in self.additional_location_information.split()[0]): self.is_assessment_errata = 'Yes' self.assessment_id = self.additional_location_information.split( '@', )[0] # set to archived if user is shadow banned if (is_user_shadow_blocked(self.submitted_by_account_id)): self.archived = True # invalidate cloudfront cache so FE updates (remove when errata is no longer in CMS) invalidate_cloudfront_caches() super(Errata, self).save(*args, **kwargs) @hooks.register('register_admin_menu_item') def register_errata_menu_item(): return MenuItem('Errata', '/django-admin/errata/errata', classnames='icon icon-form', order=10000) # @hooks.register('register_admin_menu_item') # def register_errata_menu_item(): # return MenuItem('Errata (beta)', '/api/errata/admin/dashboard/', classnames='icon icon-form', order=10000) def __str__(self): return self.book.book_title class Meta: verbose_name = "erratum" verbose_name_plural = "erratum"
class Cuenta(models.Model): id = models.AutoField(primary_key=True) codigo = models.IntegerField() nombre = models.CharField(max_length = 256) debe = models.DecimalField('debe', max_digits=50, decimal_places=2, blank=False, null=False, validators=[MinValueValidator(0)]) haber = models.DecimalField('haber', max_digits=50, decimal_places=2, blank=False, null=False, validators=[MinValueValidator(0)]) saldoDeudor = models.DecimalField('saldo_deudor', max_digits =50, decimal_places=2,blank=False,null=False,validators=[MinValueValidator(0)],default=0.00) saldoAcreedor = models.DecimalField('saldo_acreedor', max_digits =50, decimal_places=2,blank=False,null=False,validators=[MinValueValidator(0)],default=0.00) codigo_dependiente = models.IntegerField(null= True) descripcion = models.CharField(max_length= 256, null=False, blank=False, default='null') def __str__(self): return '{}{}'.format(self.nombre) def getHaber(self): return self.haber def getDebe(self): return self.debe def getSaldoAcreedor(self): return self.saldoAcreedor def getSaldoDeudor(self): return self.saldoDeudor
class estadoComprobacion(models.Model): id= models.AutoField(primary_key=True) debe =models.DecimalField('debe', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)]) haber= models.DecimalField('haber', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)])
class Salida(models.Model): id=models.AutoField(primary_key=True) kardex=models.ForeignKey(Kardex, null=True, blank=True, on_delete=models.CASCADE) fechaSalida= models.DateField('Fecha de Entrada', help_text='Formato: AAAA/MM/DD', blank=False, null=False) cantidadSalida= models.IntegerField() costoTotalSalida= models.DecimalField('haber', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)]) costoUnitarioSalida= models.DecimalField('haber', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)])
class Orden(models.Model): id=models.AutoField(primary_key=True) pan=models.ForeignKey(Pan, null=True, blank=True, on_delete=models.CASCADE) cif=models.ForeignKey(CIF, null=True, blank=True, on_delete=models.CASCADE) descripcion=models.CharField(max_length = 256) CMOD=models.DecimalField('haber', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)]) cantEmpleados= models.IntegerField() diasTrabajados= models.IntegerField() fechaCreacion= models.DateField('Fecha de Creacion', help_text='Formato: AAAA/MM/DD', blank=False, null=False) fechaEntrega= models.DateField('Fecha de Entrega', help_text='Formato: AAAA/MM/DD', blank=False, null=False) CIF_O=models.DecimalField('haber', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)]) CMP=models.DecimalField('haber', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)]) terminado= models.NullBooleanField(null = False);
class Profile(models.Model): """User profiles storage.""" user = models.OneToOneField(User, unique=True, editable=False, on_delete=models.deletion.CASCADE) language = models.CharField( verbose_name=_("Interface Language"), max_length=10, blank=True, choices=settings.LANGUAGES, ) languages = models.ManyToManyField( Language, verbose_name=_("Translated languages"), blank=True, help_text=_("Choose the languages you can translate to. " "These will be offered to you on the dashboard " "for easier access to your chosen translations."), ) secondary_languages = models.ManyToManyField( Language, verbose_name=_("Secondary languages"), help_text=_( "Choose languages you can understand, strings in those languages " "will be shown in addition to the source string."), related_name="secondary_profile_set", blank=True, ) suggested = models.IntegerField(default=0, db_index=True) translated = models.IntegerField(default=0, db_index=True) uploaded = models.IntegerField(default=0, db_index=True) commented = models.IntegerField(default=0, db_index=True) hide_completed = models.BooleanField( verbose_name=_("Hide completed translations on the dashboard"), default=False) secondary_in_zen = models.BooleanField( verbose_name=_("Show secondary translations in the Zen mode"), default=True) hide_source_secondary = models.BooleanField( verbose_name=_("Hide source if a secondary translation exists"), default=False) editor_link = models.CharField( default="", blank=True, max_length=200, verbose_name=_("Editor link"), help_text=_( "Enter a custom URL to be used as link to the source code. " "You can use {{branch}} for branch, " "{{filename}} and {{line}} as filename and line placeholders."), validators=[validate_editor], ) TRANSLATE_FULL = 0 TRANSLATE_ZEN = 1 translate_mode = models.IntegerField( verbose_name=_("Translation editor mode"), choices=((TRANSLATE_FULL, _("Full editor")), (TRANSLATE_ZEN, _("Zen mode"))), default=TRANSLATE_FULL, ) ZEN_VERTICAL = 0 ZEN_HORIZONTAL = 1 zen_mode = models.IntegerField( verbose_name=_("Zen editor mode"), choices=( (ZEN_VERTICAL, _("Top to bottom")), (ZEN_HORIZONTAL, _("Side by side")), ), default=ZEN_VERTICAL, ) special_chars = models.CharField( default="", blank=True, max_length=30, verbose_name=_("Special characters"), help_text=_( "You can specify additional special visual keyboard characters " "to be shown while translating. It can be useful for " "characters you use frequently, but are hard to type on your keyboard." ), ) nearby_strings = models.SmallIntegerField( verbose_name=_("Number of nearby strings"), default=settings.NEARBY_MESSAGES, validators=[MinValueValidator(1), MaxValueValidator(50)], help_text= _("Number of nearby strings to show in each direction in the full editor." ), ) auto_watch = models.BooleanField( verbose_name=_("Automatically watch projects on contribution"), default=settings.DEFAULT_AUTO_WATCH, help_text= _("Whenever you translate a string in a project, you will start watching it." ), ) DASHBOARD_WATCHED = 1 DASHBOARD_COMPONENT_LIST = 4 DASHBOARD_SUGGESTIONS = 5 DASHBOARD_COMPONENT_LISTS = 6 DASHBOARD_CHOICES = ( (DASHBOARD_WATCHED, _("Watched translations")), (DASHBOARD_COMPONENT_LISTS, _("Component lists")), (DASHBOARD_COMPONENT_LIST, _("Component list")), (DASHBOARD_SUGGESTIONS, _("Suggested translations")), ) DASHBOARD_SLUGS = { DASHBOARD_WATCHED: "your-subscriptions", DASHBOARD_COMPONENT_LIST: "list", DASHBOARD_SUGGESTIONS: "suggestions", DASHBOARD_COMPONENT_LISTS: "componentlists", } dashboard_view = models.IntegerField( choices=DASHBOARD_CHOICES, verbose_name=_("Default dashboard view"), default=DASHBOARD_WATCHED, ) dashboard_component_list = models.ForeignKey( "trans.ComponentList", verbose_name=_("Default component list"), on_delete=models.deletion.SET_NULL, blank=True, null=True, ) watched = models.ManyToManyField( "trans.Project", verbose_name=_("Watched projects"), help_text=_("You can receive notifications for watched projects and " "they are shown on the dashboard by default."), blank=True, ) # Public profile fields website = models.URLField( verbose_name=_("Website URL"), blank=True, ) liberapay = models.SlugField( verbose_name=_("Liberapay username"), blank=True, help_text=_("Liberapay is a platform to donate money to teams, " "organizations and individuals."), ) fediverse = models.URLField( verbose_name=_("Fediverse URL"), blank=True, help_text=_("Link to your Fediverse profile for federated services " "like Mastodon or diaspora*."), ) codesite = models.URLField( verbose_name=_("Code site URL"), blank=True, help_text=_( "Link to your code profile for services like Codeberg or GitLab."), ) github = models.SlugField( verbose_name=_("GitHub username"), blank=True, ) twitter = models.SlugField( verbose_name=_("Twitter username"), blank=True, ) linkedin = models.SlugField( verbose_name=_("LinkedIn profile name"), help_text=_( "Your LinkedIn profile name from linkedin.com/in/profilename"), blank=True, ) location = models.CharField( verbose_name=_("Location"), max_length=100, blank=True, ) company = models.CharField( verbose_name=_("Company"), max_length=100, blank=True, ) public_email = EmailField( verbose_name=_("Public e-mail"), blank=True, max_length=EMAIL_LENGTH, ) def __str__(self): return self.user.username def get_absolute_url(self): return self.user.get_absolute_url() def get_user_display(self): return get_user_display(self.user) def get_user_display_link(self): return get_user_display(self.user, True, True) def get_user_name(self): return get_user_display(self.user, False) def increase_count(self, item: str, increase: int = 1): """Updates user actions counter.""" # Update our copy setattr(self, item, getattr(self, item) + increase) # Update database update = {item: F(item) + increase} Profile.objects.filter(pk=self.pk).update(**update) @property def full_name(self): """Return user's full name.""" return self.user.full_name def clean(self): """Check if component list is chosen when required.""" # There is matching logic in ProfileBaseForm.add_error to ignore this # validation on partial forms if (self.dashboard_view == Profile.DASHBOARD_COMPONENT_LIST and self.dashboard_component_list is None): message = _( "Please choose which component list you want to display on " "the dashboard.") raise ValidationError({ "dashboard_component_list": message, "dashboard_view": message }) if (self.dashboard_view != Profile.DASHBOARD_COMPONENT_LIST and self.dashboard_component_list is not None): message = _( "Selecting component list has no effect when not shown on " "the dashboard.") raise ValidationError({ "dashboard_component_list": message, "dashboard_view": message }) def dump_data(self): def map_attr(attr): if attr.endswith("_id"): return attr[:-3] return attr def dump_object(obj, *attrs): return {map_attr(attr): getattr(obj, attr) for attr in attrs} result = { "basic": dump_object(self.user, "username", "full_name", "email", "date_joined"), "profile": dump_object( self, "language", "suggested", "translated", "uploaded", "hide_completed", "secondary_in_zen", "hide_source_secondary", "editor_link", "translate_mode", "zen_mode", "special_chars", "dashboard_view", "dashboard_component_list_id", ), "auditlog": [ dump_object(log, "address", "user_agent", "timestamp", "activity") for log in self.user.auditlog_set.iterator() ], } result["profile"]["languages"] = [ lang.code for lang in self.languages.iterator() ] result["profile"]["secondary_languages"] = [ lang.code for lang in self.secondary_languages.iterator() ] result["profile"]["watched"] = [ project.slug for project in self.watched.iterator() ] return result @cached_property def primary_language_ids(self) -> Set[int]: return set(self.languages.values_list("pk", flat=True)) @cached_property def allowed_dashboard_component_lists(self): return ComponentList.objects.filter( show_dashboard=True, components__project_id__in=self.user.allowed_project_ids, ).distinct() @cached_property def secondary_language_ids(self) -> Set[int]: return set(self.secondary_languages.values_list("pk", flat=True)) def get_translation_order(self, translation) -> int: """Returns key suitable for ordering languages based on user preferences.""" language = translation.language if language.pk in self.primary_language_ids: return 0 if language.pk in self.secondary_language_ids: return 1 if translation.is_source: return 2 return 3 @cached_property def watched_project_ids(self): # We do not use values_list, because we prefetch this return {watched.id for watched in self.watched.all()} def watches_project(self, project): return project.id in self.watched_project_ids
class MateriaPrima(models.Model): id=models.AutoField(primary_key=True) nombreMateriaPrima= models.CharField(max_length = 256) cantidad = models.IntegerField() precioUnitario= models.DecimalField('haber', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)])
class Shift(models.Model): """ A shift of one job. Columns: :job: job of this shift :begin: begin of the shift :end: end of the shift :number: number of people :blocked: shift is blocked, if the job is public :hidden: shift is not displayed publicly :name: name of the shift (optional) """ class Meta: ordering = ['job', 'begin', 'end'] job = models.ForeignKey( 'Job', on_delete=models.CASCADE, ) name = models.CharField( max_length=200, verbose_name=_("Name (optional)"), default="", blank=True, ) begin = models.DateTimeField(verbose_name=_("Begin"), ) end = models.DateTimeField(verbose_name=_("End"), ) number = models.IntegerField( default=0, verbose_name=_("Number of helpers"), validators=[MinValueValidator(0)], ) blocked = models.BooleanField( default=False, verbose_name=_("The shift is blocked and displayed as full."), ) hidden = models.BooleanField( default=False, verbose_name=_("The shift is not visible."), ) gifts = models.ManyToManyField( 'gifts.GiftSet', verbose_name=_("Gifts"), blank=True, ) archived_number = models.IntegerField( default=0, verbose_name=_("Number of registered helpers for archived event"), ) def __str__(self): if self.name: return "%s, %s, %s" % (self.job.name, self.name, self.time_with_day()) else: return "%s, %s" % (self.job.name, self.time_with_day()) def time(self): """ Returns a string representation of the begin and end time. The begin contains the date and time, the end only the time. """ return "%s, %s - %s" % (date_f(localtime(self.begin), 'DATE_FORMAT'), date_f(localtime(self.begin), 'TIME_FORMAT'), date_f(localtime(self.end), 'TIME_FORMAT')) def time_hours(self): """ Returns a string representation of the begin and end time. Only the time is used, the date is not shown. """ return "%s - %s" % (date_f(localtime(self.begin), 'TIME_FORMAT'), date_f(localtime(self.end), 'TIME_FORMAT')) def time_with_day(self): """ Returns a string representation of the day. If the shift is on two days only the name of the first day is returned. """ day = date_f(localtime(self.begin), "l") return "{}, {}".format(day, self.time()) def date(self): """ Returns the day on which the shifts begins. """ return localtime(self.begin).date() def num_helpers(self): """ Returns the current number of helpers, but 0 if event is archived. """ return self.helper_set.count() def num_helpers_archived(self): """ Returns the current number of helpers- """ if self.job.event.archived: return self.archived_number else: return self.helper_set.count() def is_full(self): """ Check if the shift is full and return a boolean. """ return self.num_helpers() >= self.number def helpers_percent(self): """ Calculate the percentage of registered helpers and returns an int. If the maximal number of helpers for a shift is 0, 0 is returned. """ if self.number == 0: return 0 num = self.num_helpers_archived() return int(round(float(num) / self.number * 100.0, 0)) def helpers_percent_5percent(self): percent = self.helpers_percent() return math.ceil(percent / 5) @property def shirt_sizes(self): # data structure shirts = OrderedDict() for size, name in self.job.event.get_shirt_choices(): shirts.update({name: 0}) # collect all sizes, this must be the first shift of the helper for helper in self.helper_set.all(): if helper.first_shift == self: tmp = shirts[helper.get_shirt_display()] shirts.update({helper.get_shirt_display(): tmp + 1}) return shirts def duplicate(self, new_date=None, new_job=None, gift_set_mapping=None): """ Duplicate a shift. There are multiple possibilities: * Shift is copied to new day in same job: set new_date * Shift is copied to new job in same event: set new_job * Shift is copied to new event: set new_job and gift_set_mapping """ new_shift = deepcopy(self) new_shift.pk = None new_shift.archived_number = 0 # maybe shift is copied to new job if new_job: new_shift.job = new_job # if shift is copied to new event, move begin and end time according to diff in event dates if self.job.event != new_job.event: diff = new_job.event.date - self.job.event.date new_shift.begin += diff new_shift.end += diff # maybe just the date is changed if new_date: new_shift.begin = new_shift.begin.replace(year=new_date.year) new_shift.begin = new_shift.begin.replace(month=new_date.month) new_shift.begin = new_shift.begin.replace(day=new_date.day) new_shift.end = new_shift.end.replace(year=new_date.year) new_shift.end = new_shift.end.replace(month=new_date.month) new_shift.end = new_shift.end.replace(day=new_date.day) # now save that new_shift.save() # and finally set the gifts again for gift in self.gifts.all(): if gift_set_mapping: new_shift.gifts.add(gift_set_mapping[gift]) else: new_shift.gifts.add(gift) return new_shift
class OrderLine(models.Model): order = models.ForeignKey(Order, related_name="lines", editable=False, on_delete=models.CASCADE) variant = models.ForeignKey( "product.ProductVariant", related_name="order_lines", on_delete=models.SET_NULL, blank=True, null=True, ) # max_length is as produced by ProductVariant's display_product method product_name = models.CharField(max_length=386) variant_name = models.CharField(max_length=255, default="", blank=True) translated_product_name = models.CharField(max_length=386, default="", blank=True) translated_variant_name = models.CharField(max_length=255, default="", blank=True) product_sku = models.CharField(max_length=255) is_shipping_required = models.BooleanField() quantity = models.IntegerField(validators=[MinValueValidator(1)]) quantity_fulfilled = models.IntegerField(validators=[MinValueValidator(0)], default=0) currency = models.CharField( max_length=settings.DEFAULT_CURRENCY_CODE_LENGTH, ) unit_discount_amount = models.DecimalField( max_digits=settings.DEFAULT_MAX_DIGITS, decimal_places=settings.DEFAULT_DECIMAL_PLACES, default=0, ) unit_discount = MoneyField(amount_field="unit_discount_amount", currency_field="currency") unit_discount_type = models.CharField( max_length=10, choices=DiscountValueType.CHOICES, default=DiscountValueType.FIXED, ) unit_discount_reason = models.TextField(blank=True, null=True) unit_price_net_amount = models.DecimalField( max_digits=settings.DEFAULT_MAX_DIGITS, decimal_places=settings.DEFAULT_DECIMAL_PLACES, ) # stores the value of the applied discount. Like 20 of % unit_discount_value = models.DecimalField( max_digits=settings.DEFAULT_MAX_DIGITS, decimal_places=settings.DEFAULT_DECIMAL_PLACES, default=0, ) unit_price_net = MoneyField(amount_field="unit_price_net_amount", currency_field="currency") unit_price_gross_amount = models.DecimalField( max_digits=settings.DEFAULT_MAX_DIGITS, decimal_places=settings.DEFAULT_DECIMAL_PLACES, ) unit_price_gross = MoneyField(amount_field="unit_price_gross_amount", currency_field="currency") unit_price = TaxedMoneyField( net_amount_field="unit_price_net_amount", gross_amount_field="unit_price_gross_amount", currency="currency", ) total_price_net_amount = models.DecimalField( max_digits=settings.DEFAULT_MAX_DIGITS, decimal_places=settings.DEFAULT_DECIMAL_PLACES, ) total_price_net = MoneyField( amount_field="total_price_net_amount", currency_field="currency", ) total_price_gross_amount = models.DecimalField( max_digits=settings.DEFAULT_MAX_DIGITS, decimal_places=settings.DEFAULT_DECIMAL_PLACES, ) total_price_gross = MoneyField( amount_field="total_price_gross_amount", currency_field="currency", ) total_price = TaxedMoneyField( net_amount_field="total_price_net_amount", gross_amount_field="total_price_gross_amount", currency="currency", ) tax_rate = models.DecimalField(max_digits=5, decimal_places=4, default=Decimal("0.0")) objects = OrderLineQueryset.as_manager() class Meta: ordering = ("pk", ) def __str__(self): return (f"{self.product_name} ({self.variant_name})" if self.variant_name else self.product_name) @property def undiscounted_unit_price(self) -> "TaxedMoney": return self.unit_price + self.unit_discount @property def quantity_unfulfilled(self): return self.quantity - self.quantity_fulfilled @property def is_digital(self) -> Optional[bool]: """Check if a variant is digital and contains digital content.""" if not self.variant: return None is_digital = self.variant.is_digital() has_digital = hasattr(self.variant, "digital_content") return is_digital and has_digital
class FileInputForm(forms.Form, BaseFormFieldPluginForm): """Form for ``FileInputPlugin``.""" plugin_data_fields = [ ("label", ""), ("name", ""), ("help_text", ""), ("initial", ""), ("max_length", str(DEFAULT_MAX_LENGTH)), ("required", False) ] label = forms.CharField( label=_("Label"), required=True, widget=forms.widgets.TextInput( attrs={'class': theme.form_element_html_class} ) ) name = forms.CharField( label=_("Name"), required=True, widget=forms.widgets.TextInput( attrs={'class': theme.form_element_html_class} ) ) help_text = forms.CharField( label=_("Help text"), required=False, widget=forms.widgets.Textarea( attrs={'class': theme.form_element_html_class} ) ) initial = forms.CharField( label=_("Initial"), required=False, widget=forms.widgets.TextInput( attrs={'class': theme.form_element_html_class} ) ) max_length = forms.IntegerField( label=_("Max length"), required=True, widget=NumberInput(attrs={'class': theme.form_element_html_class, 'min': str(DEFAULT_MIN_LENGTH)}), initial=DEFAULT_MAX_LENGTH, validators=[MinValueValidator(DEFAULT_MIN_LENGTH)] ) required = forms.BooleanField( label=_("Required"), required=False, widget=forms.widgets.CheckboxInput( attrs={'class': theme.form_element_checkbox_html_class} ) ) def clean(self): super(FileInputForm, self).clean() max_length = self.cleaned_data.get('max_length', DEFAULT_MAX_LENGTH) if self.cleaned_data['initial']: len_initial = len(self.cleaned_data['initial']) if len_initial > max_length: self.add_error( 'initial', _("Ensure this value has at most {0} characters " "(it has {1}).".format(max_length, len_initial)) )
class game_settings(models.Model): """ Game's basic settings. NOTE: Only uses the first record! """ # The name of your game. game_name = models.CharField(max_length=NAME_LENGTH, blank=True) # The screen shows to players who are not loggin. connection_screen = models.TextField(blank=True) # In solo mode, a player can not see or affect other players. solo_mode = models.BooleanField(blank=True, default=False) # Time of global CD. global_cd = models.FloatField(blank=True, default=1.0, validators=[MinValueValidator(0.0)]) # The CD of auto casting a skill. It must be bigger than GLOBAL_CD # They can not be equal! auto_cast_skill_cd = models.FloatField(blank=True, default=1.5, validators=[MinValueValidator(0.0)]) # Allow players to give up quests. can_give_up_quests = models.BooleanField(blank=True, default=True) # can close dialogue box or not. can_close_dialogue = models.BooleanField(blank=True, default=False) # Can resume unfinished dialogues automatically. auto_resume_dialogues = models.BooleanField(blank=True, default=True) # The key of a world room. # It is the default home location used for all objects. This is used as a # fallback if an object's normal home location is deleted. It is the # key of the room. If it is empty, the home will be set to the first # room in WORLD_ROOMS. default_home_key = models.CharField(max_length=KEY_LENGTH, blank=True) # The key of a world room. # The start position for new characters. It is the key of the room. # If it is empty, the home will be set to the first room in WORLD_ROOMS. start_location_key = models.CharField(max_length=KEY_LENGTH, blank=True) # The key of a world room. # Player's default home. When a player dies, he will be moved to his home. default_player_home_key = models.CharField(max_length=KEY_LENGTH, blank=True) # The key of a character. # Default character of players. default_player_character_key = models.CharField(max_length=KEY_LENGTH, blank=True) class Meta: "Define Django meta options" abstract = True app_label = "worlddata" verbose_name = "Game Setting" verbose_name_plural = "Game Settings"
class DecimalFieldModel(models.Model): decimal_field = models.DecimalField( max_digits=3, decimal_places=1, validators=[MinValueValidator(1), MaxValueValidator(3)])
class Kheladi(models.Model): ROLE_CHOICES = ( ('all rounder', 'all rounder'), ('bowler', 'bowler'), ('batsman', 'batsman'), ) BATTING_CHOICES = ( ('right hand bat', 'right hand bat'), ('left hand bat', 'left hand bat'), ) BOWLING_CHOICES = ( ('right arm fast', 'right arm fast'), ('left arm fast', 'left arm fast'), ('left arm spin', 'left arm spin'), ('right arm spin', 'right arm spin'), ) first_name = models.CharField(max_length=50, db_index=True) last_name = models.CharField(max_length=50, ) bio = models.TextField(db_index=True) favourite_cricketer = models.CharField(max_length=30, db_index=True) dp = CloudinaryField(verbose_name='profile picture', db_index=True) country = models.CharField(max_length=7, db_index=True) slug = models.SlugField(blank=True, null=True, editable=False, db_index=True) uuid = models.UUIDField(blank=True, null=True, default=uuid.uuid4, db_index=True) dob = models.DateField(verbose_name='Date of Birth', default=timezone.now, help_text='Enter in format YYYY-MM-DD', db_index=True) age = models.PositiveIntegerField(blank=True, db_index=True) height = models.CharField(default=0, max_length=10, db_index=True) role = models.CharField(choices=ROLE_CHOICES, max_length=20, default='all rounder', db_index=True) contact = models.CharField(max_length=30, blank=True, null=True, db_index=True) batting_style = models.CharField(choices=BATTING_CHOICES, max_length=20, default='right hand bat', db_index=True) bowling_style = models.CharField(choices=BOWLING_CHOICES, max_length=20, default='right arm bowl', db_index=True) highest_score = models.IntegerField( default=0, validators=[MinValueValidator(0), MaxValueValidator(200)], db_index=True) highest_wicket = models.IntegerField( default=0, validators=[MinValueValidator(0), MaxValueValidator(10)], db_index=True) def __str__(self): return self.first_name def save(self, **kwargs): if not self.age: self.age = int((timezone.now().date() - self.dob).days / 365) if not self.slug: self.slug = slugify(f'{self.first_name} {self.last_name}') super(Kheladi, self).save(**kwargs) def get_absolute_url(self): return reverse('cricket:player_detail', kwargs={ 'slug': self.slug, 'uuid': self.uuid }) class Meta: verbose_name_plural = 'Kheladi' ordering = ['first_name']
class Profile(models.Model): userid = models.CharField(primary_key=True, unique=True, max_length=6, default='') user = models.OneToOneField(User, on_delete=models.CASCADE) about = models.CharField(max_length=200) can_see = models.BooleanField(default=False) can_rate = models.BooleanField(default=True) updated_at = models.DateTimeField(auto_now=True) current_rating = models.FloatField( default=0.0, validators=[MinValueValidator(0.0), MaxValueValidator(10.0)]) cumulated_rating = models.FloatField( default=0.0, validators=[MinValueValidator(0.0), MaxValueValidator(10.0)]) public_key = models.TextField() #user public key # ImageField¶ While adding profile pictures # class ImageField(upload_to=None, height_field=None, width_field=None, max_length=100, **options) def __str__(self): return self.userid def updateMyRating(self, new_rating, session): # A control object must be present recent_control = (Control.objects.latest('updated_at')) recent_session_number = recent_control.session_number total_ratings_taken = Rating.objects.all().filter( user2=self.userid).filter( session_number=recent_session_number).count() recent_ratings_taken = Rating.objects.all().filter( user2=self.userid).filter( session_number=recent_session_number).count() total_ratings_taken = max(total_ratings_taken, 1) recent_ratings_taken = max(recent_ratings_taken, 1) # if Divide by zero because of no ratings self.current_rating = (self.current_rating * (recent_ratings_taken - 1) + int(new_rating)) / recent_ratings_taken self.cumulated_rating = (self.cumulated_rating * (total_ratings_taken - 1) + int(new_rating)) / total_ratings_taken self.save() def update_can_see(self, session): recent_control = (Control.objects.latest('updated_at')) recent_session_number = recent_control.session_number threshold = recent_control.threshold_persons recent_ratings_given = Rating.objects.all().filter( user1=self.userid).filter( session_number=recent_session_number).count() self.can_see = True if recent_ratings_given > threshold else False self.save() def get_absolute_url(self): return ("/user/" + self.userid) def get_latest_work(self): works = Work.objects.filter( user=self).order_by('-updated_at').values('work') trueworks = [] for work in works: data = work.get('work') trueworks.append(data) works = trueworks try: latest_work = works[0] decrypted_work = signing.loads(latest_work) return decrypted_work[0] except: return None @receiver(post_save, sender=User) def create_user_profile(sender, instance, created, **kwargs): if created: Profile.objects.create(user=instance, userid=instance.username) @receiver(post_save, sender=User) def save_user_profile(sender, instance, **kwargs): instance.profile.save()
class Device(LoggingModel): """ Device instance with. Each device must be assigned to location and can be place to rack. """ #TODO: добавить обьединение в кластер, генерация IP адресов FRONT = 1 REAR = 0 RACK_SIDE_CHOICES = ( (FRONT, 'Located at the front of rack'), (REAR, 'Located at the rear of rack'), ) name = models.CharField( max_length=50, unique=True ) device_model = models.ForeignKey( to=VendorModel, on_delete=models.PROTECT, related_name='instances' ) device_role = models.ForeignKey( to=DeviceRole, on_delete=models.PROTECT, related_name='devices' ) platform = models.ForeignKey( to=Platform, on_delete=models.SET_NULL, related_name='devices', blank=True, null=True ) serial = models.CharField( max_length=50, blank=True, verbose_name='Serial number' ) location = models.ForeignKey( to=Location, on_delete=models.PROTECT, related_name='devices' ) rack = models.ForeignKey( to=Rack, on_delete=models.PROTECT, related_name='devices', blank=True, null=True ) position = models.PositiveSmallIntegerField( blank=True, null=True, validators=[MinValueValidator(1)], verbose_name='Unit Number', help_text='Unit Number device starts location in the rack' ) face_position = models.PositiveSmallIntegerField( choices=RACK_SIDE_CHOICES, default=FRONT, blank=True, null=True ) # cluster = models.ForeignKey( # to='Cluster', # on_delete=models.SET_NULL, # related_name='devices', # blank=True, # null=True # ) # primary_ip = models.OneToOneField( # to='IPAddress', # on_delete=models.SET_NULL, # related_name='primary_ip', # blank=True, # null=True, # verbose_name='Основной IP адрес' # ) description = models.CharField( max_length=100, blank=True ) comment = models.TextField( blank=True ) images = GenericRelation( to=ImgAttach ) tag = TaggableManager( through=TaggedItem ) class Meta: ordering = ('name', 'pk') def __str__(self): return self.display_name or super().__str__() return self.name @property def display_name(self): if self.name: return self.name elif hasattr(self, 'device_model'): return "{}".format(self.device_model) return "" def get_absolute_url(self): return reverse('organisation:device', args=[self.pk]) def clean(self): super().clean() if self.rack is None: if self.position: raise ValidationError({ 'position': "Cannot select position without rack selected.", }) if self.face_position: raise ValidationError({ 'face_position': "Cannot select face_position without rack selected.", })
class Analysis(models.Model): name = models.CharField(max_length=30, unique=True, validators=[MinLengthValidator(3)]) date_create = models.DateField(auto_now_add=True) date_modification = models.DateField(auto_now=True) data_set = models.FileField(upload_to="data_sets/") signal_speed = models.IntegerField(validators=[MaxValueValidator(4), MinValueValidator(1)]) signal_direction = models.IntegerField(validators=[MaxValueValidator(4), MinValueValidator(1)]) step_group = models.IntegerField(validators=[greater_zero]) start_sector_direction = models.IntegerField( validators=[MaxValueValidator(360), MinValueValidator(0)] ) end_sector_direction = models.IntegerField( validators=[MaxValueValidator(360), MinValueValidator(0)] ) start_sector_speed = models.IntegerField(validators=[MinValueValidator(0)]) end_sector_speed = models.IntegerField(validators=[MinValueValidator(0)]) result_analysis = models.FilePathField(blank=True) user = models.ForeignKey(User, on_delete=models.CASCADE) def __str__(self): return self.name class Meta: ordering = ["date_modification"] def delete(self, using=None, keep_parents=False): shutil.rmtree(self.result_analysis) self.data_set.delete(save=False) super(Analysis, self).delete(using, keep_parents) def delete_results_analysis(self): if os.path.exists(self.result_analysis): for analysis_file in os.listdir(self.result_analysis): os.remove(os.path.join(self.result_analysis, analysis_file)) logging.warning(f"Path does not exists {self.result_analysis}") def save(self, force_insert=False, force_update=False, using=None, update_fields=None): is_new = self.pk is None self.calculate_analysis() if is_new: self.result_analysis = os.path.join(settings.MEDIA_ROOT, self.name) super().save(force_insert, force_update, using, update_fields) def calculate_analysis(self): try: ApplicationManager().go( self, settings.MEDIA_ROOT, ) except Exception as e: try: Analysis.objects.get(name=self.name) except ObjectDoesNotExist: shutil.rmtree(os.path.join(settings.MEDIA_ROOT, self.name)) raise ValidationError(e) def create_archive(self): file_name = "{}_{}.zip".format(self.name, self.date_modification) base_name_dir = "zip_files" abs_path_dir = os.path.join(settings.MEDIA_ROOT, base_name_dir) if not os.path.exists(abs_path_dir): os.mkdir(abs_path_dir) compress_zip(os.path.join(abs_path_dir, file_name), get_all_abs_paths(self.result_analysis)) archive = ZipArchive() archive.name = self.name archive.zip_file = os.path.join(base_name_dir, file_name) archive.analysis = self archive.save() return archive def delete_archive(self): try: ZipArchive.objects.get(name=self.name).delete() except Exception: pass
class Rack(LoggingModel): """ Rack configuration """ TYPE_1FRAME = '1-frame' TYPE_2FRAME = '2-frame' TYPE_WALLCABINET = 'wall-cabinet' TYPE_FLOORCABINET = 'floor-cabinet' TOP_TO_BUTTOM = 0 BUTTOM_TO_TOP = 1 RACK_TYPE_CHOICES = ( (TYPE_1FRAME, 'One Frame rack'), (TYPE_2FRAME, 'Two Frame rack'), (TYPE_WALLCABINET, 'Wall-mounted cabinet'), (TYPE_FLOORCABINET, 'Floor-mounted cabinet'), ) RACK_UNIT_DESC = ( (TOP_TO_BUTTOM, 'Top to buttom'), (BUTTOM_TO_TOP, 'Buttom to top'), ) name = models.CharField( max_length=50 ) location = models.ForeignKey( to=Location, on_delete=models.PROTECT, related_name='racks' ) u_height = models.PositiveSmallIntegerField( default=44, verbose_name='Unit Height', validators=[MinValueValidator(1), MaxValueValidator(100)] ) desc_units = models.BooleanField( choices=RACK_UNIT_DESC, default=BUTTOM_TO_TOP, verbose_name='Orientation', help_text='Default buttom to top' ) racktype = models.CharField( max_length=50, choices=RACK_TYPE_CHOICES, default=TYPE_FLOORCABINET, ) comment = models.TextField( blank=True ) class Meta: ordering = ('location', 'name', 'pk') def __str__(self): return self.name # def __str__(self): # return self.display_name or super().__str__() def get_absolute_url(self): return reverse('organisation:rack', args=[self.pk])
class Organizacion(models.Model): """ Tabla de las organizaciones que proponen un proyecto al EsIA. Parametros: models.Model (Organizacion): Instancia sobre la que se crea la tabla. Atributos de la clase: proyecto: proyecto al que pertenece la organizacion razon_social: Razon social de la organizacion nombre: Nombre de la orgnizacion rif: Rif de la organizacion direccion: direccion de la organizacion representante_legal: Datos del representante legal de la organizacion telefono: Telefono de la organizacion email: Email de la organizacion """ proyecto = models.ForeignKey(DatosProyecto, on_delete=models.CASCADE) RAZON_SOCIAL_CHOICES = (('natural', 'Persona natural'), ('juridica', 'Persona Jurídica')) razon_social = models.CharField(max_length=8, choices=RAZON_SOCIAL_CHOICES) nombre = models.CharField(max_length=100) rif = models.CharField( max_length=12, unique=True, validators=[ RegexValidator( re.compile('^([VEJPGvejpg]{1})-([0-9]{8})-([0-9]{1}$)'), _('RIF incorrecto'), 'invalid') ]) direccion = models.TextField() nombre_representante_legal = models.CharField( max_length=60, validators=[ RegexValidator(re.compile(r'^[\w+\s]+$'), _('Nombre incorrecto'), 'invalid') ]) apellido_representante_legal = models.CharField( max_length=60, validators=[ RegexValidator(re.compile(r'^[\w+\s]+$'), _('Apellido incorrecto'), 'invalid') ]) cedula_representante_legal = models.CharField( max_length=9, validators=[ RegexValidator(re.compile('^[V|E|J|P][0-9]{5,9}$'), _('Cédula incorrecta'), 'invalid') ]) pasaporte_representante_legal = models.IntegerField( validators=[MinValueValidator(0)], blank=True, null=True) telefono = models.CharField(max_length=11, validators=[ RegexValidator((re.compile('^[0-9]{11}$')), _('Teléfono incorrecto'), 'invalid') ]) email = models.EmailField() def get_model_type(self): # pylint: disable=no-self-use '''Devuelve el tipo de modelo''' return "Organizacion"
from django.db.models import * import uuid from django.core.validators import MinValueValidator, MaxValueValidator, URLValidator, ValidationError from common.utils import all_h_tags import bleach import re zero_to_one_validator = [ MinValueValidator(0, "This can't be a negative value"), MaxValueValidator(1, "This can't be greater than 1") ] ALLOWED_HTML_TAGS = [ *bleach.sanitizer.ALLOWED_TAGS, *['p', 'dl', 'dd', 'dt', 'img', 'svg', 'span', 'div', 's', 'hr', 'sub', 'sup', 'code', 'table', 'tr', 'td', 'th', 'tbody', 'thead', 'pre', 'br', 'u'], *all_h_tags() ] ALLOWED_HTML_ATTRS = { **bleach.sanitizer.ALLOWED_ATTRIBUTES, **{ 'img': ['src', 'alt'], 'svg': ['src', 'alt'], 'span': ['style', 'class'], 'div': ['style', 'class']
class Denizen(models.Model): name = models.CharField(_("name"), max_length=30) fathers_name = models.CharField(_("father's name"), max_length=20, null=True, blank=True) phone = models.CharField(_("phone"), max_length=30) edu_foundations = models.CharField(_("Education Foundations"), max_length=60, default='', blank=True) email = models.EmailField(_("email"), null=True, blank=True) state = models.CharField(_("state"), blank=True, max_length=1, null=True, choices=STATE_CHOICES, default='N') hood = models.CharField(_("Neighborhood"), blank=True, max_length=32, choices=HOOD_CHOICES) election_day = models.CharField(_("willing to voounteer on election day"), blank=True, max_length=1, choices=VOLUNTEER_CHOICES) second_ring = models.CharField(_("willing to be in the second ring"), blank=True, max_length=1, choices=VOLUNTEER_CHOICES) home_meetup = models.CharField(_("willing to host a meetup"), blank=True, max_length=1, choices=VOLUNTEER_CHOICES) palrig = models.CharField(_("willing to hang a palrig"), blank=True, max_length=1, choices=VOLUNTEER_CHOICES) call_center = models.CharField(_("willing to be a call center volounteer"), blank=True, max_length=1, choices=VOLUNTEER_CHOICES) field = models.CharField(_("willing to be a volounteer in the field"), blank=True, max_length=1, choices=VOLUNTEER_CHOICES) digital = models.CharField(_("willing to digital volounteer"), blank=True, max_length=1, choices=VOLUNTEER_CHOICES) meetup_guest = models.CharField(_("want to be a guest in a meetup"), blank=True, max_length=1, choices=VOLUNTEER_CHOICES) women_rights = models.BooleanField(_("Interested in women rights"), default=False) participation = models.BooleanField(_("Interested in civic participation"), default=False) commons = models.BooleanField(_("Interested in the commons"), default=False) education = models.BooleanField(_("Interested in education"), default=False) religion = models.BooleanField(_("Interested in religion"), default=False) address = models.CharField(_("Address"), max_length=40, blank=True, default='') notes = models.TextField(_("Notes"), blank=True, default='') zehut = models.CharField(_("zehut"), max_length=9, blank=True, null=True) birth_year = models.IntegerField( _("birth year"), blank=True, null=True, validators=[ MinValueValidator(1910, _("they can't be more than 108 years old")), MaxValueValidator(2000, _("They can't be younger than 18")) ]) ballot = models.CharField(_("ballot name"), blank=True, max_length=30) source = models.CharField(_("Source"), max_length=20) whatever = models.CharField(_("Whatever"), max_length=60, default='') created_on = models.DateTimeField(auto_now_add=True) last_modified = models.DateTimeField(auto_now=True) class Meta: verbose_name = _("Denizen") verbose_name_plural = _("Denizens") def save(self): #TODO: DRY !!! if self.election_day.lower() == 'x': self.election_day = 'W' if self.second_ring.lower() == 'x': self.second_ring = 'W' if self.home_meetup.lower() == 'x': self.home_meetup = 'W' if self.palrig.lower() == 'x': self.palrig = 'W' if self.digital.lower() == 'x': self.digital = 'W' if self.election_day.lower() == 'x': self.election_day = 'W' if self.election_day.lower() == 'x': self.election_day = 'W' if self.field.lower() == 'x': self.field = 'W' if self.meetup_guest.lower() == 'x': self.meetup_guest = 'W' super().save() def __str__(self): return self.name
class CIF(models.Model): id=models.AutoField(primary_key=True) porcentaje=models.DecimalField('haber', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)])
class BomItem(models.Model): """ A BomItem links a part to its component items. A part can have a BOM (bill of materials) which defines which parts are required (and in what quatity) to make it. Attributes: part: Link to the parent part (the part that will be produced) sub_part: Link to the child part (the part that will be consumed) quantity: Number of 'sub_parts' consumed to produce one 'part' reference: BOM reference field (e.g. part designators) overage: Estimated losses for a Build. Can be expressed as absolute value (e.g. '7') or a percentage (e.g. '2%') note: Note field for this BOM item checksum: Validation checksum for the particular BOM line item """ def get_absolute_url(self): return reverse('bom-item-detail', kwargs={'pk': self.id}) # A link to the parent part # Each part will get a reverse lookup field 'bom_items' part = models.ForeignKey(Part, on_delete=models.CASCADE, related_name='bom_items', help_text=_('Select parent part'), limit_choices_to={ 'assembly': True, }) # A link to the child item (sub-part) # Each part will get a reverse lookup field 'used_in' sub_part = models.ForeignKey(Part, on_delete=models.CASCADE, related_name='used_in', help_text=_('Select part to be used in BOM'), limit_choices_to={ 'component': True, }) # Quantity required quantity = models.DecimalField( default=1.0, max_digits=15, decimal_places=5, validators=[MinValueValidator(0)], help_text=_('BOM quantity for this BOM item')) overage = models.CharField( max_length=24, blank=True, validators=[validators.validate_overage], help_text=_( 'Estimated build wastage quantity (absolute or percentage)')) reference = models.CharField(max_length=500, blank=True, help_text=_('BOM item reference')) # Note attached to this BOM line item note = models.CharField(max_length=500, blank=True, help_text=_('BOM item notes')) checksum = models.CharField(max_length=128, blank=True, help_text=_('BOM line checksum')) def get_item_hash(self): """ Calculate the checksum hash of this BOM line item: The hash is calculated from the following fields: - Part.full_name (if the part name changes, the BOM checksum is invalidated) - Quantity - Reference field - Note field """ # Seed the hash with the ID of this BOM item hash = hashlib.md5(str(self.id).encode()) # Update the hash based on line information hash.update(str(self.sub_part.id).encode()) hash.update(str(self.sub_part.full_name).encode()) hash.update(str(self.quantity).encode()) hash.update(str(self.note).encode()) hash.update(str(self.reference).encode()) return str(hash.digest()) def validate_hash(self, valid=True): """ Mark this item as 'valid' (store the checksum hash). Args: valid: If true, validate the hash, otherwise invalidate it (default = True) """ if valid: self.checksum = str(self.get_item_hash()) else: self.checksum = '' self.save() @property def is_line_valid(self): """ Check if this line item has been validated by the user """ # Ensure an empty checksum returns False if len(self.checksum) == 0: return False return self.get_item_hash() == self.checksum def clean(self): """ Check validity of the BomItem model. Performs model checks beyond simple field validation. - A part cannot refer to itself in its BOM - A part cannot refer to a part which refers to it """ # A part cannot refer to itself in its BOM try: if self.sub_part is not None and self.part is not None: if self.part == self.sub_part: raise ValidationError({ 'sub_part': _('Part cannot be added to its own Bill of Materials') }) # TODO - Make sure that there is no recusion # Test for simple recursion for item in self.sub_part.bom_items.all(): if self.part == item.sub_part: raise ValidationError({ 'sub_part': _("Part '{p1}' is used in BOM for '{p2}' (recursive)". format(p1=str(self.part), p2=str(self.sub_part))) }) except Part.DoesNotExist: # A blank Part will be caught elsewhere pass class Meta: verbose_name = "BOM Item" # Prevent duplication of parent/child rows unique_together = ('part', 'sub_part') def __str__(self): return "{n} x {child} to make {parent}".format( parent=self.part.full_name, child=self.sub_part.full_name, n=helpers.decimal2string(self.quantity)) def get_overage_quantity(self, quantity): """ Calculate overage quantity """ # Most of the time overage string will be empty if len(self.overage) == 0: return 0 overage = str(self.overage).strip() # Is the overage an integer value? try: ovg = int(overage) if ovg < 0: ovg = 0 return ovg except ValueError: pass # Is the overage a percentage? if overage.endswith('%'): overage = overage[:-1].strip() try: percent = float(overage) / 100.0 if percent > 1: percent = 1 if percent < 0: percent = 0 return int(percent * quantity) except ValueError: pass # Default = No overage return 0 def get_required_quantity(self, build_quantity): """ Calculate the required part quantity, based on the supplier build_quantity. Includes overage estimate in the returned value. Args: build_quantity: Number of parts to build Returns: Quantity required for this build (including overage) """ # Base quantity requirement base_quantity = self.quantity * build_quantity return base_quantity + self.get_overage_quantity(base_quantity) @property def price_range(self): """ Return the price-range for this BOM item. """ prange = self.sub_part.get_price_range(self.quantity) if prange is None: return prange pmin, pmax = prange # remove trailing zeros pmin = pmin.normalize() pmax = pmax.normalize() if pmin == pmax: return str(pmin) return "{pmin} to {pmax}".format(pmin=pmin, pmax=pmax)
class Final(models.Model): id=models.AutoField(primary_key=True) kardex=models.ForeignKey(Kardex, null=True, blank=True, on_delete=models.CASCADE) fechaFinal= models.DateField('Fecha de Final', help_text='Formato: AAAA/MM/DD', blank=False, null=False) cantidadFinal= models.IntegerField() costoTotalFinal= models.DecimalField('Costo Final', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)]) costoUnitarioFinal= models.DecimalField('Costo Unitario FInal', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)]) es_Actual= models.NullBooleanField(null = True, default=False);
class Part(models.Model): """ The Part object represents an abstract part, the 'concept' of an actual entity. An actual physical instance of a Part is a StockItem which is treated separately. Parts can be used to create other parts (as part of a Bill of Materials or BOM). Attributes: name: Brief name for this part variant: Optional variant number for this part - Must be unique for the part name category: The PartCategory to which this part belongs description: Longer form description of the part keywords: Optional keywords for improving part search results IPN: Internal part number (optional) revision: Part revision is_template: If True, this part is a 'template' part and cannot be instantiated as a StockItem URL: Link to an external page with more information about this part (e.g. internal Wiki) image: Image of this part default_location: Where the item is normally stored (may be null) default_supplier: The default SupplierPart which should be used to procure and stock this part minimum_stock: Minimum preferred quantity to keep in stock units: Units of measure for this part (default='pcs') salable: Can this part be sold to customers? assembly: Can this part be build from other parts? component: Can this part be used to make other parts? purchaseable: Can this part be purchased from suppliers? trackable: Trackable parts can have unique serial numbers assigned, etc, etc active: Is this part active? Parts are deactivated instead of being deleted virtual: Is this part "virtual"? e.g. a software product or similar notes: Additional notes field for this part """ class Meta: verbose_name = "Part" verbose_name_plural = "Parts" def __str__(self): return "{n} - {d}".format(n=self.full_name, d=self.description) @property def full_name(self): """ Format a 'full name' for this Part. - IPN (if not null) - Part name - Part variant (if not null) Elements are joined by the | character """ elements = [] if self.IPN: elements.append(self.IPN) elements.append(self.name) if self.revision: elements.append(self.revision) return ' | '.join(elements) def set_category(self, category): # Ignore if the category is already the same if self.category == category: return self.category = category self.save() def get_absolute_url(self): """ Return the web URL for viewing this part """ return reverse('part-detail', kwargs={'pk': self.id}) def get_image_url(self): """ Return the URL of the image for this part """ if self.image: return os.path.join(settings.MEDIA_URL, str(self.image.url)) else: return os.path.join(settings.STATIC_URL, 'img/blank_image.png') def validate_unique(self, exclude=None): """ Validate that a part is 'unique'. Uniqueness is checked across the following (case insensitive) fields: * Name * IPN * Revision e.g. there can exist multiple parts with the same name, but only if they have a different revision or internal part number. """ super().validate_unique(exclude) # Part name uniqueness should be case insensitive try: parts = Part.objects.exclude(id=self.id).filter( name__iexact=self.name, IPN__iexact=self.IPN, revision__iexact=self.revision) if parts.exists(): msg = _("Part must be unique for name, IPN and revision") raise ValidationError({ "name": msg, "IPN": msg, "revision": msg, }) except Part.DoesNotExist: pass def clean(self): """ Perform cleaning operations for the Part model """ if self.is_template and self.variant_of is not None: raise ValidationError({ 'is_template': _("Part cannot be a template part if it is a variant of another part" ), 'variant_of': _("Part cannot be a variant of another part if it is already a template" ), }) name = models.CharField(max_length=100, blank=False, help_text=_('Part name'), validators=[validators.validate_part_name]) is_template = models.BooleanField( default=False, help_text=_('Is this part a template part?')) variant_of = models.ForeignKey( 'part.Part', related_name='variants', null=True, blank=True, limit_choices_to={ 'is_template': True, 'active': True, }, on_delete=models.SET_NULL, help_text=_('Is this part a variant of another part?')) description = models.CharField(max_length=250, blank=False, help_text=_('Part description')) keywords = models.CharField( max_length=250, blank=True, help_text=_('Part keywords to improve visibility in search results')) category = TreeForeignKey(PartCategory, related_name='parts', null=True, blank=True, on_delete=models.DO_NOTHING, help_text=_('Part category')) IPN = models.CharField(max_length=100, blank=True, help_text=_('Internal Part Number')) revision = models.CharField(max_length=100, blank=True, help_text=_('Part revision or version number')) URL = InvenTreeURLField(blank=True, help_text=_('Link to extenal URL')) image = models.ImageField(upload_to=rename_part_image, max_length=255, null=True, blank=True) default_location = TreeForeignKey( 'stock.StockLocation', on_delete=models.SET_NULL, blank=True, null=True, help_text=_('Where is this item normally stored?'), related_name='default_parts') def get_default_location(self): """ Get the default location for a Part (may be None). If the Part does not specify a default location, look at the Category this part is in. The PartCategory object may also specify a default stock location """ if self.default_location: return self.default_location elif self.category: # Traverse up the category tree until we find a default location cats = self.category.get_ancestors(ascending=True, include_self=True) for cat in cats: if cat.default_location: return cat.default_location # Default case - no default category found return None def get_default_supplier(self): """ Get the default supplier part for this part (may be None). - If the part specifies a default_supplier, return that - If there is only one supplier part available, return that - Else, return None """ if self.default_supplier: return self.default_supplier if self.supplier_count == 1: return self.supplier_parts.first() # Default to None if there are multiple suppliers to choose from return None default_supplier = models.ForeignKey(SupplierPart, on_delete=models.SET_NULL, blank=True, null=True, help_text=_('Default supplier part'), related_name='default_parts') minimum_stock = models.PositiveIntegerField( default=0, validators=[MinValueValidator(0)], help_text=_('Minimum allowed stock level')) units = models.CharField(max_length=20, default="", blank=True, help_text=_('Stock keeping units for this part')) assembly = models.BooleanField( default=False, verbose_name='Assembly', help_text=_('Can this part be built from other parts?')) component = models.BooleanField( default=True, verbose_name='Component', help_text=_('Can this part be used to build other parts?')) trackable = models.BooleanField( default=False, help_text=_('Does this part have tracking for unique items?')) purchaseable = models.BooleanField( default=True, help_text=_('Can this part be purchased from external suppliers?')) salable = models.BooleanField( default=False, help_text=_("Can this part be sold to customers?")) active = models.BooleanField(default=True, help_text=_('Is this part active?')) virtual = models.BooleanField( default=False, help_text=_( 'Is this a virtual part, such as a software product or license?')) notes = models.TextField(blank=True) bom_checksum = models.CharField(max_length=128, blank=True, help_text=_('Stored BOM checksum')) bom_checked_by = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True, related_name='boms_checked') bom_checked_date = models.DateField(blank=True, null=True) def format_barcode(self): """ Return a JSON string for formatting a barcode for this Part object """ return helpers.MakeBarcode( "Part", self.id, reverse('api-part-detail', kwargs={'pk': self.id}), { 'name': self.name, }) @property def category_path(self): if self.category: return self.category.pathstring return '' @property def available_stock(self): """ Return the total available stock. - This subtracts stock which is already allocated to builds """ total = self.total_stock total -= self.allocation_count return max(total, 0) @property def quantity_to_order(self): """ Return the quantity needing to be ordered for this part. """ required = -1 * self.net_stock return max(required, 0) @property def net_stock(self): """ Return the 'net' stock. It takes into account: - Stock on hand (total_stock) - Stock on order (on_order) - Stock allocated (allocation_count) This number (unlike 'available_stock') can be negative. """ return self.total_stock - self.allocation_count + self.on_order def isStarredBy(self, user): """ Return True if this part has been starred by a particular user """ try: PartStar.objects.get(part=self, user=user) return True except PartStar.DoesNotExist: return False def need_to_restock(self): """ Return True if this part needs to be restocked (either by purchasing or building). If the allocated_stock exceeds the total_stock, then we need to restock. """ return (self.total_stock + self.on_order - self.allocation_count) < self.minimum_stock @property def can_build(self): """ Return the number of units that can be build with available stock """ # If this part does NOT have a BOM, result is simply the currently available stock if not self.has_bom: return 0 total = None # Calculate the minimum number of parts that can be built using each sub-part for item in self.bom_items.all().prefetch_related( 'sub_part__stock_items'): stock = item.sub_part.available_stock n = int(stock / item.quantity) if total is None or n < total: total = n return max(total, 0) @property def active_builds(self): """ Return a list of outstanding builds. Builds marked as 'complete' or 'cancelled' are ignored """ return self.builds.filter(status__in=BuildStatus.ACTIVE_CODES) @property def inactive_builds(self): """ Return a list of inactive builds """ return self.builds.exclude(status__in=BuildStatus.ACTIVE_CODES) @property def quantity_being_built(self): """ Return the current number of parts currently being built """ return sum([b.quantity for b in self.active_builds]) @property def build_allocation(self): """ Return list of builds to which this part is allocated """ builds = [] for item in self.used_in.all().prefetch_related('part__builds'): active = item.part.active_builds for build in active: b = {} b['build'] = build b['quantity'] = item.quantity * build.quantity builds.append(b) prefetch_related_objects(builds, 'build_items') return builds @property def allocated_build_count(self): """ Return the total number of this part that are allocated for builds """ return sum([a['quantity'] for a in self.build_allocation]) @property def allocation_count(self): """ Return true if any of this part is allocated: - To another build - To a customer order """ return sum([ self.allocated_build_count, ]) @property def stock_entries(self): """ Return all 'in stock' items. To be in stock: - customer is None - belongs_to is None """ return self.stock_items.filter(customer=None, belongs_to=None) @property def total_stock(self): """ Return the total stock quantity for this part. Part may be stored in multiple locations """ if self.is_template: total = sum( [variant.total_stock for variant in self.variants.all()]) else: total = self.stock_entries.filter( status__in=StockStatus.AVAILABLE_CODES).aggregate( total=Sum('quantity'))['total'] if total: return total else: return 0 @property def has_bom(self): return self.bom_count > 0 @property def bom_count(self): """ Return the number of items contained in the BOM for this part """ return self.bom_items.count() @property def used_in_count(self): """ Return the number of part BOMs that this part appears in """ return self.used_in.count() def get_bom_hash(self): """ Return a checksum hash for the BOM for this part. Used to determine if the BOM has changed (and needs to be signed off!) The hash is calculated by hashing each line item in the BOM. returns a string representation of a hash object which can be compared with a stored value """ hash = hashlib.md5(str(self.id).encode()) for item in self.bom_items.all().prefetch_related('sub_part'): hash.update(str(item.get_item_hash()).encode()) return str(hash.digest()) @property def is_bom_valid(self): """ Check if the BOM is 'valid' - if the calculated checksum matches the stored value """ return self.get_bom_hash() == self.bom_checksum @transaction.atomic def validate_bom(self, user): """ Validate the BOM (mark the BOM as validated by the given User. - Calculates and stores the hash for the BOM - Saves the current date and the checking user """ # Validate each line item too for item in self.bom_items.all(): item.validate_hash() self.bom_checksum = self.get_bom_hash() self.bom_checked_by = user self.bom_checked_date = datetime.now().date() self.save() @transaction.atomic def clear_bom(self): """ Clear the BOM items for the part (delete all BOM lines). """ self.bom_items.all().delete() def required_parts(self): """ Return a list of parts required to make this part (list of BOM items) """ parts = [] for bom in self.bom_items.all().select_related('sub_part'): parts.append(bom.sub_part) return parts def get_allowed_bom_items(self): """ Return a list of parts which can be added to a BOM for this part. - Exclude parts which are not 'component' parts - Exclude parts which this part is in the BOM for """ parts = Part.objects.filter(component=True).exclude(id=self.id) parts = parts.exclude(id__in=[part.id for part in self.used_in.all()]) return parts @property def supplier_count(self): """ Return the number of supplier parts available for this part """ return self.supplier_parts.count() @property def has_pricing_info(self): """ Return true if there is pricing information for this part """ return self.get_price_range() is not None @property def has_complete_bom_pricing(self): """ Return true if there is pricing information for each item in the BOM. """ for item in self.bom_items.all().select_related('sub_part'): if not item.sub_part.has_pricing_info: return False return True def get_price_info(self, quantity=1, buy=True, bom=True): """ Return a simplified pricing string for this part Args: quantity: Number of units to calculate price for buy: Include supplier pricing (default = True) bom: Include BOM pricing (default = True) """ price_range = self.get_price_range(quantity, buy, bom) if price_range is None: return None min_price, max_price = price_range if min_price == max_price: return min_price return "{a} - {b}".format(a=min_price, b=max_price) def get_supplier_price_range(self, quantity=1): min_price = None max_price = None for supplier in self.supplier_parts.all(): price = supplier.get_price(quantity) if price is None: continue if min_price is None or price < min_price: min_price = price if max_price is None or price > max_price: max_price = price if min_price is None or max_price is None: return None return (min_price, max_price) def get_bom_price_range(self, quantity=1): """ Return the price range of the BOM for this part. Adds the minimum price for all components in the BOM. Note: If the BOM contains items without pricing information, these items cannot be included in the BOM! """ min_price = None max_price = None for item in self.bom_items.all().select_related('sub_part'): prices = item.sub_part.get_price_range(quantity * item.quantity) if prices is None: continue low, high = prices if min_price is None: min_price = 0 if max_price is None: max_price = 0 min_price += low max_price += high if min_price is None or max_price is None: return None return (min_price, max_price) def get_price_range(self, quantity=1, buy=True, bom=True): """ Return the price range for this part. This price can be either: - Supplier price (if purchased from suppliers) - BOM price (if built from other parts) Returns: Minimum of the supplier price or BOM price. If no pricing available, returns None """ buy_price_range = self.get_supplier_price_range( quantity) if buy else None bom_price_range = self.get_bom_price_range(quantity) if bom else None if buy_price_range is None: return bom_price_range elif bom_price_range is None: return buy_price_range else: return (min(buy_price_range[0], bom_price_range[0]), max(buy_price_range[1], bom_price_range[1])) def deepCopy(self, other, **kwargs): """ Duplicates non-field data from another part. Does not alter the normal fields of this part, but can be used to copy other data linked by ForeignKey refernce. Keyword Args: image: If True, copies Part image (default = True) bom: If True, copies BOM data (default = False) """ # Copy the part image if kwargs.get('image', True): if other.image: image_file = ContentFile(other.image.read()) image_file.name = rename_part_image(self, other.image.url) self.image = image_file # Copy the BOM data if kwargs.get('bom', False): for item in other.bom_items.all(): # Point the item to THIS part. # Set the pk to None so a new entry is created. item.part = self item.pk = None item.save() # Copy the fields that aren't available in the duplicate form self.salable = other.salable self.assembly = other.assembly self.component = other.component self.purchaseable = other.purchaseable self.trackable = other.trackable self.virtual = other.virtual self.save() @property def attachment_count(self): """ Count the number of attachments for this part. If the part is a variant of a template part, include the number of attachments for the template part. """ n = self.attachments.count() if self.variant_of: n += self.variant_of.attachments.count() return n def purchase_orders(self): """ Return a list of purchase orders which reference this part """ orders = [] for part in self.supplier_parts.all().prefetch_related( 'purchase_order_line_items'): for order in part.purchase_orders(): if order not in orders: orders.append(order) return orders def open_purchase_orders(self): """ Return a list of open purchase orders against this part """ return [ order for order in self.purchase_orders() if order.status in OrderStatus.OPEN ] def closed_purchase_orders(self): """ Return a list of closed purchase orders against this part """ return [ order for order in self.purchase_orders() if order.status not in OrderStatus.OPEN ] @property def on_order(self): """ Return the total number of items on order for this part. """ return sum([ part.on_order() for part in self.supplier_parts.all().prefetch_related( 'purchase_order_line_items') ]) def get_parameters(self): """ Return all parameters for this part, ordered by name """ return self.parameters.order_by('template__name')
class productoTerminado(models.Model): id=models.AutoField(primary_key=True) orden=models.ForeignKey(Orden, null=True, blank=True, on_delete=models.CASCADE) cantidadProducto=models.IntegerField() costoUnitarioProducto=models.DecimalField('Costo Unitario', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)]) costoTotalProducto=models.DecimalField('haber', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)]) porcentajeGanancia=models.DecimalField('haber', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)]) precioVenta=models.DecimalField('haber', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)])
class Invoice(core_models.UuidMixin, models.Model): """ Invoice describes billing information about purchased packages for customers on a monthly basis """ class Permissions(object): customer_path = 'customer' class Meta(object): unique_together = ('customer', 'month', 'year') class States(object): PENDING = 'pending' CREATED = 'created' PAID = 'paid' CANCELED = 'canceled' CHOICES = ((PENDING, _('Pending')), (CREATED, _('Created')), (PAID, _('Paid')), (CANCELED, _('Canceled'))) month = models.PositiveSmallIntegerField( default=utils.get_current_month, validators=[MinValueValidator(1), MaxValueValidator(12)]) year = models.PositiveSmallIntegerField(default=utils.get_current_year) state = models.CharField(max_length=30, choices=States.CHOICES, default=States.PENDING) customer = models.ForeignKey(structure_models.Customer, verbose_name=_('organization'), related_name='+', on_delete=models.CASCADE) current_cost = models.DecimalField( default=0, max_digits=10, decimal_places=2, help_text=_('Cached value for current cost.'), editable=False) tax_percent = models.DecimalField( default=0, max_digits=4, decimal_places=2, validators=[MinValueValidator(0), MaxValueValidator(100)]) invoice_date = models.DateField( null=True, blank=True, help_text=_('Date then invoice moved from state pending to created.')) tracker = FieldTracker() def update_current_cost(self): self.current_cost = self.total_current self.save(update_fields=['current_cost']) @property def tax(self): return self.price * self.tax_percent / 100 @property def total(self): return self.price + self.tax @property def price(self): return sum((item.price for item in self.items)) @property def tax_current(self): return self.price_current * self.tax_percent / 100 @property def total_current(self): return self.price_current + self.tax_current @property def price_current(self): return sum((item.price_current for item in self.items)) @property def items(self): return itertools.chain(self.openstack_items.all(), self.offering_items.all(), self.generic_items.all()) @property def due_date(self): if self.invoice_date: return self.invoice_date + datetime.timedelta( days=settings.WALDUR_INVOICES['PAYMENT_INTERVAL']) @property def number(self): return 100000 + self.id def set_created(self): """ Performs following actions: - Freeze all invoice items - Change state from pending to billed """ if self.state != self.States.PENDING: raise IncorrectStateException( _('Invoice must be in pending state.')) self.state = self.States.CREATED self.invoice_date = timezone.now().date() self.save(update_fields=['state', 'invoice_date']) def freeze(self): for item in self.items: item.freeze() def register_offering(self, offering, start=None): if start is None: start = timezone.now() end = core_utils.month_end(start) OfferingItem.objects.create( offering=offering, unit_price=offering.unit_price, unit=offering.unit, invoice=self, start=start, end=end, ) def __str__(self): return '%s | %s-%s' % (self.customer, self.year, self.month)
class detalleTransaccion(models.Model): id_detalle = models.AutoField(primary_key = True) debe = models.DecimalField('debe', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)]) haber = models.DecimalField('haber', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)]) id_Transaccion = models.ForeignKey(Transaccion, null=True, blank=True,on_delete= models.CASCADE) id_cuenta = models.ForeignKey(Cuenta, null=True, blank=True, on_delete=models.CASCADE) def __str__(self): return '{}{}'.format(self.id_detalle)
(validate_comma_separated_integer_list, '1, 2, 3', ValidationError), (validate_comma_separated_integer_list, ',', ValidationError), (validate_comma_separated_integer_list, '1,2,3,', ValidationError), (validate_comma_separated_integer_list, '1,2,', ValidationError), (validate_comma_separated_integer_list, ',1', ValidationError), (validate_comma_separated_integer_list, '1,,2', ValidationError), (int_list_validator(sep='.'), '1.2.3', None), (int_list_validator(sep='.'), '1,2,3', ValidationError), (MaxValueValidator(10), 10, None), (MaxValueValidator(10), -10, None), (MaxValueValidator(10), 0, None), (MaxValueValidator(NOW), NOW, None), (MaxValueValidator(NOW), NOW - timedelta(days=1), None), (MaxValueValidator(0), 1, ValidationError), (MaxValueValidator(NOW), NOW + timedelta(days=1), ValidationError), (MinValueValidator(-10), -10, None), (MinValueValidator(-10), 10, None), (MinValueValidator(-10), 0, None), (MinValueValidator(NOW), NOW, None), (MinValueValidator(NOW), NOW + timedelta(days=1), None), (MinValueValidator(0), -1, ValidationError), (MinValueValidator(NOW), NOW - timedelta(days=1), ValidationError), (MaxLengthValidator(10), '', None), (MaxLengthValidator(10), 10 * 'x', None), (MaxLengthValidator(10), 15 * 'x', ValidationError), (MinLengthValidator(10), 15 * 'x', None), (MinLengthValidator(10), 10 * 'x', None), (MinLengthValidator(10), '', ValidationError), (URLValidator(EXTENDED_SCHEMES), 'file://localhost/path', None), (URLValidator(EXTENDED_SCHEMES), 'git://example.com/', None), (URLValidator(EXTENDED_SCHEMES), 'git://-invalid.com', ValidationError),
class estadoResulta(models.Model): id=models.AutoField(primary_key=True) debe =models.DecimalField('debe', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)]) haber= models.DecimalField('haber', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)]) utilidades=models.DecimalField('Utilildad', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)]) utilidadNeta=models.DecimalField('Utilildad', max_digits=50, decimal_places=2, blank=False, null=True, validators=[MinValueValidator(0)])
class Settings(Model): stg_guicertificate = models.ForeignKey( "Certificate", verbose_name=_("Certificate for HTTPS"), limit_choices_to={ 'cert_type__in': [CERT_TYPE_EXISTING, CERT_TYPE_INTERNAL] }, on_delete=models.SET_NULL, blank=True, null=True) stg_guiaddress = ListField(blank=True, default=['0.0.0.0'], verbose_name=_("WebGUI IPv4 Address")) stg_guiv6address = ListField(blank=True, default=['::'], verbose_name=_("WebGUI IPv6 Address")) stg_guiport = models.IntegerField( verbose_name=_("WebGUI HTTP Port"), validators=[MinValueValidator(1), MaxValueValidator(65535)], default=80, ) stg_guihttpsport = models.IntegerField( verbose_name=_("WebGUI HTTPS Port"), validators=[MinValueValidator(1), MaxValueValidator(65535)], default=443, ) stg_guihttpsredirect = models.BooleanField( verbose_name=_('WebGUI HTTP -> HTTPS Redirect'), default=False, help_text=_('Redirect all incoming HTTP requests to HTTPS'), ) stg_language = models.CharField(max_length=120, choices=settings.LANGUAGES, default="en", verbose_name=_("Language")) stg_kbdmap = models.CharField( max_length=120, choices=choices.KBDMAP_CHOICES(), verbose_name=_("Console Keyboard Map"), blank=True, ) stg_timezone = models.CharField(max_length=120, choices=choices.TimeZoneChoices(), default="America/Los_Angeles", verbose_name=_("Timezone")) stg_sysloglevel = models.CharField( max_length=120, choices=choices.SYS_LOG_LEVEL, default="f_info", verbose_name=_("Syslog level"), help_text=_("Specifies which messages will be logged by " "server. INFO and VERBOSE log transactions that " "server performs on behalf of the client. " "f_is_debug specify higher levels of debugging output. " "The default is f_info."), ) stg_syslogserver = models.CharField( default='', blank=True, max_length=120, verbose_name=_("Syslog server"), help_text=_( "Specifies the server and port syslog messages " "will be sent to. The accepted format is hostname:port " "or ip:port, if :port is not specified it will default to " "port 514 (this field currently only takes IPv4 addresses)"), ) stg_wizardshown = models.BooleanField( editable=False, default=False, ) stg_pwenc_check = models.CharField( max_length=100, editable=False, ) class Meta: verbose_name = _("General")