Prepare ERP source for Gitea deployment

This commit is contained in:
A R R R Associates
2026-06-20 15:01:44 +05:30
commit 5c75eb6bd9
450 changed files with 67698 additions and 0 deletions
@@ -0,0 +1,103 @@
"""Phase 7S.3 email-to-engagement mapping
Revision ID: 20260612_phase_7s3_email_mapping
Revises: 20260611_phase_7s2_imap_incoming
Create Date: 2026-06-12
SQLite-safe revision:
- Adds reference id columns as plain Integer columns instead of adding
ForeignKey constraints through ALTER TABLE, because SQLite cannot ALTER
constraints without batch copy/move migration.
- SQLAlchemy model relationships can still use these id columns for lookups.
"""
from __future__ import annotations
from alembic import op
import sqlalchemy as sa
revision = "20260612_phase_7s3_email_mapping"
down_revision = "20260611_phase_7s2_imap_incoming"
branch_labels = None
depends_on = None
def _inspector():
return sa.inspect(op.get_bind())
def _has_table(table_name: str) -> bool:
return table_name in _inspector().get_table_names()
def _has_column(table_name: str, column_name: str) -> bool:
if not _has_table(table_name):
return False
return column_name in {col["name"] for col in _inspector().get_columns(table_name)}
def _create_index_if_missing(table_name: str, index_name: str, columns: list[str]) -> None:
if not _has_table(table_name):
return
existing = {idx["name"] for idx in _inspector().get_indexes(table_name)}
if index_name not in existing:
op.create_index(index_name, table_name, columns)
def _add_column_if_missing(table_name: str, column: sa.Column) -> None:
if _has_table(table_name) and not _has_column(table_name, column.name):
op.add_column(table_name, column)
def upgrade() -> None:
if not _has_table("email_incoming_messages"):
return
_add_column_if_missing(
"email_incoming_messages",
sa.Column("tracking_code", sa.String(length=80), nullable=True),
)
# SQLite does not support ALTER TABLE ADD CONSTRAINT for ForeignKey.
# Keep these as nullable integer reference columns. Application code and
# SQLAlchemy models can still resolve the linked records safely.
_add_column_if_missing(
"email_incoming_messages",
sa.Column("matched_engagement_id", sa.Integer(), nullable=True),
)
_add_column_if_missing(
"email_incoming_messages",
sa.Column("matched_task_id", sa.Integer(), nullable=True),
)
_add_column_if_missing(
"email_incoming_messages",
sa.Column("matched_invoice_id", sa.Integer(), nullable=True),
)
_add_column_if_missing(
"email_incoming_messages",
sa.Column("mapping_status", sa.String(length=30), nullable=False, server_default="UNMAPPED"),
)
_add_column_if_missing(
"email_incoming_messages",
sa.Column("mapping_notes", sa.Text(), nullable=True),
)
_add_column_if_missing(
"email_incoming_messages",
sa.Column("mapped_at_utc", sa.DateTime(timezone=True), nullable=True),
)
for name, cols in {
"ix_email_incoming_messages_tracking_code": ["tracking_code"],
"ix_email_incoming_messages_matched_engagement_id": ["matched_engagement_id"],
"ix_email_incoming_messages_matched_task_id": ["matched_task_id"],
"ix_email_incoming_messages_matched_invoice_id": ["matched_invoice_id"],
"ix_email_incoming_messages_mapping_status": ["mapping_status"],
"ix_email_incoming_messages_mapped_at_utc": ["mapped_at_utc"],
}.items():
_create_index_if_missing("email_incoming_messages", name, cols)
def downgrade() -> None:
# Keep defensive because SQLite cannot reliably drop columns/constraints
# in all local development environments without a batch table rewrite.
pass