class Category(BaseScopedNameMixin, db.Model): """ Expense categories. """ __tablename__ = 'category' workspace_id = db.Column(db.Integer, db.ForeignKey('workspace.id'), nullable=False) workspace = db.relation(Workspace, backref=db.backref('categories', cascade='all, delete-orphan')) parent = db.synonym('workspace') __table_args__ = (db.UniqueConstraint('name', 'workspace_id'), )
class Budget(BaseScopedNameMixin, db.Model): """ Budget to which expense reports can be assigned. """ __tablename__ = 'budget' workspace_id = db.Column(db.Integer, db.ForeignKey('workspace.id'), nullable=False) workspace = db.relation(Workspace, backref=db.backref('budgets', cascade='all, delete-orphan')) parent = db.synonym('workspace') #: Description of the budget. HTML field. description = db.Column(db.Text, nullable=False, default='') __table_args__ = (db.UniqueConstraint('name', 'workspace_id'), )
class Payment(BaseMixin, db.Model): __tablename__ = 'payment' workspace_id = db.Column(db.Integer, db.ForeignKey('workspace.id'), nullable=False) workspace = db.relation(Workspace, backref=db.backref('payments', cascade='all, delete-orphan')) #: User who made the payment user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) user = db.relationship(User, primaryjoin=user_id == User.id, backref=db.backref('payouts', cascade='all, delete-orphan')) #: User-reported date when payment was made date = db.Column(db.Date, nullable=False) #: Currency for payment currency = db.Column(db.Unicode(3), nullable=False, default=u'INR') #: Amount of payment amount = db.Column(db.Numeric(10, 2), default=0, nullable=False)
class ExpenseReport(BaseScopedIdNameMixin, db.Model): """ Collection of expenses. """ __tablename__ = 'expense_report' workspace_id = db.Column(db.Integer, db.ForeignKey('workspace.id'), nullable=False) workspace = db.relation(Workspace, backref=db.backref('reports', cascade='all, delete-orphan')) parent = db.synonym('workspace') #: User who submitted the report user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) user = db.relationship(User, primaryjoin=user_id == User.id, backref=db.backref('expensereports', cascade='all, delete-orphan')) #: Date of report submission datetime = db.Column(db.DateTime, default=datetime.utcnow, nullable=False) #: Budget to which this report is assigned budget_id = db.Column(db.Integer, db.ForeignKey('budget.id'), nullable=True) budget = db.relationship(Budget, primaryjoin=budget_id == Budget.id) #: Currency for expenses in this report currency = db.Column(db.Unicode(3), nullable=False, default='INR') #: Optional description of expenses description = db.Column(db.Text, nullable=False, default='') #: Total value in the report's currency total_value = db.Column(db.Numeric(10, 2), nullable=False, default=Decimal('0.0')) #: Total value in the organization's preferred currency total_converted = db.Column(db.Numeric(10, 2), nullable=False, default=Decimal('0.0')) #: Reviewer reviewer_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True) reviewer = db.relationship( User, primaryjoin=reviewer_id == User.id, backref=db.backref('reviewed_reports', cascade='all')) # No delete-orphan #: Reviewer notes notes = db.Column(db.Text, nullable=False, default='') # HTML notes #: Status status = db.Column(db.Integer, nullable=False, default=REPORT_STATUS.DRAFT) __table_args__ = (db.UniqueConstraint('url_id', 'workspace_id'), ) def update_total(self): self.total_value = sum([e.amount for e in self.expenses]) # self.total_value = db.session.query( # db.func.sum(Expense.amount).label('sum')).filter_by( # report_id = self.id).first().sum def update_sequence_numbers(self): # self.expenses is ordered by seq. See the relation defined at Expense.report for i, expense in enumerate(self.expenses): # Only edit the object if its sequence position has changed if expense.seq != i + 1: expense.seq = i + 1 def permissions(self, user, inherited=None): perms = super(ExpenseReport, self).permissions(user, inherited) workflow = self.workflow() perms.discard('view') perms.discard('edit') perms.discard('delete') perms.discard('new-expense') if 'review' in perms or 'admin' in perms: if not workflow.draft(): perms.add('view') if self.user == user: perms.add('owner') perms.add('view') if workflow.draft(): perms.add('delete') if workflow.editable(): perms.add('edit') perms.add('new-expense') if workflow.review(): perms.add('withdraw') return perms