Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
 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)
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
    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)
Ejemplo n.º 6
0
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