visionextract-crm / models.py
jashdoshi77's picture
Deploy VisionExtract to HF Spaces
1a63864
# models.py - UPDATED
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime, date
from sqlalchemy import Text
import json
db = SQLAlchemy()
# Business Card Model
class BusinessCard(db.Model):
__tablename__ = 'business_cards'
id = db.Column(db.Integer, primary_key=True)
json_id = db.Column(db.String(64), unique=True, nullable=False)
owner_name = db.Column(db.String(200), nullable=False)
company_name = db.Column(db.String(200))
email = db.Column(db.String(120))
phone_number = db.Column(db.String(50))
address = db.Column(db.Text)
source_document = db.Column(db.String(500))
user_hash = db.Column(db.String(64), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def to_dict(self):
return {
'id': self.json_id,
'Owner Name': self.owner_name,
'Company Name': self.company_name,
'Email': self.email,
'Number': self.phone_number,
'Address': self.address,
'source_document': self.source_document,
'image_filename': f"{self.json_id}.png",
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None
}
# Brochure Model
class Brochure(db.Model):
__tablename__ = 'brochures'
id = db.Column(db.Integer, primary_key=True)
json_id = db.Column(db.String(64), unique=True, nullable=False)
company_name = db.Column(db.String(200), nullable=False)
raw_text = db.Column(db.Text)
source_document = db.Column(db.String(500))
user_hash = db.Column(db.String(64), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
contacts = db.relationship('Contact', backref='brochure', lazy=True, cascade='all, delete-orphan')
def to_dict(self):
return {
'id': self.json_id,
'company_name': self.company_name,
'raw_text': self.raw_text,
'contacts': [contact.to_dict() for contact in self.contacts],
'image_filename': f"{self.json_id}.pdf",
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None
}
# Contact Model (for Brochures)
class Contact(db.Model):
__tablename__ = 'brochure_contacts'
id = db.Column(db.Integer, primary_key=True)
json_id = db.Column(db.String(64), unique=True, nullable=False)
brochure_id = db.Column(db.Integer, db.ForeignKey('brochures.id'), nullable=False)
owner_name = db.Column(db.String(200), nullable=False)
email = db.Column(db.String(120))
phone_number = db.Column(db.String(50))
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def to_dict(self):
return {
'id': self.json_id,
'Owner Name': self.owner_name,
'Email': self.email,
'Number': self.phone_number,
'brochure_id': self.brochure_id,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None
}
# User Model for CRM - ENHANCED
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password_hash = db.Column(db.String(255), nullable=False)
email = db.Column(db.String(120))
name = db.Column(db.String(100))
phone = db.Column(db.String(20))
department = db.Column(db.String(100))
role = db.Column(db.String(20), default='employee')
status = db.Column(db.String(20), default='active')
dark_mode = db.Column(db.Boolean, default=False) # NEW: Dark mode preference
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
last_login = db.Column(db.DateTime)
# Relationships
contacts_assigned = db.relationship('CRMContact', foreign_keys='CRMContact.assigned_to', backref='assigned_user', lazy=True)
deals_assigned = db.relationship('Deal', foreign_keys='Deal.assigned_to', backref='assigned_user', lazy=True)
tasks_assigned = db.relationship('Task', foreign_keys='Task.assigned_to', backref='assigned_user', lazy=True)
activities = db.relationship('Activity', backref='user', lazy=True)
comments = db.relationship('Comment', backref='user', lazy=True)
notifications = db.relationship('Notification', backref='user', lazy=True)
# In User model
task_assignments_created = db.relationship(
'TaskAssignment',
foreign_keys='TaskAssignment.assigned_by',
backref='assigner',
lazy=True
)
task_assignments_received = db.relationship(
'TaskAssignment',
foreign_keys='TaskAssignment.user_id',
backref='assignee',
lazy=True
)
def to_dict(self):
return {
'id': self.id,
'username': self.username,
'email': self.email,
'name': self.name,
'phone': self.phone,
'department': self.department,
'role': self.role,
'status': self.status,
'dark_mode': self.dark_mode,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None,
'last_login': self.last_login.isoformat() if self.last_login else None
}
# Company Model for CRM - ENHANCED
class Company(db.Model):
__tablename__ = 'companies'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(200), unique=True, nullable=False)
industry = db.Column(db.String(100))
size = db.Column(db.String(50))
website = db.Column(db.String(200))
description = db.Column(db.Text)
tags = db.Column(db.String(500)) # NEW: Tags for companies
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def to_dict(self):
return {
'id': self.id,
'name': self.name,
'industry': self.industry,
'size': self.size,
'website': self.website,
'description': self.description,
'tags': self.tags,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None
}
# CRM Contact Model - ENHANCED
class CRMContact(db.Model):
__tablename__ = 'crm_contacts'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(200), nullable=False)
email = db.Column(db.String(120))
phone = db.Column(db.String(50))
company = db.Column(db.String(200))
position = db.Column(db.String(100))
tags = db.Column(db.String(500))
status = db.Column(db.String(50), nullable=True)
source = db.Column(db.String(100), default='manual')
assigned_to = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
notes = db.Column(db.Text)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# Relationships
deals = db.relationship('Deal', backref='contact', lazy=True)
tasks = db.relationship('Task', backref='contact', lazy=True)
activities = db.relationship('Activity', backref='contact', lazy=True)
comments = db.relationship('Comment', backref='contact', lazy=True)
attachments = db.relationship('Attachment', backref='contact', lazy=True)
def to_dict(self):
return {
'id': self.id,
'name': self.name,
'email': self.email,
'phone': self.phone,
'company': self.company,
'position': self.position,
'tags': self.tags,
'status': self.status,
'source': self.source,
'assigned_to': self.assigned_to,
'notes': self.notes,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None
}
# Deal Model - ENHANCED with tags
class Deal(db.Model):
__tablename__ = 'deals'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(200), nullable=False)
company = db.Column(db.String(200))
value = db.Column(db.Float, default=0.0)
stage = db.Column(db.String(50), default='lead')
probability = db.Column(db.Integer, default=0)
contact_id = db.Column(db.Integer, db.ForeignKey('crm_contacts.id'))
assigned_to = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
expected_close = db.Column(db.Date)
tags = db.Column(db.String(500)) # ENHANCED: Tags for deals
description = db.Column(db.Text)
created_date = db.Column(db.Date, default=datetime.utcnow)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# Relationships
activities = db.relationship('Activity', backref='deal', lazy=True)
comments = db.relationship('Comment', backref='deal', lazy=True)
attachments = db.relationship('Attachment', backref='deal', lazy=True)
tasks = db.relationship('Task', backref='deal', lazy=True)
def to_dict(self):
return {
'id': self.id,
'title': self.title,
'company': self.company,
'value': self.value,
'stage': self.stage,
'probability': self.probability,
'contact_id': self.contact_id,
'assigned_to': self.assigned_to,
'expected_close': self.expected_close.isoformat() if self.expected_close else None,
'tags': self.tags,
'description': self.description,
'created_date': self.created_date.isoformat() if self.created_date else None,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None
}
# Task Model - ENHANCED with assignment and mentions
class Task(db.Model):
__tablename__ = 'tasks'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(200), nullable=False)
description = db.Column(db.Text)
due_date = db.Column(db.Date)
due_time = db.Column(db.Time)
priority = db.Column(db.String(20), default='medium')
assigned_to = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
contact_id = db.Column(db.Integer, db.ForeignKey('crm_contacts.id'))
deal_id = db.Column(db.Integer, db.ForeignKey('deals.id'))
completed = db.Column(db.Boolean, default=False)
completed_date = db.Column(db.DateTime)
tags = db.Column(db.String(500)) # ENHANCED: Tags for tasks
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# Calendar fields
event_type = db.Column(db.String(20), default='task')
location = db.Column(db.String(200))
is_all_day = db.Column(db.Boolean, default=False)
reminder_minutes = db.Column(db.Integer, default=30)
# NEW: Mentions for tagging users
mentions = db.Column(db.String(500)) # Store mentioned user IDs
def to_dict(self):
return {
'id': self.id,
'title': self.title,
'description': self.description,
'due_date': self.due_date.isoformat() if self.due_date else None,
'due_time': self.due_time.isoformat() if self.due_time else None,
'priority': self.priority,
'assigned_to': self.assigned_to,
'contact_id': self.contact_id,
'deal_id': self.deal_id,
'completed': self.completed,
'completed_date': self.completed_date.isoformat() if self.completed_date else None,
'tags': self.tags,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None,
'event_type': self.event_type,
'location': self.location,
'is_all_day': self.is_all_day,
'reminder_minutes': self.reminder_minutes,
'mentions': self.mentions
}
# Task Assignment Model - NEW
class TaskAssignment(db.Model):
__tablename__ = 'task_assignments'
id = db.Column(db.Integer, primary_key=True)
task_id = db.Column(db.Integer, db.ForeignKey('tasks.id'), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
assigned_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
due_date = db.Column(db.Date)
notes = db.Column(db.Text)
status = db.Column(db.String(20), default='assigned')
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def to_dict(self):
return {
'id': self.id,
'task_id': self.task_id,
'user_id': self.user_id,
'assigned_by': self.assigned_by,
'due_date': self.due_date.isoformat() if self.due_date else None,
'notes': self.notes,
'status': self.status,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None
}
# Activity Model (Audit Log) - ENHANCED
class Activity(db.Model):
__tablename__ = 'activities'
id = db.Column(db.Integer, primary_key=True)
contact_id = db.Column(db.Integer, db.ForeignKey('crm_contacts.id'))
deal_id = db.Column(db.Integer, db.ForeignKey('deals.id'))
task_id = db.Column(db.Integer, db.ForeignKey('tasks.id'))
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
action = db.Column(db.String(100), nullable=False)
description = db.Column(db.Text)
entity_type = db.Column(db.String(50)) # NEW: contact, deal, task, company
entity_id = db.Column(db.Integer) # NEW: ID of the entity
old_values = db.Column(db.Text) # NEW: JSON string of old values
new_values = db.Column(db.Text) # NEW: JSON string of new values
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
def to_dict(self):
return {
'id': self.id,
'contact_id': self.contact_id,
'deal_id': self.deal_id,
'task_id': self.task_id,
'user_id': self.user_id,
'action': self.action,
'description': self.description,
'entity_type': self.entity_type,
'entity_id': self.entity_id,
'old_values': json.loads(self.old_values) if self.old_values else None,
'new_values': json.loads(self.new_values) if self.new_values else None,
'timestamp': self.timestamp.isoformat() if self.timestamp else None
}
# Attachment Model - ENHANCED
class Attachment(db.Model):
__tablename__ = 'attachments'
id = db.Column(db.Integer, primary_key=True)
contact_id = db.Column(db.Integer, db.ForeignKey('crm_contacts.id'))
deal_id = db.Column(db.Integer, db.ForeignKey('deals.id'))
task_id = db.Column(db.Integer, db.ForeignKey('tasks.id'))
filename = db.Column(db.String(255), nullable=False)
file_path = db.Column(db.String(500), nullable=False)
file_size = db.Column(db.Integer)
file_type = db.Column(db.String(100))
uploaded_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
uploaded_at = db.Column(db.DateTime, default=datetime.utcnow)
description = db.Column(db.Text)
def to_dict(self):
return {
'id': self.id,
'contact_id': self.contact_id,
'deal_id': self.deal_id,
'task_id': self.task_id,
'filename': self.filename,
'file_path': self.file_path,
'file_size': self.file_size,
'file_type': self.file_type,
'uploaded_by': self.uploaded_by,
'uploaded_at': self.uploaded_at.isoformat() if self.uploaded_at else None,
'description': self.description
}
# Comment Model - ENHANCED with mentions
class Comment(db.Model):
__tablename__ = 'comments'
id = db.Column(db.Integer, primary_key=True)
contact_id = db.Column(db.Integer, db.ForeignKey('crm_contacts.id'))
deal_id = db.Column(db.Integer, db.ForeignKey('deals.id'))
task_id = db.Column(db.Integer, db.ForeignKey('tasks.id'))
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
text = db.Column(db.Text, nullable=False)
mentions = db.Column(db.String(500)) # NEW: Store mentioned user IDs
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
def to_dict(self):
return {
'id': self.id,
'contact_id': self.contact_id,
'deal_id': self.deal_id,
'task_id': self.task_id,
'user_id': self.user_id,
'text': self.text,
'mentions': self.mentions,
'timestamp': self.timestamp.isoformat() if self.timestamp else None
}
# Notification Model - ENHANCED
class Notification(db.Model):
__tablename__ = 'notifications'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
title = db.Column(db.String(200), nullable=False)
message = db.Column(db.Text, nullable=False)
type = db.Column(db.String(50), default='info')
read = db.Column(db.Boolean, default=False)
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
link = db.Column(db.String(500))
category = db.Column(db.String(50), default='system')
is_urgent = db.Column(db.Boolean, default=False)
# NEW: For task assignments and mentions
related_entity_type = db.Column(db.String(50)) # task, deal, contact
related_entity_id = db.Column(db.Integer)
def to_dict(self):
return {
'id': self.id,
'user_id': self.user_id,
'title': self.title,
'message': self.message,
'type': self.type,
'read': self.read,
'timestamp': self.timestamp.isoformat() if self.timestamp else None,
'link': self.link,
'category': self.category,
'is_urgent': self.is_urgent,
'related_entity_type': self.related_entity_type,
'related_entity_id': self.related_entity_id
}
# Reminder Model - NEW
class Reminder(db.Model):
__tablename__ = 'reminders'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
title = db.Column(db.String(200), nullable=False)
description = db.Column(db.Text)
remind_at = db.Column(db.DateTime, nullable=False)
is_completed = db.Column(db.Boolean, default=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def to_dict(self):
return {
'id': self.id,
'user_id': self.user_id,
'title': self.title,
'description': self.description,
'remind_at': self.remind_at.isoformat() if self.remind_at else None,
'is_completed': self.is_completed,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None
}
# System Settings Model
class SystemSetting(db.Model):
__tablename__ = 'system_settings'
id = db.Column(db.Integer, primary_key=True)
key = db.Column(db.String(100), unique=True, nullable=False)
value = db.Column(db.Text)
description = db.Column(db.String(500))
category = db.Column(db.String(50), default='general')
updated_by = db.Column(db.Integer, db.ForeignKey('users.id'))
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def to_dict(self):
return {
'id': self.id,
'key': self.key,
'value': self.value,
'description': self.description,
'category': self.category,
'updated_by': self.updated_by,
'updated_at': self.updated_at.isoformat() if self.updated_at else None
}
# AI Chat History Model
class AIChatHistory(db.Model):
__tablename__ = 'ai_chat_history'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
question = db.Column(db.Text, nullable=False)
answer = db.Column(db.Text, nullable=False)
category = db.Column(db.String(50), default='general')
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
def to_dict(self):
return {
'id': self.id,
'user_id': self.user_id,
'question': self.question,
'answer': self.answer,
'category': self.category,
'timestamp': self.timestamp.isoformat() if self.timestamp else None
}
# AI Insights Model
class AIInsight(db.Model):
__tablename__ = 'ai_insights'
id = db.Column(db.Integer, primary_key=True)
insight_type = db.Column(db.String(50), nullable=False)
title = db.Column(db.String(200), nullable=False)
description = db.Column(db.Text, nullable=False)
data = db.Column(db.Text)
confidence = db.Column(db.Float, default=0.0)
is_active = db.Column(db.Boolean, default=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
expires_at = db.Column(db.DateTime)
def to_dict(self):
return {
'id': self.id,
'insight_type': self.insight_type,
'title': self.title,
'description': self.description,
'data': json.loads(self.data) if self.data else {},
'confidence': self.confidence,
'is_active': self.is_active,
'created_at': self.created_at.isoformat() if self.created_at else None,
'expires_at': self.expires_at.isoformat() if self.expires_at else None
}
# Bulk Message Campaign Model - NEW
class BulkMessageCampaign(db.Model):
__tablename__ = 'bulk_message_campaigns'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(200), nullable=False)
message_type = db.Column(db.String(20), nullable=False) # email, whatsapp
subject = db.Column(db.String(300))
message = db.Column(db.Text, nullable=False)
contact_ids = db.Column(db.Text) # JSON array of contact IDs
filters = db.Column(db.Text) # JSON filter criteria
sent_count = db.Column(db.Integer, default=0)
total_contacts = db.Column(db.Integer, default=0)
status = db.Column(db.String(20), default='draft') # draft, sending, completed, failed
created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
sent_at = db.Column(db.DateTime)
def to_dict(self):
return {
'id': self.id,
'name': self.name,
'message_type': self.message_type,
'subject': self.subject,
'message': self.message,
'contact_ids': json.loads(self.contact_ids) if self.contact_ids else [],
'filters': json.loads(self.filters) if self.filters else {},
'sent_count': self.sent_count,
'total_contacts': self.total_contacts,
'status': self.status,
'created_by': self.created_by,
'created_at': self.created_at.isoformat() if self.created_at else None,
'sent_at': self.sent_at.isoformat() if self.sent_at else None
}
# Export History Model - NEW
class ExportHistory(db.Model):
__tablename__ = 'export_history'
id = db.Column(db.Integer, primary_key=True)
export_type = db.Column(db.String(50), nullable=False) # contacts, companies, deals, tasks, master
file_format = db.Column(db.String(20), nullable=False) # excel, pdf
file_path = db.Column(db.String(500))
filters = db.Column(db.Text) # JSON filter criteria
record_count = db.Column(db.Integer, default=0)
exported_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
exported_at = db.Column(db.DateTime, default=datetime.utcnow)
def to_dict(self):
return {
'id': self.id,
'export_type': self.export_type,
'file_format': self.file_format,
'file_path': self.file_path,
'filters': json.loads(self.filters) if self.filters else {},
'record_count': self.record_count,
'exported_by': self.exported_by,
'exported_at': self.exported_at.isoformat() if self.exported_at else None
}