class Company(db.Model): __tablename__ = 'company' id = db.Column(u'id', db.BigInteger, primary_key=True, nullable=False) user_id = db.Column(u'user_id', db.BigInteger, db.ForeignKey('user.id'), nullable=False) logo_id = db.Column(u'logo_id', db.BigInteger, db.ForeignKey('logo.id'), nullable=False) company_type_id = db.Column(u'company_type_id', db.BigInteger, db.ForeignKey('company_type.id'), nullable=False) name = db.Column(u'name', db.Unicode(length=255)) address1 = db.Column(u'address1', db.Unicode(length=255)) address2 = db.Column(u'address2', db.Unicode(length=255)) town = db.Column(u'town', db.Unicode(length=100)) city = db.Column(u'city', db.Unicode(length=100)) county = db.Column(u'county', db.Unicode(length=255)) country = db.Column(u'country', db.Unicode(length=2)) post_code = db.Column(u'post_code', db.Unicode(length=20)) registration_number = db.Column(u'registration_number', db.Unicode(length=20)) created_at = db.Column(u'created_at', db.DateTime, nullable=False, default=get_current_time()) updated_at = db.Column(u'updated_at', db.DateTime, nullable=False, default=get_current_time()) # user user = db.relation('User', primaryjoin='Company.user_id==User.id', backref=db.backref('company', uselist=False)) # logo logo = db.relation('Logo', primaryjoin='Company.logo_id==Logo.id') # account type company_type = db.relation('CompanyType', backref=db.backref('companies', lazy='dynamic'))
class Subscription(db.Model): __tablename__ = 'subscription' id = db.Column(db.Integer(11), primary_key=True, nullable=False) user_id = db.Column(db.Integer(11), db.ForeignKey('user.id'), nullable=False) plan_id = db.Column(db.Integer(11), db.ForeignKey('plan.id'), nullable=False) active = db.Column(db.Boolean, nullable=False, default=False) start_date = db.Column(db.DateTime, nullable=True) end_date = db.Column(db.DateTime, nullable=True) stripe_data = db.Column(db.UnicodeText(4294967295), nullable=False, default=u'{}') updated_at = db.Column(db.DateTime, nullable=False, default=datetime.now) created_at = db.Column(db.DateTime, nullable=False, default=datetime.now, onupdate=datetime.now) # relations transactions = db.relation('Transaction', backref=db.backref('subscription', lazy='joined', uselist=False))
class Logo(db.Model): __tablename__ = 'logo' id = db.Column(u'id', db.BigInteger, primary_key=True, nullable=False) original_image_id = db.Column(u'original_image_id', db.BigInteger, db.ForeignKey('file.id'), nullable=False) thumbnail_image_id = db.Column(u'thumbnail_image_id', db.BigInteger, db.ForeignKey('file.id'), nullable=False) original = db.relation('File', primaryjoin='Logo.original_image_id==File.id', backref=db.backref('original', uselist=False)) thumbnail = db.relation('File', primaryjoin='Logo.thumbnail_image_id==File.id', backref=db.backref('thumbnail', uselist=False))
class CustomField(db.Model): __tablename__ = 'custom_field' id = db.Column(u'id', db.BigInteger, primary_key=True, nullable=False) user_id = db.Column(u'user_id', db.Integer, db.ForeignKey('user.id'), nullable=False) name = db.Column(u'name', db.Unicode(length=255)) value = db.Column(u'value', db.Unicode(length=255)) # user user = db.relation('User', backref=db.backref('custom_fields'))
class Payment(db.Model): __tablename__ = 'payment' id = db.Column(db.BigInteger, primary_key=True, nullable=False) invoice_id = db.Column(db.BigInteger, db.ForeignKey('invoice.id')) date = db.Column(db.DateTime, default=datetime.now, nullable=False) currency_code = db.Column(db.Unicode(3), nullable=False) method = db.Column(db.Unicode(50), nullable=False) description = db.Column(db.Unicode(255), nullable=True) amount = db.Column(db.Numeric(8, 2), default=0, nullable=False) created_at = db.Column(db.DateTime, default=datetime.now, nullable=False) #relation definitions invoice = db.relation('Invoice', primaryjoin='Payment.invoice_id==Invoice.id', backref=db.backref('payments', lazy='dyanmic'))
class Plan(db.Model): __tablename__ = 'plan' id = db.Column(db.Integer(11), primary_key=True, nullable=False) name = db.Column(db.Unicode(20)) gateway_uid = db.Column(db.Unicode(255)) description = db.Column(db.Unicode(255)) amount = db.Column(db.Numeric(8, 2), default=0) billing_interval = db.Column(db.Enum('daily', 'weekly', 'monthly', 'yearly'), default='monthly') created_at = db.Column(db.DateTime, nullable=False, default=datetime.now) # relationships subscriptions = db.relation('Subscription', backref=db.backref('plan', lazy='joined', uselist=False)) @property def interval_name(self): if self.billing_interval == 'monthly': return 'month'
class InvoiceItem(db.Model): __tablename__ = 'invoice_item' id = db.Column(u'id', db.BigInteger, primary_key=True, nullable=False) invoice_id = db.Column(u'invoice_id', db.BigInteger, db.ForeignKey('invoice.id')) type_id = db.Column(u'type_id', db.BigInteger, db.ForeignKey('invoice_item_type.id')) tax_rate_id = db.Column(u'tax_rate_id', db.BigInteger, db.ForeignKey('tax_rate.id')) description = db.Column(u'description', db.String) quantity = db.Column(u'quantity', db.Numeric(8, 2)) price = db.Column(u'price', db.Numeric(8, 2)) tax = db.Column(u'tax', db.Numeric(8, 2)) total = db.Column(u'total', db.Numeric(8, 2)) sort_order = db.Column(u'sort_order', db.Integer, default=0) #relation definitions invoice_item_type = db.relation( 'InvoiceItemType', primaryjoin='InvoiceItem.type_id==InvoiceItemType.id') invoice = db.relation('Invoice', primaryjoin='InvoiceItem.invoice_id==Invoice.id', backref=db.backref('invoice_items', lazy='dyanmic')) tax_rate = db.relation('TaxRate', primaryjoin='InvoiceItem.tax_rate_id==TaxRate.id') def should_render_field(self, name): """Returns True if the field should be rendered in the item list on the invoice""" no_render = { 'Comment': ['quantity', 'price', 'tax', 'total'], 'VAT': ['quantity'] } type_name = self.invoice_item_type.name if not type_name in no_render: return True if name in no_render[type_name]: return False return True def quantity_str(self): """Returns a more sanely formatted quantity string, taking into account the type of the item that we're rendering""" if self.invoice_item_type.name == 'Hour': mins = self.quantity * 60 hours = 0 while mins >= 60: mins -= 60 hours += 1 if mins == 0: return hours else: mins = int(round(mins)) mins = str(mins).zfill(2) return '%s:%s' % (hours, mins) return int(self.quantity) if math.fmod(self.quantity, 1) == 0 else self.quantity def update_totals(self): """Recalculate the tax and the totals for this invoice""" if self.tax_rate_id > 0: rate = 0 if self.id: rate = self.tax_rate.rate else: from nano.models import Invoice, TaxRate rate = TaxRate.query.get(self.tax_rate_id).rate self.tax = self.quantity * float(self.price) * float(rate) / 100 else: self.tax = 0 self.total = self.quantity * float(self.price) return self.tax, self.total def serialize(self): """Serialize the invoice structure so that it can be used for JSON""" d = model_to_dict(self) d['InvoiceItemType'] = self.invoice_item_type.serialize() if self.tax_rate: d['TaxRate'] = self.tax_rate.serialize() return d
class Invoice(db.Model): __tablename__ = 'invoice' DATE_FORMAT = '%a %b %d %Y' id = db.Column(u'id', db.Integer, primary_key=True, nullable=False) user_id = db.Column(u'user_id', db.Integer, db.ForeignKey('user.id')) contact_id = db.Column(u'contact_id', db.Integer, db.ForeignKey('contact.id')) payment_term_id = db.Column(u'payment_term_id', db.Integer, db.ForeignKey('payment_term.id')) status = db.Column(u'status', db.String(255)) reference = db.Column(u'reference', db.String(255)) po_reference = db.Column(u'po_reference', db.String(255)) currency_code = db.Column(u'currency_code', db.String(5)) date_issued = db.Column(u'date_issued', db.DateTime) due_date = db.Column(u'due_date', db.DateTime) written_off_date = db.Column(u'written_off_date', db.DateTime) sub_total = db.Column(u'sub_total', db.Numeric(8, 2)) tax = db.Column(u'tax', db.Numeric(8, 2)) total = db.Column(u'total', db.Numeric(8, 2)) payment_status = db.Column(u'payment_status', db.Unicode(10), default=u'unpaid') updated_at = db.Column(u'updated_at', db.DateTime, nullable=False, default=get_current_time()) created_at = db.Column(u'created_at', db.DateTime, nullable=False, default=get_current_time()) # relations user = db.relation('User', primaryjoin='Invoice.user_id==User.id', backref='invoices') contact = db.relation('Contact', primaryjoin='Invoice.contact_id==Contact.id', backref='invoices') payment_term = db.relation('PaymentTerm', primaryjoin='Invoice.payment_term_id==PaymentTerm.id') invoice_link = db.relation('InvoiceLink', backref=db.backref('invoice', uselist=False, lazy='joined')) gocardless_payments = db.relation('GoCardlessPayment', backref=db.backref('invoice', uselist=False, lazy='joined')) stripe_payments = db.relation('StripePayment', backref=db.backref('invoice', uselist=False, lazy='joined')) @classmethod def next_invoice_number(cls, user): """Next the next invoice number for the user""" cur_max = cls.query.filter_by(user_id=user.id).count() cur_max += 1 return str(cur_max) @property def due_date_nice(self): return self.due_date.strftime(self.DATE_FORMAT) @property def date_issued_nice(self): return self.date_issued.strftime(self.DATE_FORMAT) def next_item_sort_order(self): """Generate the next number for the invoice item's sort order""" from nano.models import InvoiceItem total = InvoiceItem.query.filter_by(invoice_id=self.id).count() return total+1 def update_totals(self, commit=False): """Update total and tax""" sub_total = 0.0 tax = 0.0 for item in self.invoice_items: sub_total += float(item.total if item.total else 0) tax += float(item.tax if item.tax else 0) self.tax = tax self.sub_total = sub_total self.total = float(self.tax) + float(self.sub_total) if commit: db.session.add(self) db.session.commit() return True def serialize(self): d = model_to_dict(self) d['InvoiceItems'] = [item.serialize() for item in self.invoice_items] return d def update_payment_status(self): """Returns true if the amount has been paid""" payments = Payment.query.filter_by(invoice_id=self.id).all() total = 0.0 for payment in payments: total += float(payment.amount) if total >= self.total: self.payment_status = u'paid' else: self.payment_status = u'unpaid' db.session.add(self) db.session.commit() return False def get_status(self): if self.status == 'draft': return 'draft' if self.status == 'saved': paid = True if self.payment_status == 'paid' else False if paid: return 'paid' if self.due_date <= datetime.now(): return 'overdue' else: return 'saved' def __json__(self): return json_dumps(self.serialize())