"""Phase 21 Stock Item Master + Mapping Intelligence. Revision ID: 20260824_stock_item_intel_p21 Revises: 20260824_bank_analyzer_reuse_p20 """ from alembic import op import sqlalchemy as sa revision = "20260824_stock_item_intel_p21" down_revision = "20260824_bank_analyzer_reuse_p20" branch_labels = None depends_on = None def upgrade(): op.create_table( "accounting_stock_sync_runs", sa.Column("id", sa.Integer(), primary_key=True), sa.Column("tenant_id", sa.Integer(), sa.ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False), sa.Column("client_id", sa.Integer(), sa.ForeignKey("clients.id", ondelete="CASCADE"), nullable=False), sa.Column("tally_guid", sa.String(120), nullable=False), sa.Column("company_name", sa.String(255), nullable=False, server_default=""), sa.Column("status", sa.String(30), nullable=False, server_default="completed"), sa.Column("stock_group_count", sa.Integer(), nullable=False, server_default="0"), sa.Column("stock_item_count", sa.Integer(), nullable=False, server_default="0"), sa.Column("unit_count", sa.Integer(), nullable=False, server_default="0"), sa.Column("requested_by_user_id", sa.Integer(), sa.ForeignKey("users.id", ondelete="SET NULL"), nullable=True), sa.Column("created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), ) for name in ("tenant_id","client_id","tally_guid","status","created_at_utc"): op.create_index(f"ix_accounting_stock_sync_runs_{name}", "accounting_stock_sync_runs", [name]) op.create_table( "accounting_stock_groups", sa.Column("id", sa.Integer(), primary_key=True), sa.Column("tenant_id", sa.Integer(), sa.ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False), sa.Column("client_id", sa.Integer(), sa.ForeignKey("clients.id", ondelete="CASCADE"), nullable=False), sa.Column("tally_guid", sa.String(120), nullable=False), sa.Column("company_name", sa.String(255), nullable=False, server_default=""), sa.Column("master_guid", sa.String(120), nullable=False, server_default=""), sa.Column("name", sa.String(255), nullable=False), sa.Column("parent_name", sa.String(255), nullable=False, server_default=""), sa.Column("base_units", sa.String(80), nullable=False, server_default=""), sa.Column("source_payload_json", sa.Text(), nullable=False, server_default="{}"), sa.Column("synced_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), sa.UniqueConstraint("tenant_id","client_id","tally_guid","name", name="uq_accounting_stock_group"), ) for name in ("tenant_id","client_id","tally_guid","master_guid","name","parent_name","synced_at_utc"): op.create_index(f"ix_accounting_stock_groups_{name}", "accounting_stock_groups", [name]) op.create_table( "accounting_stock_items", sa.Column("id", sa.Integer(), primary_key=True), sa.Column("tenant_id", sa.Integer(), sa.ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False), sa.Column("client_id", sa.Integer(), sa.ForeignKey("clients.id", ondelete="CASCADE"), nullable=False), sa.Column("tally_guid", sa.String(120), nullable=False), sa.Column("company_name", sa.String(255), nullable=False, server_default=""), sa.Column("master_guid", sa.String(120), nullable=False, server_default=""), sa.Column("name", sa.String(255), nullable=False), sa.Column("parent_group_name", sa.String(255), nullable=False, server_default=""), sa.Column("category_name", sa.String(255), nullable=False, server_default=""), sa.Column("base_units", sa.String(80), nullable=False, server_default=""), sa.Column("additional_units", sa.String(80), nullable=False, server_default=""), sa.Column("hsn_code", sa.String(40), nullable=False, server_default=""), sa.Column("gst_applicable", sa.String(80), nullable=False, server_default=""), sa.Column("gst_type_of_supply", sa.String(80), nullable=False, server_default=""), sa.Column("opening_balance", sa.Float(), nullable=False, server_default="0"), sa.Column("opening_value", sa.Float(), nullable=False, server_default="0"), sa.Column("opening_rate", sa.String(80), nullable=False, server_default=""), sa.Column("normalized_name", sa.String(255), nullable=False, server_default=""), sa.Column("source_payload_json", sa.Text(), nullable=False, server_default="{}"), sa.Column("synced_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), sa.UniqueConstraint("tenant_id","client_id","tally_guid","name", name="uq_accounting_stock_item"), ) for name in ("tenant_id","client_id","tally_guid","master_guid","name","parent_group_name","base_units","hsn_code","normalized_name","synced_at_utc"): op.create_index(f"ix_accounting_stock_items_{name}", "accounting_stock_items", [name]) op.create_table( "accounting_stock_units", sa.Column("id", sa.Integer(), primary_key=True), sa.Column("tenant_id", sa.Integer(), sa.ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False), sa.Column("client_id", sa.Integer(), sa.ForeignKey("clients.id", ondelete="CASCADE"), nullable=False), sa.Column("tally_guid", sa.String(120), nullable=False), sa.Column("company_name", sa.String(255), nullable=False, server_default=""), sa.Column("master_guid", sa.String(120), nullable=False, server_default=""), sa.Column("name", sa.String(80), nullable=False), sa.Column("original_name", sa.String(80), nullable=False, server_default=""), sa.Column("is_simple_unit", sa.String(30), nullable=False, server_default=""), sa.Column("base_units", sa.String(80), nullable=False, server_default=""), sa.Column("additional_units", sa.String(80), nullable=False, server_default=""), sa.Column("conversion", sa.String(80), nullable=False, server_default=""), sa.Column("normalized_name", sa.String(80), nullable=False, server_default=""), sa.Column("source_payload_json", sa.Text(), nullable=False, server_default="{}"), sa.Column("synced_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), sa.UniqueConstraint("tenant_id","client_id","tally_guid","name", name="uq_accounting_stock_unit"), ) for name in ("tenant_id","client_id","tally_guid","master_guid","name","normalized_name","synced_at_utc"): op.create_index(f"ix_accounting_stock_units_{name}", "accounting_stock_units", [name]) op.create_table( "accounting_stock_item_mappings", sa.Column("id", sa.Integer(), primary_key=True), sa.Column("tenant_id", sa.Integer(), sa.ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False), sa.Column("client_id", sa.Integer(), sa.ForeignKey("clients.id", ondelete="CASCADE"), nullable=False), sa.Column("tally_guid", sa.String(120), nullable=False), sa.Column("source_type", sa.String(50), nullable=False, server_default="generic"), sa.Column("party_key", sa.String(255), nullable=False, server_default=""), sa.Column("source_description", sa.String(500), nullable=False), sa.Column("source_description_norm", sa.String(500), nullable=False), sa.Column("hsn_sac", sa.String(40), nullable=False, server_default=""), sa.Column("stock_item_id", sa.Integer(), sa.ForeignKey("accounting_stock_items.id", ondelete="CASCADE"), nullable=False), sa.Column("confidence", sa.Integer(), nullable=False, server_default="100"), sa.Column("mapping_origin", sa.String(30), nullable=False, server_default="manual"), sa.Column("note", sa.Text(), nullable=False, server_default=""), sa.Column("created_by_user_id", sa.Integer(), sa.ForeignKey("users.id", ondelete="SET NULL"), nullable=True), sa.Column("updated_by_user_id", sa.Integer(), sa.ForeignKey("users.id", ondelete="SET NULL"), nullable=True), sa.Column("created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), sa.Column("updated_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), sa.UniqueConstraint("tenant_id","client_id","tally_guid","source_type","party_key","source_description_norm","hsn_sac", name="uq_accounting_stock_item_mapping_source"), ) for name in ("tenant_id","client_id","tally_guid","source_type","party_key","source_description_norm","hsn_sac","stock_item_id"): op.create_index(f"ix_accounting_stock_item_mappings_{name}", "accounting_stock_item_mappings", [name]) op.create_table( "accounting_stock_unit_mappings", sa.Column("id", sa.Integer(), primary_key=True), sa.Column("tenant_id", sa.Integer(), sa.ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False), sa.Column("client_id", sa.Integer(), sa.ForeignKey("clients.id", ondelete="CASCADE"), nullable=False), sa.Column("tally_guid", sa.String(120), nullable=False), sa.Column("source_unit", sa.String(80), nullable=False), sa.Column("source_unit_norm", sa.String(80), nullable=False), sa.Column("target_unit_id", sa.Integer(), sa.ForeignKey("accounting_stock_units.id", ondelete="CASCADE"), nullable=False), sa.Column("quantity_factor", sa.Float(), nullable=False, server_default="1"), sa.Column("note", sa.Text(), nullable=False, server_default=""), sa.Column("created_by_user_id", sa.Integer(), sa.ForeignKey("users.id", ondelete="SET NULL"), nullable=True), sa.Column("updated_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), sa.UniqueConstraint("tenant_id","client_id","tally_guid","source_unit_norm", name="uq_accounting_stock_unit_mapping_source"), ) for name in ("tenant_id","client_id","tally_guid","source_unit_norm","target_unit_id"): op.create_index(f"ix_accounting_stock_unit_mappings_{name}", "accounting_stock_unit_mappings", [name]) def downgrade(): op.drop_table("accounting_stock_unit_mappings") op.drop_table("accounting_stock_item_mappings") op.drop_table("accounting_stock_units") op.drop_table("accounting_stock_items") op.drop_table("accounting_stock_groups") op.drop_table("accounting_stock_sync_runs")