def save(self, *args, **kwargs): if not self.slug: self.slug = generate_slug(Period) if 'update_fields' in kwargs and 'slug' not in kwargs[ 'update_fields']: kwargs['update_fields'] = list( chain(kwargs['update_fields'], ['slug'])) if not self.version_hash: self.version_hash = get_version_hash() if 'update_fields' in kwargs and 'version_hash' not in kwargs[ 'update_fields']: kwargs['update_fields'] = list( chain(kwargs['update_fields'], ['version_hash'])) if self.start >= self.end: raise ValidationError("start cannot be after end") Q_date_conflict = get_date_conflict_Q(self.start, self.end) conflicting_periods = Period.objects.filter( Q(company=self.company) & Q_date_conflict) if self.pk: conflicting_periods = conflicting_periods.exclude(pk=self.pk) if conflicting_periods.exists(): raise ValidationError( f"start and end date overlaps with another period: {conflicting_periods.values_list('pk', flat=True)}" ) return super().save(*args, **kwargs)
def save(self, *args, **kwargs): if not self.slug: self.slug = generate_slug(Company) if 'update_fields' in kwargs and 'slug' not in kwargs['update_fields']: kwargs['update_fields'] = list(chain(kwargs['update_fields'], ['slug'])) return super().save(*args, **kwargs)
def save(self, *args, **kwargs): if not self.slug: self.slug = generate_slug(JournalEntry) if 'update_fields' in kwargs and 'slug' not in kwargs[ 'update_fields']: kwargs['update_fields'] = list( chain(kwargs['update_fields'], ['slug'])) if not self.display_id: self.display_id = get_next_journal_entry_display_id_for_company( self.period.company) if 'update_fields' in kwargs and 'display_id' not in kwargs[ 'update_fields']: kwargs['update_fields'] = list( chain(kwargs['update_fields'], ['display_id'])) if not (self.period.start <= self.date <= self.period.end): raise ValidationError("entry date must fall within period") for je_line in self.lines.all(): if je_line.account.user and je_line.account.user != self.period.user: raise ValidationError( "period user does not equal account user") return super().save(*args, **kwargs)
def save(self, *args, **kwargs): if not self.slug: self.slug = generate_slug(Account) if 'update_fields' in kwargs and 'slug' not in kwargs[ 'update_fields']: kwargs['update_fields'] = list( chain(kwargs['update_fields'], ['slug'])) if self.company and self.company.user != self.user: raise ValidationError("company user mismatch") if self.is_current is not None and self.type not in self.CURRENT_TYPES: raise ValidationError( "is_current cannot be assigned to this accoount type") if self.type in self.CURRENT_TYPES and self.is_current is None: raise ValidationError( "is_current cannot be None for this accoount type") if self.type in self.OPERATING_TYPES and self.is_operating is None: raise ValidationError( "is_operating cannot be None for this accoount type") if not self.type in self.OPERATING_TYPES and not self.is_operating is None: raise ValidationError( "is_operating must be None for this accoount type") # Validate tag is valid if self.tag == self.TAG_COST_OF_GOODS: if not self.type in [self.TYPE_REVENUE, self.TYPE_EXPENSE]: raise ValidationError( f"Accounts with tag {self.ACCOUNT_TAG_NAME_DICT[self.tag]} must be an expense account." ) if self.type == self.TYPE_REVENUE and not self.is_contra: raise ValidationError( f"Revenue account must be marked as a contra account to hold a Cost of Goods sold tag." ) if self.type == self.TYPE_EXPENSE and self.is_contra: raise ValidationError( f"Expense accounts cannot be marked as a contra account to hold a Cost of Goods sold tag." ) if not self.is_operating: raise ValidationError( f"Accounts with the tag Cost of Goods Sold must be operating accounts." ) if self.tag == self.TAG_RETAINED_EARNINGS: if self.type != self.TYPE_EQUITY or self.is_contra: raise ValidationError( f"Accounts with tag {self.ACCOUNT_TAG_NAME_DICT[self.tag]} must be a non-contra equity account." ) if self.tag == self.TAG_CASH: if self.type != self.TYPE_ASSET or self.is_contra or not self.is_current: raise ValidationError( f"Accounts with tag {self.ACCOUNT_TAG_NAME_DICT[self.tag]} must be a non-contra current asset account." ) return super().save(*args, **kwargs)
def save(self, *args, **kwargs): if not self.slug: self.slug = generate_slug(JournalEntryLine) if 'update_fields' in kwargs and 'slug' not in kwargs[ 'update_fields']: kwargs['update_fields'] = list( chain(kwargs['update_fields'], ['slug'])) if self.account.user and self.account.user != self.journal_entry.period.user: raise ValidationError("period user does not equal account user") return super().save(*args, **kwargs)
def import_company_data(data: dict, user) -> Company: # TODO: use bulk_create # Create a new company company_name = data['company']['name'] new_company_name = None if Company.objects.filter(user=user, name=company_name).exists(): while True: slug_suffix = generate_slug(None) new_company_name = company_name[:Account.name.field.max_length - (len(slug_suffix) + 1)] + slug_suffix if not Company.objects.filter(user=user, name=new_company_name).exists(): break else: new_company_name = company_name new_user_history = data['meta']['user_history'] + [ { 'user_hash': user.userprofile.slug, 'timestamp': timezone.now().strftime("%s"), 'event': 'import', } ] new_company = Company.objects.create( user=user, name=new_company_name, user_finger_print_str=json.dumps(new_user_history)) data['company']['new_id'] = new_company.id # create new accounts account_map = {} for ix, account_data in enumerate(data['accounts']): new_account = Account.objects.create( company=new_company, user=user, name=account_data['name'], number=account_data['number'], type=account_data['type'], tag=account_data['tag'], is_contra=account_data['is_contra'], is_current=account_data['is_current'], is_operating=account_data['is_operating']) account_map[account_data['id']] = new_account # Create new periods period_map = {} for ix, period_data in enumerate(data['periods']): new_period = Period.objects.create(start=period_data['start_str'], end=period_data['end_str'], company=new_company) period_map[period_data['id']] = new_period # Create new Journal Entries journal_entry_id_map = {} journal_entry_slug_map = {} for ix, journal_entry_data in enumerate(data['journal_entries']): new_journal_entry = JournalEntry.objects.create( period=period_map[journal_entry_data['period_id']], date=journal_entry_data['date_str'], memo=journal_entry_data['memo'], is_adjusting_entry=journal_entry_data['is_adjusting_entry'], is_closing_entry=journal_entry_data['is_closing_entry'], ) journal_entry_id_map[journal_entry_data['id']] = new_journal_entry journal_entry_slug_map[journal_entry_data['slug']] = new_journal_entry # Create journal entry lines new_journal_entry_lines = [] jel_slugs = list( generate_slugs_batch(JournalEntryLine, len(data['journal_entry_lines']))) for ix, jel_data in enumerate(data['journal_entry_lines']): new_journal_entry_lines.append( JournalEntryLine( slug=jel_slugs[ix], journal_entry=journal_entry_id_map[ jel_data['journal_entry_id']], account=account_map[jel_data['account_id']], type=jel_data['type'], amount=jel_data['amount'], )) JournalEntryLine.objects.bulk_create(new_journal_entry_lines) # Create cash flow worksheets for cfws in data['cash_flow_worksheets']: cfws_je_data = json.loads(cfws['data']) new_cfws_data = [] for cfws_je in cfws_je_data: new_je = journal_entry_slug_map[cfws_je['journal_entry']] new_cfws_data.append({ 'journal_entry': new_je.slug, 'operations': cfws_je['operations'], 'investments': cfws_je['investments'], 'finances': cfws_je['finances'], }) new_period = period_map[cfws['period_id']] reports_lib.create_cash_flow_worksheet(new_period, new_cfws_data) return new_company