from django.db import models from django.utils import timezone from django_cryptography.fields import encrypt from config.extras import BREWFATHER_APP_ROOT from django.conf import settings import logging logger = logging.getLogger('django') class CustomModel(models.Model): """ Custom model class with default fields to use. """ created_date = models.DateTimeField(default=timezone.now) class Meta: abstract = True class UserProfile(CustomModel): user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) brewfather_api_user = encrypt(models.TextField(max_length=128)) brewfather_api_key = encrypt(models.TextField(max_length=128)) def __str__(self): return self.user.username class Batch(CustomModel): brewfather_id = models.CharField(max_length=50) brewfather_num = models.IntegerField(default=1) brewfather_name = models.CharField(max_length=500, default='name') recipe = models.OneToOneField('BatchRecipe', on_delete=models.CASCADE, default=1) @property def brewfather_url(self): return '{}/tabs/batches/batch/{}'.format(BREWFATHER_APP_ROOT, self.brewfather_id) def __str__(self): # Return a string that represents the instance return 'BF #{num}: {name}'.format(name=self.brewfather_name, num=self.brewfather_num) #----------------------------------------------------------------------- # Recipe Stuff #----------------------------------------------------------------------- class Unit(CustomModel): unit_types = { 'WT': 'Weight', 'VL': 'Volume', } """ Recipe to be stored with a batch.""" name = models.CharField(max_length=50) unit_type = models.CharField(max_length=3, choices=unit_types, default='WT') class Supplier(CustomModel): name = models.CharField(max_length=50) class CustomIngredient(CustomModel): """ Custom model class with default fields to use. """ created_date = models.DateTimeField(default=timezone.now) name = models.CharField(max_length=50) units = models.ForeignKey(Unit, on_delete=models.PROTECT) unit_cost = models.DecimalField(max_digits=6, decimal_places=2, null=True, blank=True) supplier = models.ForeignKey(Supplier, on_delete=models.PROTECT, null=True, blank=True) notes = models.TextField(max_length=500, blank=True, null=True) user_notes = models.TextField(max_length=500, blank=True, null=True) class Meta: abstract = True class BatchRecipe(CustomModel): """ Recipe to be stored with a batch.""" name = models.CharField(max_length=50) batch_recipe = models.BooleanField(null=True) recipe_json = models.TextField(null=True, blank=True) mash = models.ForeignKey('Mash' , on_delete=models.PROTECT, null=True, blank=True) efficiency = models.DecimalField(max_digits=6, decimal_places=4, null=True, blank=True) def __str__(self): return self.name class Fermentable(CustomIngredient): categories = { 1: 'Base', 2: 'Wheat/Oat', 3: 'Crystal', 4: 'Roasted', 5: 'Acid', } types = { 1: 'Grain', 2: 'Adjunct', } grain_category = models.IntegerField(choices=categories, default=1) fermentable_type = models.IntegerField(choices=types, default=1) diastatic_power = models.DecimalField(max_digits=6, decimal_places=4, null=True, blank=True) potential = models.DecimalField(max_digits=6, decimal_places=4) protein = models.DecimalField(max_digits=6, decimal_places=4, null=True, blank=True) attenuation = models.DecimalField(max_digits=6, decimal_places=4, null=True, blank=True) lovibond = models.DecimalField(max_digits=6, decimal_places=4, null=True, blank=True) max_in_batch = models.DecimalField(max_digits=6, decimal_places=4, null=True, blank=True) moisture = models.DecimalField(max_digits=6, decimal_places=4, null=True, blank=True) non_fermentable = models.BooleanField(null=True, blank=True) ibu_per_unit = models.DecimalField(max_digits=6, decimal_places=4, default=0) def __str__(self): return self.name class RecipeFermentable(CustomModel): recipe = models.ForeignKey(BatchRecipe, on_delete=models.CASCADE) fermentable = models.ForeignKey(Fermentable, on_delete=models.CASCADE) quantity = models.DecimalField(max_digits=6, decimal_places=4) class Hop(CustomIngredient): uses = { 1: 'Bittering', 2: 'Aroma', 3: 'Both', } types = { 1: 'Pellet', 2: 'Leaf', 3: 'Cryo', 4: 'CO2 Extract', } ibu = models.DecimalField(max_digits=6, decimal_places=4, default=0) use = models.IntegerField(choices=uses, default=1) hop_type = models.IntegerField(choices=types, default=1) alpha = models.DecimalField(max_digits=6, decimal_places=2, default=0) def __str__(self): return self.name class RecipeHop(CustomModel): recipe = models.ForeignKey(BatchRecipe, on_delete=models.CASCADE) hop = models.ForeignKey(Hop, on_delete=models.CASCADE) quantity = models.DecimalField(max_digits=6, decimal_places=4) class Misc(CustomIngredient): uses = { 1: 'Mash', 2: 'Sparge', 3: 'Boil', 4: 'Flamout', 5: 'Primary', 6: 'Secondary', 7: 'Cold Crash', 8: 'Bottling', } types = { 1: 'Spice', 2: 'Fining', 3: 'Water Agent', 4: 'Herb', 5: 'Flavor', 6: 'Other', } use = models.IntegerField(choices=uses, default=1) misc_type = models.IntegerField(choices=types, default=1) water_adjustment = models.BooleanField(null=True, blank=True) def __str__(self): return self.name class RecipeMisc(CustomModel): recipe = models.ForeignKey(BatchRecipe, on_delete=models.CASCADE) misc = models.ForeignKey(Misc, on_delete=models.CASCADE) quantity = models.DecimalField(max_digits=6, decimal_places=4) class RecipeYeast(CustomModel): recipe = models.ForeignKey(BatchRecipe, on_delete=models.CASCADE) yeast = models.ForeignKey('yeast.Strain', on_delete=models.CASCADE) class Mash(CustomModel): name = models.CharField(max_length=50) def __str__(self): return self.name class MashStep(CustomModel): step_types = { 1: 'infusion', 2: 'temperature', 3: 'decoction', } name = models.CharField(max_length=50) step_temp = models.DecimalField(max_digits=6, decimal_places=2) ramp_time = models.DecimalField(max_digits=6, decimal_places=2) step_time = models.DecimalField(max_digits=6, decimal_places=2) step_type = models.IntegerField(choices=step_types, default=1) parent_mash = models.ForeignKey(Mash, on_delete=models.CASCADE) def __str__(self): return self.name