Rota Criar Tenant

This commit is contained in:
RicardoJDaleprane 2026-02-11 21:25:57 -03:00
parent 91a4568db1
commit 5ce9ceaac9
34 changed files with 2260 additions and 12 deletions

View File

@ -1,5 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="PROJECT_PROFILE" value="Default" />
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>

View File

@ -0,0 +1,31 @@
"""nome-usuario
Revision ID: 223ec99140a9
Revises: 2bc15d1e557d
Create Date: 2024-12-28 05:55:10.230627
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = '223ec99140a9'
down_revision: Union[str, None] = '2bc15d1e557d'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###

View File

@ -0,0 +1,80 @@
"""Initial Migration Shared
Revision ID: 2bc15d1e557d
Revises:
Create Date: 2024-11-30 17:40:09.765054
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = '2bc15d1e557d'
down_revision: Union[str, None] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('inquilinos',
sa.Column('nome', sa.String(length=100), nullable=False),
sa.Column('cpf_cnpj', sa.String(length=14), nullable=False),
sa.Column('pessoa_celular', sa.String(length=20), nullable=True),
sa.Column('uuid', sa.UUID(), nullable=False),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_inquilinos')),
sa.UniqueConstraint('cpf_cnpj', name=op.f('uq_ct_inquilinos_cpf_cnpj'))
)
op.create_table('rbac_papeis',
sa.Column('nome', sa.String(length=50), nullable=False),
sa.Column('uuid', sa.UUID(), nullable=False),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_rbac_papeis')),
sa.UniqueConstraint('nome', name=op.f('uq_ct_rbac_papeis_nome'))
)
op.create_table('rbac_permissoes',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('nome', sa.String(length=50), nullable=False),
sa.PrimaryKeyConstraint('id', name=op.f('pk_ct_rbac_permissoes')),
sa.UniqueConstraint('nome', name=op.f('uq_ct_rbac_permissoes_nome'))
)
op.create_table('rbac_papel_permissoes',
sa.Column('papel_uuid', sa.UUID(), nullable=False),
sa.Column('permissao_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['papel_uuid'], ['shared.rbac_papeis.uuid'], name=op.f('fk_ct_rbac_papel_permissoes_papel_uuid_rbac_papeis')),
sa.ForeignKeyConstraint(['permissao_id'], ['shared.rbac_permissoes.id'], name=op.f('fk_ct_rbac_papel_permissoes_permissao_id_rbac_permissoes')),
sa.PrimaryKeyConstraint('papel_uuid', 'permissao_id', name=op.f('pk_ct_rbac_papel_permissoes'))
)
op.create_table('rbac_usuarios',
sa.Column('fk_inquilino_uuid', sa.UUID(), nullable=False),
sa.Column('id', fastapi_users_db_sqlalchemy.generics.GUID(), nullable=False),
sa.Column('email', sa.String(length=320), nullable=False),
sa.Column('hashed_password', sa.String(length=1024), nullable=False),
sa.Column('is_active', sa.Boolean(), nullable=False),
sa.Column('is_superuser', sa.Boolean(), nullable=False),
sa.Column('is_verified', sa.Boolean(), nullable=False),
sa.ForeignKeyConstraint(['fk_inquilino_uuid'], ['shared.inquilinos.uuid'], name=op.f('fk_ct_rbac_usuarios_fk_inquilino_uuid_inquilinos'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id', name=op.f('pk_ct_rbac_usuarios'))
)
op.create_table('rbac_papeis_usuario',
sa.Column('user_uuid', sa.UUID(), nullable=False),
sa.Column('papel_uuid', sa.UUID(), nullable=False),
sa.ForeignKeyConstraint(['papel_uuid'], ['shared.rbac_papeis.uuid'], name=op.f('fk_ct_rbac_papeis_usuario_papel_uuid_rbac_papeis')),
sa.ForeignKeyConstraint(['user_uuid'], ['shared.rbac_usuarios.id'], name=op.f('fk_ct_rbac_papeis_usuario_user_uuid_rbac_usuarios')),
sa.PrimaryKeyConstraint('user_uuid', 'papel_uuid', name=op.f('pk_ct_rbac_papeis_usuario'))
)
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('rbac_papeis_usuario')
op.drop_table('rbac_usuarios')
op.drop_table('rbac_papel_permissoes')
op.drop_table('rbac_permissoes')
op.drop_table('rbac_papeis')
op.drop_table('inquilinos')
# ### end Alembic comman

View File

@ -0,0 +1,31 @@
"""nome completo
Revision ID: 8b5eaa353af9
Revises: 223ec99140a9
Create Date: 2024-12-29 04:23:00.693428
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = '8b5eaa353af9'
down_revision: Union[str, None] = '223ec99140a9'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('rbac_usuarios', sa.Column('nome_completo', sa.String(length=100), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('rbac_usuarios', 'nome_completo')
# ### end Alembic commands ###

View File

@ -0,0 +1,38 @@
"""Transacao Comercial
Revision ID: 03f34e0286e2
Revises: cef79ed4a795
Create Date: 2025-03-10 12:31:08.864786
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = '03f34e0286e2'
down_revision: Union[str, None] = 'cef79ed4a795'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
# Defina o nome do tipo enum e os valores
enum_name = "comercialtransacaocomercialenum"
enum_values = ["PAGAMENTO", "RECEBIMENTO", "AMBOS"]
def upgrade() -> None:
sa.Enum(*enum_values, name=enum_name).create(op.get_bind())
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('comercial_relacoes_comercial', sa.Column('transacao_comercial',
sa.Enum('PAGAMENTO', 'RECEBIMENTO', 'AMBOS',
name='comercialtransacaocomercialenum',
inherit_schema=True), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('comercial_relacoes_comercial', 'transacao_comercial')
# ### end Alembic commands ###

View File

@ -0,0 +1,33 @@
"""Ajuste Campos Itens Equipamentos
Revision ID: 15bf111b7392
Revises: 1f0b163b5dc0
Create Date: 2025-04-20 16:56:06.263869
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = '15bf111b7392'
down_revision: Union[str, None] = '1f0b163b5dc0'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('estoque_itens_equipamentos', 'itens_equipamentos_ativo')
# ### end Alembic commands ###
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_manutencao',
existing_type=sa.Boolean(), server_default=sa.text('false'), existing_nullable=False)
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('estoque_itens_equipamentos',
sa.Column('itens_equipamentos_ativo', sa.BOOLEAN(), autoincrement=False, nullable=False))
# ### end Alembic commands ###

View File

@ -0,0 +1,287 @@
"""Correção campo permitir campo nulo
Revision ID: 17c67edadd6a
Revises: f7d6f6b09b0b
Create Date: 2024-12-14 17:51:50.439445
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = '17c67edadd6a'
down_revision: Union[str, None] = 'f7d6f6b09b0b'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('comercial_enderecos', 'endereco_pessoa_descricao',
existing_type=sa.VARCHAR(length=50),
nullable=True)
op.alter_column('comercial_enderecos', 'endereco_pessoa_numero',
existing_type=sa.VARCHAR(length=8),
nullable=True)
op.alter_column('comercial_enderecos', 'endereco_pessoa_complemento',
existing_type=sa.VARCHAR(length=50),
nullable=True)
op.alter_column('comercial_enderecos', 'endereco_pessoa_cep',
existing_type=sa.VARCHAR(length=8),
nullable=True)
op.alter_column('comercial_fisicas', 'fisica_cpf',
existing_type=sa.VARCHAR(length=11),
nullable=True)
op.alter_column('comercial_fisicas', 'fisica_rg',
existing_type=sa.VARCHAR(length=20),
nullable=True)
op.alter_column('comercial_fisicas', 'fisica_genero',
existing_type=sa.VARCHAR(length=2),
nullable=True)
op.alter_column('comercial_fisicas', 'fisica_nome',
existing_type=sa.VARCHAR(length=100),
nullable=True)
op.alter_column('comercial_juridicas', 'juridica_cnpj',
existing_type=sa.VARCHAR(length=14),
nullable=True)
op.alter_column('comercial_juridicas', 'juridica_email_fiscal',
existing_type=sa.VARCHAR(length=100),
nullable=True)
op.alter_column('comercial_juridicas', 'juridica_insc_est',
existing_type=sa.VARCHAR(length=50),
nullable=True)
op.alter_column('comercial_juridicas', 'juridica_ins_mun',
existing_type=sa.VARCHAR(length=50),
nullable=True)
op.alter_column('comercial_juridicas', 'juridica_razao_social',
existing_type=sa.VARCHAR(length=200),
nullable=True)
op.alter_column('comercial_juridicas', 'juridica_representante',
existing_type=sa.VARCHAR(length=100),
nullable=True)
op.alter_column('comercial_pessoas', 'pessoa_telefone',
existing_type=sa.VARCHAR(length=20),
nullable=True)
op.alter_column('comercial_pessoas', 'pessoa_celular',
existing_type=sa.VARCHAR(length=20),
nullable=True)
op.alter_column('comercial_pessoas', 'pessoa_tipo',
existing_type=sa.VARCHAR(length=1),
nullable=True)
op.alter_column('comercial_pessoas', 'pessoa_email',
existing_type=sa.VARCHAR(length=100),
nullable=True)
op.alter_column('estoque_equipamentos', 'equipamento_nome',
existing_type=sa.VARCHAR(length=50),
nullable=True)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_ns',
existing_type=sa.VARCHAR(length=50),
nullable=True)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_patrimonio',
existing_type=sa.VARCHAR(length=10),
nullable=True)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_data_compra',
existing_type=sa.DATE(),
nullable=True)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_prazo_garantia',
existing_type=sa.DATE(),
nullable=True)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_voltagem',
existing_type=sa.VARCHAR(length=1),
nullable=True)
op.alter_column('estoque_manutencoes_equipamentos', 'manutencao_equipamento_data_entrada',
existing_type=sa.DATE(),
nullable=True)
op.alter_column('estoque_manutencoes_equipamentos', 'manutencao_equipamento_defeito_apresentado',
existing_type=sa.VARCHAR(length=100),
nullable=True)
op.alter_column('financeiro_categorias', 'categorias_nome',
existing_type=sa.VARCHAR(length=20),
nullable=True)
op.alter_column('financeiro_centros_custo', 'centros_custo_nome',
existing_type=sa.VARCHAR(length=20),
nullable=True)
op.alter_column('financeiro_centros_custo', 'centros_custo_descricao',
existing_type=sa.VARCHAR(length=100),
nullable=True)
op.alter_column('financeiro_contas', 'contas_data_emissao',
existing_type=sa.DATE(),
nullable=True)
op.alter_column('financeiro_contas', 'contas_data_vencimento',
existing_type=sa.DATE(),
nullable=True)
op.alter_column('financeiro_contas', 'contas_descricao',
existing_type=sa.VARCHAR(length=200),
nullable=True)
op.alter_column('financeiro_contas_corrente', 'contas_corrente_nome_conta',
existing_type=sa.VARCHAR(length=50),
nullable=True)
op.alter_column('financeiro_contas_corrente', 'contas_corrente_descricao',
existing_type=sa.VARCHAR(length=100),
nullable=True)
op.alter_column('financeiro_formas_pagamento', 'formas_pagamento_descricao',
existing_type=sa.VARCHAR(length=20),
nullable=True)
op.alter_column('financeiro_movimentacoes_conta', 'movimentacoes_conta_descricao',
existing_type=sa.VARCHAR(length=200),
nullable=True)
op.alter_column('financeiro_status', 'statuss_nome_status',
existing_type=sa.VARCHAR(length=20),
nullable=True)
op.alter_column('financeiro_status', 'statuss_descricao',
existing_type=sa.VARCHAR(length=200),
nullable=True)
op.alter_column('historico_alteracoes', 'tabela',
existing_type=sa.VARCHAR(length=100),
nullable=True)
op.alter_column('historico_alteracoes', 'action',
existing_type=sa.VARCHAR(length=10),
nullable=True)
op.alter_column('historico_update', 'coluna',
existing_type=sa.VARCHAR(length=100),
nullable=True)
op.alter_column('historico_update', 'valor_antigo',
existing_type=sa.VARCHAR(length=200),
nullable=True)
op.alter_column('historico_update', 'valor_novo',
existing_type=sa.VARCHAR(length=200),
nullable=True)
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('historico_update', 'valor_novo',
existing_type=sa.VARCHAR(length=200),
nullable=False)
op.alter_column('historico_update', 'valor_antigo',
existing_type=sa.VARCHAR(length=200),
nullable=False)
op.alter_column('historico_update', 'coluna',
existing_type=sa.VARCHAR(length=100),
nullable=False)
op.alter_column('historico_alteracoes', 'action',
existing_type=sa.VARCHAR(length=10),
nullable=False)
op.alter_column('historico_alteracoes', 'tabela',
existing_type=sa.VARCHAR(length=100),
nullable=False)
op.alter_column('financeiro_status', 'statuss_descricao',
existing_type=sa.VARCHAR(length=200),
nullable=False)
op.alter_column('financeiro_status', 'statuss_nome_status',
existing_type=sa.VARCHAR(length=20),
nullable=False)
op.alter_column('financeiro_movimentacoes_conta', 'movimentacoes_conta_descricao',
existing_type=sa.VARCHAR(length=200),
nullable=False)
op.alter_column('financeiro_formas_pagamento', 'formas_pagamento_descricao',
existing_type=sa.VARCHAR(length=20),
nullable=False)
op.alter_column('financeiro_contas_corrente', 'contas_corrente_descricao',
existing_type=sa.VARCHAR(length=100),
nullable=False)
op.alter_column('financeiro_contas_corrente', 'contas_corrente_nome_conta',
existing_type=sa.VARCHAR(length=50),
nullable=False)
op.alter_column('financeiro_contas', 'contas_descricao',
existing_type=sa.VARCHAR(length=200),
nullable=False)
op.alter_column('financeiro_contas', 'contas_data_vencimento',
existing_type=sa.DATE(),
nullable=False)
op.alter_column('financeiro_contas', 'contas_data_emissao',
existing_type=sa.DATE(),
nullable=False)
op.alter_column('financeiro_centros_custo', 'centros_custo_descricao',
existing_type=sa.VARCHAR(length=100),
nullable=False)
op.alter_column('financeiro_centros_custo', 'centros_custo_nome',
existing_type=sa.VARCHAR(length=20),
nullable=False)
op.alter_column('financeiro_categorias', 'categorias_nome',
existing_type=sa.VARCHAR(length=20),
nullable=False)
op.alter_column('estoque_manutencoes_equipamentos', 'manutencao_equipamento_defeito_apresentado',
existing_type=sa.VARCHAR(length=100),
nullable=False)
op.alter_column('estoque_manutencoes_equipamentos', 'manutencao_equipamento_data_entrada',
existing_type=sa.DATE(),
nullable=False)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_voltagem',
existing_type=sa.VARCHAR(length=1),
nullable=False)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_prazo_garantia',
existing_type=sa.DATE(),
nullable=False)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_data_compra',
existing_type=sa.DATE(),
nullable=False)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_patrimonio',
existing_type=sa.VARCHAR(length=10),
nullable=False)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_ns',
existing_type=sa.VARCHAR(length=50),
nullable=False)
op.alter_column('estoque_equipamentos', 'equipamento_nome',
existing_type=sa.VARCHAR(length=50),
nullable=False)
op.alter_column('comercial_pessoas', 'pessoa_email',
existing_type=sa.VARCHAR(length=100),
nullable=False)
op.alter_column('comercial_pessoas', 'pessoa_tipo',
existing_type=sa.VARCHAR(length=1),
nullable=False)
op.alter_column('comercial_pessoas', 'pessoa_celular',
existing_type=sa.VARCHAR(length=20),
nullable=False)
op.alter_column('comercial_pessoas', 'pessoa_telefone',
existing_type=sa.VARCHAR(length=20),
nullable=False)
op.alter_column('comercial_juridicas', 'juridica_representante',
existing_type=sa.VARCHAR(length=100),
nullable=False)
op.alter_column('comercial_juridicas', 'juridica_razao_social',
existing_type=sa.VARCHAR(length=200),
nullable=False)
op.alter_column('comercial_juridicas', 'juridica_ins_mun',
existing_type=sa.VARCHAR(length=50),
nullable=False)
op.alter_column('comercial_juridicas', 'juridica_insc_est',
existing_type=sa.VARCHAR(length=50),
nullable=False)
op.alter_column('comercial_juridicas', 'juridica_email_fiscal',
existing_type=sa.VARCHAR(length=100),
nullable=False)
op.alter_column('comercial_juridicas', 'juridica_cnpj',
existing_type=sa.VARCHAR(length=14),
nullable=False)
op.alter_column('comercial_fisicas', 'fisica_nome',
existing_type=sa.VARCHAR(length=100),
nullable=False)
op.alter_column('comercial_fisicas', 'fisica_genero',
existing_type=sa.VARCHAR(length=2),
nullable=False)
op.alter_column('comercial_fisicas', 'fisica_rg',
existing_type=sa.VARCHAR(length=20),
nullable=False)
op.alter_column('comercial_fisicas', 'fisica_cpf',
existing_type=sa.VARCHAR(length=11),
nullable=False)
op.alter_column('comercial_enderecos', 'endereco_pessoa_cep',
existing_type=sa.VARCHAR(length=8),
nullable=False)
op.alter_column('comercial_enderecos', 'endereco_pessoa_complemento',
existing_type=sa.VARCHAR(length=50),
nullable=False)
op.alter_column('comercial_enderecos', 'endereco_pessoa_numero',
existing_type=sa.VARCHAR(length=8),
nullable=False)
op.alter_column('comercial_enderecos', 'endereco_pessoa_descricao',
existing_type=sa.VARCHAR(length=50),
nullable=False)
# ### end Alembic commands ###

View File

@ -0,0 +1,35 @@
"""Remocao Campo ativo fora padrao
Revision ID: 1f0b163b5dc0
Revises: 5ffe665c5be9
Create Date: 2025-03-17 08:40:40.599043
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = '1f0b163b5dc0'
down_revision: Union[str, None] = '5ffe665c5be9'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('estoque_equipamentos', 'equipamento_ativo')
op.drop_column('estoque_setores', 'setor_ativo')
op.drop_column('estoque_tipos_equipamentos', 'tipo_equipamento_ativo')
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('estoque_tipos_equipamentos', sa.Column('tipo_equipamento_ativo', sa.BOOLEAN(), server_default=sa.text('true'), autoincrement=False, nullable=False))
op.add_column('estoque_setores', sa.Column('setor_ativo', sa.BOOLEAN(), server_default=sa.text('true'), autoincrement=False, nullable=False))
op.add_column('estoque_equipamentos', sa.Column('equipamento_ativo', sa.BOOLEAN(), server_default=sa.text('true'), autoincrement=False, nullable=False))
# ### end Alembic commands ###

View File

@ -0,0 +1,41 @@
"""Boleano Manutenção Ajuste
Revision ID: 3aee83e24ef5
Revises: f893530f5281
Create Date: 2025-01-27 18:25:44.336991
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = '3aee83e24ef5'
down_revision: Union[str, None] = 'f893530f5281'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_ativo',
existing_type=sa.BOOLEAN(),
nullable=False)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_manutencao',
existing_type=sa.BOOLEAN(),
nullable=False)
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_manutencao',
existing_type=sa.BOOLEAN(),
nullable=True)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_ativo',
existing_type=sa.BOOLEAN(),
nullable=True)
# ### end Alembic commands ###

View File

@ -0,0 +1,43 @@
"""Colunas extras Tabela Associativa
Revision ID: 405e3f59e8af
Revises: 997336d58696
Create Date: 2025-02-04 06:59:12.882748
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = '405e3f59e8af'
down_revision: Union[str, None] = '997336d58696'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('estoque_manutencao_itens_equipamentos', sa.Column('manutencao_equipamento_defeito_apresentado', sa.String(length=100), nullable=True))
op.add_column('estoque_manutencao_itens_equipamentos', sa.Column('manutencao_equipamento_correcao_realizada', sa.Text(), nullable=True))
op.add_column('estoque_manutencao_itens_equipamentos', sa.Column('manutencao_equipamento_data_retorno', sa.Date(), nullable=True))
op.drop_constraint('fk_ct_estoque_manutencao_itens_equipamentos_fk_manutenc_35f1', 'estoque_manutencao_itens_equipamentos', type_='foreignkey')
op.drop_constraint('fk_ct_estoque_manutencao_itens_equipamentos_fk_itens_eq_ccb9', 'estoque_manutencao_itens_equipamentos', type_='foreignkey')
op.create_foreign_key(op.f('fk_ct_estoque_manutencao_itens_equipamentos_fk_itens_equipamentos_uuid_estoque_itens_equipamentos'), 'estoque_manutencao_itens_equipamentos', 'estoque_itens_equipamentos', ['fk_itens_equipamentos_uuid'], ['uuid'], ondelete='CASCADE')
op.create_foreign_key(op.f('fk_ct_estoque_manutencao_itens_equipamentos_fk_manutencao_uuid_estoque_manutencoes_equipamentos'), 'estoque_manutencao_itens_equipamentos', 'estoque_manutencoes_equipamentos', ['fk_manutencao_uuid'], ['uuid'], ondelete='CASCADE')
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(op.f('fk_ct_estoque_manutencao_itens_equipamentos_fk_manutencao_uuid_estoque_manutencoes_equipamentos'), 'estoque_manutencao_itens_equipamentos', type_='foreignkey')
op.drop_constraint(op.f('fk_ct_estoque_manutencao_itens_equipamentos_fk_itens_equipamentos_uuid_estoque_itens_equipamentos'), 'estoque_manutencao_itens_equipamentos', type_='foreignkey')
op.create_foreign_key('fk_ct_estoque_manutencao_itens_equipamentos_fk_itens_eq_ccb9', 'estoque_manutencao_itens_equipamentos', 'estoque_itens_equipamentos', ['fk_itens_equipamentos_uuid'], ['uuid'])
op.create_foreign_key('fk_ct_estoque_manutencao_itens_equipamentos_fk_manutenc_35f1', 'estoque_manutencao_itens_equipamentos', 'estoque_manutencoes_equipamentos', ['fk_manutencao_uuid'], ['uuid'])
op.drop_column('estoque_manutencao_itens_equipamentos', 'manutencao_equipamento_data_retorno')
op.drop_column('estoque_manutencao_itens_equipamentos', 'manutencao_equipamento_correcao_realizada')
op.drop_column('estoque_manutencao_itens_equipamentos', 'manutencao_equipamento_defeito_apresentado')
# ### end Alembic commands ###

View File

@ -0,0 +1,305 @@
"""Initial Migration Tenant
Revision ID: 52048623d0cc
Revises:
Create Date: 2024-11-30 17:40:30.077753
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = '52048623d0cc'
down_revision: Union[str, None] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('comercial_pessoas',
sa.Column('pessoa_status', sa.Boolean(), nullable=True),
sa.Column('pessoa_telefone', sa.String(length=20), nullable=False),
sa.Column('pessoa_celular', sa.String(length=20), nullable=False),
sa.Column('pessoa_tipo', sa.String(length=1), nullable=False),
sa.Column('pessoa_email', sa.String(length=100), nullable=False),
sa.Column('pessoa_local_evento', sa.Boolean(), nullable=True),
sa.Column('uuid', sa.UUID(), nullable=False),
sa.Column('created_at', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=False),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=True),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_comercial_pessoas'))
)
op.create_index(op.f('ix_ct_comercial_pessoas_updated_at'), 'comercial_pessoas', ['updated_at'], unique=False)
op.create_table('comercial_relacoes_comercial',
sa.Column('descricao_relacao_comercial', sa.String(length=30), nullable=False),
sa.Column('created_at', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=False),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=True),
sa.Column('uuid', sa.UUID(), nullable=False),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_comercial_relacoes_comercial'))
)
op.create_index(op.f('ix_ct_comercial_relacoes_comercial_updated_at'), 'comercial_relacoes_comercial', ['updated_at'], unique=False)
op.create_table('comercial_tipos_endereco',
sa.Column('tipo_endereco_descricao', sa.String(length=30), nullable=False),
sa.Column('created_at', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=False),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=True),
sa.Column('uuid', sa.UUID(), nullable=False),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_comercial_tipos_endereco'))
)
op.create_index(op.f('ix_ct_comercial_tipos_endereco_updated_at'), 'comercial_tipos_endereco', ['updated_at'], unique=False)
op.create_table('estoque_setores',
sa.Column('setor_nome', sa.String(length=30), nullable=False),
sa.Column('uuid', sa.UUID(), nullable=False),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_estoque_setores'))
)
op.create_table('financeiro_categorias',
sa.Column('categorias_nome', sa.String(length=20), nullable=False),
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.PrimaryKeyConstraint('id', name=op.f('pk_ct_financeiro_categorias'))
)
op.create_table('financeiro_centros_custo',
sa.Column('centros_custo_nome', sa.String(length=20), nullable=False),
sa.Column('centros_custo_descricao', sa.String(length=100), nullable=False),
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.PrimaryKeyConstraint('id', name=op.f('pk_ct_financeiro_centros_custo'))
)
op.create_table('financeiro_contas_corrente',
sa.Column('contas_corrente_nome_conta', sa.String(length=50), nullable=False),
sa.Column('contas_corrente_saldo_inicial', sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column('contas_corrente_data_criacao', sa.Date(), nullable=False),
sa.Column('contas_corrente_descricao', sa.String(length=100), nullable=False),
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.PrimaryKeyConstraint('id', name=op.f('pk_ct_financeiro_contas_corrente'))
)
op.create_index(op.f('ix_ct_financeiro_contas_corrente_contas_corrente_data_criacao'), 'financeiro_contas_corrente', ['contas_corrente_data_criacao'], unique=False)
op.create_table('financeiro_formas_pagamento',
sa.Column('formas_pagamento_descricao', sa.String(length=20), nullable=False),
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.PrimaryKeyConstraint('id', name=op.f('pk_ct_financeiro_formas_pagamento'))
)
op.create_table('financeiro_status',
sa.Column('statuss_nome_status', sa.String(length=20), nullable=False),
sa.Column('statuss_descricao', sa.String(length=200), nullable=False),
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.PrimaryKeyConstraint('id', name=op.f('pk_ct_financeiro_status'))
)
op.create_table('historico_alteracoes',
sa.Column('tabela', sa.String(length=100), nullable=False),
sa.Column('data_modificacao', sa.DateTime(), nullable=False),
sa.Column('action', sa.String(length=10), nullable=False),
sa.Column('usuario_id', sa.String(length=36), nullable=True),
sa.Column('registro_id', sa.String(length=36), nullable=False),
sa.Column('uuid', sa.UUID(), nullable=False),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_historico_alteracoes'))
)
op.create_table('comercial_enderecos',
sa.Column('endereco_pessoa_status', sa.Boolean(), nullable=True),
sa.Column('endereco_pessoa_descricao', sa.String(length=50), nullable=False),
sa.Column('endereco_pessoa_numero', sa.String(length=8), nullable=False),
sa.Column('endereco_pessoa_complemento', sa.String(length=50), nullable=False),
sa.Column('endereco_pessoa_cep', sa.String(length=8), nullable=False),
sa.Column('fk_pessoa_uuid', sa.UUID(), nullable=False),
sa.Column('fk_tipo_endereco_uuid', sa.UUID(), nullable=False),
sa.Column('created_at', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=False),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=True),
sa.Column('uuid', sa.UUID(), nullable=False),
sa.ForeignKeyConstraint(['fk_pessoa_uuid'], ['comercial_pessoas.uuid'], name=op.f('fk_ct_comercial_enderecos_fk_pessoa_uuid_comercial_pessoas'), ondelete='CASCADE'),
sa.ForeignKeyConstraint(['fk_tipo_endereco_uuid'], ['comercial_tipos_endereco.uuid'], name=op.f('fk_ct_comercial_enderecos_fk_tipo_endereco_uuid_comercial_tipos_endereco'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_comercial_enderecos'))
)
op.create_index(op.f('ix_ct_comercial_enderecos_updated_at'), 'comercial_enderecos', ['updated_at'], unique=False)
op.create_table('comercial_fisicas',
sa.Column('uuid', sa.UUID(), nullable=False),
sa.Column('fisica_cpf', sa.String(length=11), nullable=False),
sa.Column('fisica_rg', sa.String(length=20), nullable=False),
sa.Column('fisica_genero', sa.String(length=2), nullable=False),
sa.Column('fisica_nome', sa.String(length=100), nullable=False),
sa.ForeignKeyConstraint(['uuid'], ['comercial_pessoas.uuid'], name=op.f('fk_ct_comercial_fisicas_uuid_comercial_pessoas'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_comercial_fisicas'))
)
op.create_table('comercial_juridicas',
sa.Column('uuid', sa.UUID(), nullable=False),
sa.Column('juridica_cnpj', sa.String(length=14), nullable=False),
sa.Column('juridica_email_fiscal', sa.String(length=100), nullable=False),
sa.Column('juridica_insc_est', sa.String(length=50), nullable=False),
sa.Column('juridica_ins_mun', sa.String(length=50), nullable=False),
sa.Column('juridica_razao_social', sa.String(length=200), nullable=False),
sa.Column('juridica_representante', sa.String(length=100), nullable=False),
sa.ForeignKeyConstraint(['uuid'], ['comercial_pessoas.uuid'], name=op.f('fk_ct_comercial_juridicas_uuid_comercial_pessoas'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_comercial_juridicas'))
)
op.create_table('comercial_relacionamento_pessoa_empresa',
sa.Column('relacao_comercial_uuid', sa.UUID(), nullable=True),
sa.Column('pessoa_uuid', sa.UUID(), nullable=True),
sa.ForeignKeyConstraint(['pessoa_uuid'], ['comercial_pessoas.uuid'], name=op.f('fk_ct_comercial_relacionamento_pessoa_empresa_pessoa_uuid_comercial_pessoas'), ondelete='CASCADE'),
sa.ForeignKeyConstraint(['relacao_comercial_uuid'], ['comercial_relacoes_comercial.uuid'], name=op.f('fk_ct_comercial_relacionamento_pessoa_empresa_relacao_comercial_uuid_comercial_relacoes_comercial'), ondelete='CASCADE')
)
op.create_table('estoque_tipos_equipamentos',
sa.Column('tipo_equipamento_nome', sa.String(length=50), nullable=False),
sa.Column('fk_setor_uuid', sa.UUID(), nullable=False),
sa.Column('uuid', sa.UUID(), nullable=False),
sa.ForeignKeyConstraint(['fk_setor_uuid'], ['estoque_setores.uuid'], name=op.f('fk_ct_estoque_tipos_equipamentos_fk_setor_uuid_estoque_setores'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_estoque_tipos_equipamentos'))
)
op.create_table('financeiro_contas',
sa.Column('contas_tipo_conta', sa.Enum('PAGAR', 'RECEBER', name='financeirotipocontaenum', inherit_schema=True), nullable=False),
sa.Column('contas_data_emissao', sa.Date(), nullable=False),
sa.Column('contas_data_vencimento', sa.Date(), nullable=False),
sa.Column('contas_valor_total', sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column('contas_valor_juros', sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column('contas_valor_multa', sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column('contas_valor_desconto', sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column('contas_descricao', sa.String(length=200), nullable=False),
sa.Column('fk_pessoas_uuid', sa.UUID(), nullable=False),
sa.Column('fk_statuss_id', sa.Integer(), nullable=False),
sa.Column('fk_categorias_id', sa.Integer(), nullable=False),
sa.Column('fk_centros_custo_id', sa.Integer(), nullable=False),
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.ForeignKeyConstraint(['fk_categorias_id'], ['financeiro_categorias.id'], name=op.f('fk_ct_financeiro_contas_fk_categorias_id_financeiro_categorias'), ondelete='CASCADE'),
sa.ForeignKeyConstraint(['fk_centros_custo_id'], ['financeiro_centros_custo.id'], name=op.f('fk_ct_financeiro_contas_fk_centros_custo_id_financeiro_centros_custo'), ondelete='CASCADE'),
sa.ForeignKeyConstraint(['fk_pessoas_uuid'], ['comercial_pessoas.uuid'], name=op.f('fk_ct_financeiro_contas_fk_pessoas_uuid_comercial_pessoas'), ondelete='CASCADE'),
sa.ForeignKeyConstraint(['fk_statuss_id'], ['financeiro_status.id'], name=op.f('fk_ct_financeiro_contas_fk_statuss_id_financeiro_status'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id', name=op.f('pk_ct_financeiro_contas'))
)
op.create_table('historico_delete',
sa.Column('fk_historico_alteracoes_uuid', sa.UUID(), nullable=False),
sa.Column('registro_deletado', sa.Text(), nullable=False),
sa.Column('uuid', sa.UUID(), nullable=False),
sa.ForeignKeyConstraint(['fk_historico_alteracoes_uuid'], ['historico_alteracoes.uuid'], name=op.f('fk_ct_historico_delete_fk_historico_alteracoes_uuid_historico_alteracoes'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_historico_delete'))
)
op.create_table('historico_update',
sa.Column('fk_historico_alteracoes_uuid', sa.UUID(), nullable=False),
sa.Column('coluna', sa.String(length=100), nullable=False),
sa.Column('valor_antigo', sa.String(length=200), nullable=False),
sa.Column('valor_novo', sa.String(length=200), nullable=False),
sa.Column('uuid', sa.UUID(), nullable=False),
sa.ForeignKeyConstraint(['fk_historico_alteracoes_uuid'], ['historico_alteracoes.uuid'], name=op.f('fk_ct_historico_update_fk_historico_alteracoes_uuid_historico_alteracoes'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_historico_update'))
)
op.create_table('estoque_equipamentos',
sa.Column('equipamento_nome', sa.String(length=50), nullable=False),
sa.Column('equipamento_informacoes', sa.Text(), nullable=False),
sa.Column('fk_tipo_equipamento_uuid', sa.UUID(), nullable=False),
sa.Column('uuid', sa.UUID(), nullable=False),
sa.ForeignKeyConstraint(['fk_tipo_equipamento_uuid'], ['estoque_tipos_equipamentos.uuid'], name=op.f('fk_ct_estoque_equipamentos_fk_tipo_equipamento_uuid_estoque_tipos_equipamentos'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_estoque_equipamentos'))
)
op.create_table('financeiro_parcelas',
sa.Column('parcelas_numero_parcela', sa.Integer(), nullable=False),
sa.Column('parcelas_valor_parcela', sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column('parcelas_valor_juros', sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column('parcelas_valor_multa', sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column('parcelas_valor_desconto', sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column('parcelas_data_vencimento', sa.Date(), nullable=False),
sa.Column('fk_contas_id', sa.Integer(), nullable=False),
sa.Column('fk_statuss_id', sa.Integer(), nullable=False),
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.ForeignKeyConstraint(['fk_contas_id'], ['financeiro_contas.id'], name=op.f('fk_ct_financeiro_parcelas_fk_contas_id_financeiro_contas'), ondelete='CASCADE'),
sa.ForeignKeyConstraint(['fk_statuss_id'], ['financeiro_status.id'], name=op.f('fk_ct_financeiro_parcelas_fk_statuss_id_financeiro_status'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id', name=op.f('pk_ct_financeiro_parcelas'))
)
op.create_index(op.f('ix_ct_financeiro_parcelas_parcelas_data_vencimento'), 'financeiro_parcelas', ['parcelas_data_vencimento'], unique=False)
op.create_table('estoque_itens_equipamentos',
sa.Column('itens_equipamentos_ns', sa.String(length=50), nullable=False),
sa.Column('itens_equipamentos_patrimonio', sa.String(length=10), nullable=False),
sa.Column('itens_equipamentos_data_compra', sa.Date(), nullable=False),
sa.Column('itens_equipamentos_prazo_garantia', sa.Date(), nullable=False),
sa.Column('itens_equipamentos_voltagem', sa.String(length=1), nullable=False),
sa.Column('itens_equipamentos_valor_aquisicao', sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column('itens_equipamentos_rfid_uid', sa.String(length=39), nullable=False),
sa.Column('fk_equipamento_uuid', sa.UUID(), nullable=False),
sa.Column('created_at', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=False),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=True),
sa.Column('uuid', sa.UUID(), nullable=False),
sa.ForeignKeyConstraint(['fk_equipamento_uuid'], ['estoque_equipamentos.uuid'], name=op.f('fk_ct_estoque_itens_equipamentos_fk_equipamento_uuid_estoque_equipamentos'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_estoque_itens_equipamentos'))
)
op.create_index(op.f('ix_ct_estoque_itens_equipamentos_updated_at'), 'estoque_itens_equipamentos', ['updated_at'], unique=False)
op.create_table('financeiro_pagamentos',
sa.Column('data_pagamento', sa.Date(), nullable=False),
sa.Column('valor_pago', sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column('observacao', sa.Text(), nullable=False),
sa.Column('fk_parcelas_id', sa.Integer(), nullable=False),
sa.Column('fk_contas_corrente_id', sa.Integer(), nullable=False),
sa.Column('fk_formas_pagamento_id', sa.Integer(), nullable=False),
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.ForeignKeyConstraint(['fk_contas_corrente_id'], ['financeiro_contas_corrente.id'], name=op.f('fk_ct_financeiro_pagamentos_fk_contas_corrente_id_financeiro_contas_corrente'), ondelete='CASCADE'),
sa.ForeignKeyConstraint(['fk_formas_pagamento_id'], ['financeiro_formas_pagamento.id'], name=op.f('fk_ct_financeiro_pagamentos_fk_formas_pagamento_id_financeiro_formas_pagamento'), ondelete='CASCADE'),
sa.ForeignKeyConstraint(['fk_parcelas_id'], ['financeiro_parcelas.id'], name=op.f('fk_ct_financeiro_pagamentos_fk_parcelas_id_financeiro_parcelas'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id', name=op.f('pk_ct_financeiro_pagamentos'))
)
op.create_index(op.f('ix_ct_financeiro_pagamentos_data_pagamento'), 'financeiro_pagamentos', ['data_pagamento'], unique=False)
op.create_table('estoque_manutencoes_equipamentos',
sa.Column('manutencao_equipamento_data_entrada', sa.Date(), nullable=False),
sa.Column('manutencao_equipamento_data_retorno', sa.Date(), nullable=True),
sa.Column('manutencao_equipamento_defeito_apresentado', sa.String(length=100), nullable=False),
sa.Column('manutencao_equipamento_correcao_realizada', sa.Text(), nullable=False),
sa.Column('fk_itens_equipamentos_uuid', sa.UUID(), nullable=False),
sa.Column('uuid', sa.UUID(), nullable=False),
sa.ForeignKeyConstraint(['fk_itens_equipamentos_uuid'], ['estoque_itens_equipamentos.uuid'], name=op.f('fk_ct_estoque_manutencoes_equipamentos_fk_itens_equipamentos_uuid_estoque_itens_equipamentos'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_estoque_manutencoes_equipamentos'))
)
op.create_table('financeiro_movimentacoes_conta',
sa.Column('movimentacoes_conta_tipo_movimentacao', sa.Enum('CREDITO', 'DEBITO', name='financeirotipomovimentacaoenum', inherit_schema=True), nullable=False),
sa.Column('movimentacoes_conta_valor_movimentacao', sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column('movimentacoes_conta_data_movimentacao', sa.Date(), nullable=False),
sa.Column('movimentacoes_conta_descricao', sa.String(length=200), nullable=False),
sa.Column('fk_contas_corrente_id', sa.Integer(), nullable=False),
sa.Column('fk_pagamentos_id', sa.Integer(), nullable=False),
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.ForeignKeyConstraint(['fk_contas_corrente_id'], ['financeiro_contas_corrente.id'], name=op.f('fk_ct_financeiro_movimentacoes_conta_fk_contas_corrente_id_financeiro_contas_corrente'), ondelete='CASCADE'),
sa.ForeignKeyConstraint(['fk_pagamentos_id'], ['financeiro_pagamentos.id'], name=op.f('fk_ct_financeiro_movimentacoes_conta_fk_pagamentos_id_financeiro_pagamentos'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id', name=op.f('pk_ct_financeiro_movimentacoes_conta'))
)
op.create_index(op.f('ix_ct_financeiro_movimentacoes_conta_movimentacoes_conta_data_movimentacao'), 'financeiro_movimentacoes_conta', ['movimentacoes_conta_data_movimentacao'], unique=False)
op.create_table('financeiro_conta_manutencao_equipamentos',
sa.Column('manutencao_uuid', sa.UUID(), nullable=False),
sa.Column('conta_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['conta_id'], ['financeiro_contas.id'], name=op.f('fk_ct_financeiro_conta_manutencao_equipamentos_conta_id_financeiro_contas')),
sa.ForeignKeyConstraint(['manutencao_uuid'], ['estoque_manutencoes_equipamentos.uuid'], name=op.f('fk_ct_financeiro_conta_manutencao_equipamentos_manutencao_uuid_estoque_manutencoes_equipamentos')),
sa.PrimaryKeyConstraint('manutencao_uuid', 'conta_id', name=op.f('pk_ct_financeiro_conta_manutencao_equipamentos'))
)
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('financeiro_conta_manutencao_equipamentos')
op.drop_index(op.f('ix_ct_financeiro_movimentacoes_conta_movimentacoes_conta_data_movimentacao'), table_name='financeiro_movimentacoes_conta')
op.drop_table('financeiro_movimentacoes_conta')
op.drop_table('estoque_manutencoes_equipamentos')
op.drop_index(op.f('ix_ct_financeiro_pagamentos_data_pagamento'), table_name='financeiro_pagamentos')
op.drop_table('financeiro_pagamentos')
op.drop_index(op.f('ix_ct_estoque_itens_equipamentos_updated_at'), table_name='estoque_itens_equipamentos')
op.drop_table('estoque_itens_equipamentos')
op.drop_index(op.f('ix_ct_financeiro_parcelas_parcelas_data_vencimento'), table_name='financeiro_parcelas')
op.drop_table('financeiro_parcelas')
op.drop_table('estoque_equipamentos')
op.drop_table('historico_update')
op.drop_table('historico_delete')
op.drop_table('financeiro_contas')
op.drop_table('estoque_tipos_equipamentos')
op.drop_table('comercial_relacionamento_pessoa_empresa')
op.drop_table('comercial_juridicas')
op.drop_table('comercial_fisicas')
op.drop_index(op.f('ix_ct_comercial_enderecos_updated_at'), table_name='comercial_enderecos')
op.drop_table('comercial_enderecos')
op.drop_table('historico_alteracoes')
op.drop_table('financeiro_status')
op.drop_table('financeiro_formas_pagamento')
op.drop_index(op.f('ix_ct_financeiro_contas_corrente_contas_corrente_data_criacao'), table_name='financeiro_contas_corrente')
op.drop_table('financeiro_contas_corrente')
op.drop_table('financeiro_centros_custo')
op.drop_table('financeiro_categorias')
op.drop_table('estoque_setores')
op.drop_index(op.f('ix_ct_comercial_tipos_endereco_updated_at'), table_name='comercial_tipos_endereco')
op.drop_table('comercial_tipos_endereco')
op.drop_index(op.f('ix_ct_comercial_relacoes_comercial_updated_at'), table_name='comercial_relacoes_comercial')
op.drop_table('comercial_relacoes_comercial')
op.drop_index(op.f('ix_ct_comercial_pessoas_updated_at'), table_name='comercial_pessoas')
op.drop_table('comercial_pessoas')
# ### end Alembic commands ###

View File

@ -0,0 +1,43 @@
"""Ajuste Relacionamento Tabela Manutenção
Revision ID: 54212415a2e0
Revises: 3aee83e24ef5
Create Date: 2025-01-31 11:48:27.771071
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = '54212415a2e0'
down_revision: Union[str, None] = '3aee83e24ef5'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('estoque_manutencao_itens_equipamentos',
sa.Column('fk_manutencao_uuid', sa.UUID(), nullable=False),
sa.Column('fk_itens_equipamentos_uuid', sa.UUID(), nullable=False),
sa.ForeignKeyConstraint(['fk_itens_equipamentos_uuid'], ['estoque_itens_equipamentos.uuid'], name=op.f('fk_ct_estoque_manutencao_itens_equipamentos_fk_itens_equipamentos_uuid_estoque_itens_equipamentos')),
sa.ForeignKeyConstraint(['fk_manutencao_uuid'], ['estoque_manutencoes_equipamentos.uuid'], name=op.f('fk_ct_estoque_manutencao_itens_equipamentos_fk_manutencao_uuid_estoque_manutencoes_equipamentos')),
sa.PrimaryKeyConstraint('fk_manutencao_uuid', 'fk_itens_equipamentos_uuid', name=op.f('pk_ct_estoque_manutencao_itens_equipamentos'))
)
op.add_column('estoque_equipamentos', sa.Column('equipamento_ativo', sa.Boolean(), nullable=False, server_default=sa.true()))
op.add_column('estoque_setores', sa.Column('setor_ativo', sa.Boolean(), nullable=False, server_default=sa.true()))
op.add_column('estoque_tipos_equipamentos', sa.Column('tipo_equipamento_ativo', sa.Boolean(), nullable=False, server_default=sa.true()))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('estoque_tipos_equipamentos', 'tipo_equipamento_ativo')
op.drop_column('estoque_setores', 'setor_ativo')
op.drop_column('estoque_equipamentos', 'equipamento_ativo')
op.drop_table('estoque_manutencao_itens_equipamentos')
# ### end Alembic commands ###

View File

@ -0,0 +1,65 @@
"""Campo Ativo
Revision ID: 5ffe665c5be9
Revises: aabed61bf4b6
Create Date: 2025-03-17 08:21:36.254705
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = '5ffe665c5be9'
down_revision: Union[str, None] = 'aabed61bf4b6'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('comercial_pessoas', sa.Column('ativo', sa.Boolean(), server_default=sa.text('true'), nullable=False))
op.add_column('comercial_pessoas', sa.Column('data_ativacao', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=False))
op.add_column('comercial_pessoas', sa.Column('data_desativacao', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=True))
op.add_column('comercial_relacoes_comercial', sa.Column('ativo', sa.Boolean(), server_default=sa.text('true'), nullable=False))
op.add_column('comercial_relacoes_comercial', sa.Column('data_ativacao', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=False))
op.add_column('comercial_relacoes_comercial', sa.Column('data_desativacao', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=True))
op.add_column('estoque_equipamentos', sa.Column('ativo', sa.Boolean(), server_default=sa.text('true'), nullable=False))
op.add_column('estoque_equipamentos', sa.Column('data_ativacao', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=False))
op.add_column('estoque_equipamentos', sa.Column('data_desativacao', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=True))
op.add_column('estoque_itens_equipamentos', sa.Column('ativo', sa.Boolean(), server_default=sa.text('true'), nullable=False))
op.add_column('estoque_itens_equipamentos', sa.Column('data_ativacao', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=False))
op.add_column('estoque_itens_equipamentos', sa.Column('data_desativacao', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=True))
op.add_column('estoque_setores', sa.Column('ativo', sa.Boolean(), server_default=sa.text('true'), nullable=False))
op.add_column('estoque_setores', sa.Column('data_ativacao', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=False))
op.add_column('estoque_setores', sa.Column('data_desativacao', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=True))
op.add_column('estoque_tipos_equipamentos', sa.Column('ativo', sa.Boolean(), server_default=sa.text('true'), nullable=False))
op.add_column('estoque_tipos_equipamentos', sa.Column('data_ativacao', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=False))
op.add_column('estoque_tipos_equipamentos', sa.Column('data_desativacao', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('estoque_tipos_equipamentos', 'data_desativacao')
op.drop_column('estoque_tipos_equipamentos', 'data_ativacao')
op.drop_column('estoque_tipos_equipamentos', 'ativo')
op.drop_column('estoque_setores', 'data_desativacao')
op.drop_column('estoque_setores', 'data_ativacao')
op.drop_column('estoque_setores', 'ativo')
op.drop_column('estoque_itens_equipamentos', 'data_desativacao')
op.drop_column('estoque_itens_equipamentos', 'data_ativacao')
op.drop_column('estoque_itens_equipamentos', 'ativo')
op.drop_column('estoque_equipamentos', 'data_desativacao')
op.drop_column('estoque_equipamentos', 'data_ativacao')
op.drop_column('estoque_equipamentos', 'ativo')
op.drop_column('comercial_relacoes_comercial', 'data_desativacao')
op.drop_column('comercial_relacoes_comercial', 'data_ativacao')
op.drop_column('comercial_relacoes_comercial', 'ativo')
op.drop_column('comercial_pessoas', 'data_desativacao')
op.drop_column('comercial_pessoas', 'data_ativacao')
op.drop_column('comercial_pessoas', 'ativo')
# ### end Alembic commands ###

View File

@ -0,0 +1,31 @@
"""URL NF
Revision ID: 6f05efd0ef79
Revises: 85d86f327de9
Create Date: 2024-12-24 17:55:56.964916
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = '6f05efd0ef79'
down_revision: Union[str, None] = '85d86f327de9'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('estoque_itens_equipamentos', sa.Column('itens_equipamentos_url', sa.String(length=2083), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('estoque_itens_equipamentos', 'itens_equipamentos_url')
# ### end Alembic commands ###

View File

@ -0,0 +1,31 @@
"""Equipamento Ativo
Revision ID: 71db5898279e
Revises: 6f05efd0ef79
Create Date: 2024-12-27 06:54:36.928365
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = '71db5898279e'
down_revision: Union[str, None] = '6f05efd0ef79'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('estoque_itens_equipamentos', sa.Column('itens_equipamentos_ativo', sa.Boolean(), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('estoque_itens_equipamentos', 'itens_equipamentos_ativo')
# ### end Alembic commands ###

View File

@ -0,0 +1,119 @@
"""Ajuste campo nulo
Revision ID: 85d86f327de9
Revises: 17c67edadd6a
Create Date: 2024-12-14 18:30:31.199519
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = '85d86f327de9'
down_revision: Union[str, None] = '17c67edadd6a'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('estoque_equipamentos', 'equipamento_nome',
existing_type=sa.VARCHAR(length=50),
nullable=False)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_patrimonio',
existing_type=sa.VARCHAR(length=10),
nullable=False)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_valor_aquisicao',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=True)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_rfid_uid',
existing_type=sa.VARCHAR(length=39),
nullable=True)
op.alter_column('financeiro_contas', 'contas_valor_total',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=True)
op.alter_column('financeiro_contas', 'contas_valor_juros',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=True)
op.alter_column('financeiro_contas', 'contas_valor_multa',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=True)
op.alter_column('financeiro_contas', 'contas_valor_desconto',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=True)
op.alter_column('financeiro_contas_corrente', 'contas_corrente_saldo_inicial',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=True)
op.alter_column('financeiro_movimentacoes_conta', 'movimentacoes_conta_valor_movimentacao',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=True)
op.alter_column('financeiro_pagamentos', 'valor_pago',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=True)
op.alter_column('financeiro_parcelas', 'parcelas_valor_parcela',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=True)
op.alter_column('financeiro_parcelas', 'parcelas_valor_juros',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=True)
op.alter_column('financeiro_parcelas', 'parcelas_valor_multa',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=True)
op.alter_column('financeiro_parcelas', 'parcelas_valor_desconto',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=True)
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('financeiro_parcelas', 'parcelas_valor_desconto',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=False)
op.alter_column('financeiro_parcelas', 'parcelas_valor_multa',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=False)
op.alter_column('financeiro_parcelas', 'parcelas_valor_juros',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=False)
op.alter_column('financeiro_parcelas', 'parcelas_valor_parcela',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=False)
op.alter_column('financeiro_pagamentos', 'valor_pago',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=False)
op.alter_column('financeiro_movimentacoes_conta', 'movimentacoes_conta_valor_movimentacao',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=False)
op.alter_column('financeiro_contas_corrente', 'contas_corrente_saldo_inicial',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=False)
op.alter_column('financeiro_contas', 'contas_valor_desconto',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=False)
op.alter_column('financeiro_contas', 'contas_valor_multa',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=False)
op.alter_column('financeiro_contas', 'contas_valor_juros',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=False)
op.alter_column('financeiro_contas', 'contas_valor_total',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=False)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_rfid_uid',
existing_type=sa.VARCHAR(length=39),
nullable=False)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_valor_aquisicao',
existing_type=sa.NUMERIC(precision=10, scale=2),
nullable=False)
op.alter_column('estoque_itens_equipamentos', 'itens_equipamentos_patrimonio',
existing_type=sa.VARCHAR(length=10),
nullable=True)
op.alter_column('estoque_equipamentos', 'equipamento_nome',
existing_type=sa.VARCHAR(length=50),
nullable=True)
# ### end Alembic commands ###

View File

@ -0,0 +1,33 @@
"""Exclusão Colunoa Tabela Manutenção
Revision ID: 997336d58696
Revises: 54212415a2e0
Create Date: 2025-01-31 15:45:41.416306
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = '997336d58696'
down_revision: Union[str, None] = '54212415a2e0'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint('fk_ct_estoque_manutencoes_equipamentos_fk_itens_equipam_c4a1', 'estoque_manutencoes_equipamentos', type_='foreignkey')
op.drop_column('estoque_manutencoes_equipamentos', 'fk_itens_equipamentos_uuid')
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('estoque_manutencoes_equipamentos', sa.Column('fk_itens_equipamentos_uuid', sa.UUID(), autoincrement=False, nullable=False))
op.create_foreign_key('fk_ct_estoque_manutencoes_equipamentos_fk_itens_equipam_c4a1', 'estoque_manutencoes_equipamentos', 'estoque_itens_equipamentos', ['fk_itens_equipamentos_uuid'], ['uuid'], ondelete='CASCADE')
# ### end Alembic commands ###

View File

@ -0,0 +1,31 @@
"""Ajuste Relacionamentos S3
Revision ID: 9a867c0a6f02
Revises: ad38237bf077
Create Date: 2025-01-05 11:57:01.074787
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = '9a867c0a6f02'
down_revision: Union[str, None] = 'ad38237bf077'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_foreign_key(op.f('fk_ct_s3_arquivo_associacoes_fk_arquivo_uuid_s3_arquivos'), 's3_arquivo_associacoes', 's3_arquivos', ['fk_arquivo_uuid'], ['uuid'], ondelete='CASCADE')
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(op.f('fk_ct_s3_arquivo_associacoes_fk_arquivo_uuid_s3_arquivos'), 's3_arquivo_associacoes', type_='foreignkey')
# ### end Alembic commands ###

View File

@ -0,0 +1,47 @@
"""Gerenciamento Arquivos
Revision ID: a46b9a45e35d
Revises: f1a9c53bb090
Create Date: 2025-01-03 19:42:06.429869
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = 'a46b9a45e35d'
down_revision: Union[str, None] = 'f1a9c53bb090'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('s3_arquivos',
sa.Column('uuid', sa.UUID(), nullable=False),
sa.Column('created_at', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=False),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=True),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_s3_arquivos'))
)
op.create_table('s3_arquivo_associacoes',
sa.Column('arquivo_associacoes_arquivo_id', sa.UUID(), nullable=False),
sa.Column('arquivo_associacoes_tabela_relacionada', sa.String(), nullable=False),
sa.Column('arquivo_associacoes_linha_id', sa.Uuid(), nullable=False),
sa.Column('uuid', sa.UUID(), nullable=False),
sa.Column('created_at', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=False),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=True),
sa.ForeignKeyConstraint(['arquivo_associacoes_arquivo_id'], ['s3_arquivos.uuid'], name=op.f('fk_ct_s3_arquivo_associacoes_arquivo_associacoes_arquivo_id_s3_arquivos'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_ct_s3_arquivo_associacoes'))
)
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('s3_arquivo_associacoes')
op.drop_table('s3_arquivos')
# ### end Alembic commands ###

View File

@ -0,0 +1,41 @@
"""Teste Campo Ativo
Revision ID: aabed61bf4b6
Revises: 03f34e0286e2
Create Date: 2025-03-17 08:06:24.204853
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision: str = 'aabed61bf4b6'
down_revision: Union[str, None] = '03f34e0286e2'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('comercial_relacoes_comercial', 'transacao_comercial',
existing_type=postgresql.ENUM('PAGAMENTO', 'RECEBIMENTO', 'AMBOS', name='comercialtransacaocomercialenum'),
nullable=False)
op.add_column('comercial_tipos_endereco', sa.Column('ativo', sa.Boolean(), server_default=sa.text('true'), nullable=False))
op.add_column('comercial_tipos_endereco', sa.Column('data_ativacao', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=False))
op.add_column('comercial_tipos_endereco', sa.Column('data_desativacao', sa.DateTime(), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('comercial_tipos_endereco', 'data_desativacao')
op.drop_column('comercial_tipos_endereco', 'data_ativacao')
op.drop_column('comercial_tipos_endereco', 'ativo')
op.alter_column('comercial_relacoes_comercial', 'transacao_comercial',
existing_type=postgresql.ENUM('PAGAMENTO', 'RECEBIMENTO', 'AMBOS', name='comercialtransacaocomercialenum'),
nullable=True)
# ### end Alembic commands ###

View File

@ -0,0 +1,43 @@
"""Ajuste Tabela s3_arquivo_associacoes
Revision ID: ad38237bf077
Revises: bcfe3a7124a6
Create Date: 2025-01-05 11:41:37.874417
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = 'ad38237bf077'
down_revision: Union[str, None] = 'bcfe3a7124a6'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('s3_arquivo_associacoes', sa.Column('fk_arquivo_uuid', sa.UUID(), nullable=False))
op.add_column('s3_arquivo_associacoes', sa.Column('arquivo_associacoes_linha_uuid', sa.Uuid(), nullable=False))
op.alter_column('s3_arquivo_associacoes', 'arquivo_associacoes_tabela_relacionada',
existing_type=sa.VARCHAR(),
nullable=True)
op.drop_column('s3_arquivo_associacoes', 'arquivo_associacoes_linha_id')
op.drop_column('s3_arquivo_associacoes', 'arquivo_associacoes_arquivo_id')
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('s3_arquivo_associacoes', sa.Column('arquivo_associacoes_arquivo_id', sa.UUID(), autoincrement=False, nullable=False))
op.add_column('s3_arquivo_associacoes', sa.Column('arquivo_associacoes_linha_id', sa.UUID(), autoincrement=False, nullable=False))
op.alter_column('s3_arquivo_associacoes', 'arquivo_associacoes_tabela_relacionada',
existing_type=sa.VARCHAR(),
nullable=False)
op.drop_column('s3_arquivo_associacoes', 'arquivo_associacoes_linha_uuid')
op.drop_column('s3_arquivo_associacoes', 'fk_arquivo_uuid')
# ### end Alembic commands ###

View File

@ -0,0 +1,33 @@
"""Ajuste Tabela s3_arquivos
Revision ID: bcfe3a7124a6
Revises: a46b9a45e35d
Create Date: 2025-01-03 19:46:55.239751
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = 'bcfe3a7124a6'
down_revision: Union[str, None] = 'a46b9a45e35d'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('s3_arquivos', sa.Column('arquivos_nome_original', sa.String(length=200), nullable=True))
op.add_column('s3_arquivos', sa.Column('arquivos_nome_armazenado', sa.String(length=200), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('s3_arquivos', 'arquivos_nome_armazenado')
op.drop_column('s3_arquivos', 'arquivos_nome_original')
# ### end Alembic commands ###

View File

@ -0,0 +1,35 @@
"""Remoção Colunas Tabela Manutenção
Revision ID: cef79ed4a795
Revises: 405e3f59e8af
Create Date: 2025-02-04 07:06:43.847820
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = 'cef79ed4a795'
down_revision: Union[str, None] = '405e3f59e8af'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('estoque_manutencoes_equipamentos', 'manutencao_equipamento_correcao_realizada')
op.drop_column('estoque_manutencoes_equipamentos', 'manutencao_equipamento_defeito_apresentado')
op.drop_column('estoque_manutencoes_equipamentos', 'manutencao_equipamento_data_retorno')
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('estoque_manutencoes_equipamentos', sa.Column('manutencao_equipamento_data_retorno', sa.DATE(), autoincrement=False, nullable=True))
op.add_column('estoque_manutencoes_equipamentos', sa.Column('manutencao_equipamento_defeito_apresentado', sa.VARCHAR(length=100), autoincrement=False, nullable=True))
op.add_column('estoque_manutencoes_equipamentos', sa.Column('manutencao_equipamento_correcao_realizada', sa.TEXT(), autoincrement=False, nullable=False))
# ### end Alembic commands ###

View File

@ -0,0 +1,37 @@
"""Aumento Campo Email
Revision ID: f1a9c53bb090
Revises: 71db5898279e
Create Date: 2024-12-27 10:34:45.157752
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = 'f1a9c53bb090'
down_revision: Union[str, None] = '71db5898279e'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('comercial_pessoas', 'pessoa_email',
existing_type=sa.VARCHAR(length=100),
type_=sa.String(length=150),
existing_nullable=True)
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('comercial_pessoas', 'pessoa_email',
existing_type=sa.String(length=150),
type_=sa.VARCHAR(length=100),
existing_nullable=True)
# ### end Alembic commands ###

View File

@ -0,0 +1,31 @@
"""Inclusao Boleano Voltagem
Revision ID: f7d6f6b09b0b
Revises: 52048623d0cc
Create Date: 2024-12-14 10:39:08.645329
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = 'f7d6f6b09b0b'
down_revision: Union[str, None] = '52048623d0cc'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('estoque_equipamentos', sa.Column('equipamento_eletrico', sa.Boolean(), nullable=True, default=True))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('estoque_equipamentos', 'equipamento_eletrico')
# ### end Alembic commands ###

View File

@ -0,0 +1,33 @@
"""Boleano Manutenção retirada url s3
Revision ID: f893530f5281
Revises: 9a867c0a6f02
Create Date: 2025-01-27 10:52:49.384065
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
# revision identifiers, used by Alembic.
revision: str = 'f893530f5281'
down_revision: Union[str, None] = '9a867c0a6f02'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('estoque_itens_equipamentos', sa.Column('itens_equipamentos_manutencao', sa.Boolean(), nullable=True))
op.drop_column('estoque_itens_equipamentos', 'itens_equipamentos_url')
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('estoque_itens_equipamentos', sa.Column('itens_equipamentos_url', sa.VARCHAR(length=2083), autoincrement=False, nullable=True))
op.drop_column('estoque_itens_equipamentos', 'itens_equipamentos_manutencao')
# ### end Alembic commands ###

62
app/common/debug.py Normal file
View File

@ -0,0 +1,62 @@
# app/common/debug.py
from __future__ import annotations
import os
import builtins as _bi
from functools import lru_cache
from typing import Callable
# Chaves que aceitamos para ligar o debug (use APP_DEBUG como padrão)
_DEBUG_ENV_KEYS = ("APP_DEBUG", "DEBUG", "NOVO_INQUILINO_DEBUG")
_TRUE = {"1", "true", "yes", "on", "debug"}
@lru_cache(maxsize=1)
def debug_enabled() -> bool:
"""
as variáveis de ambiente uma única vez (cache).
Prioridade: APP_DEBUG > DEBUG > NOVO_INQUILINO_DEBUG.
"""
for key in _DEBUG_ENV_KEYS:
val = os.getenv(key)
if val is not None:
return val.lower() in _TRUE
return False
def make_dbg(prefix: str) -> Callable[..., None]:
"""
Retorna uma função _dbg(msg, *args, **kwargs) que:
- formata msg somente quando debug está ON
- prefixa com [<prefix>][DEBUG]
- é NO-OP quando debug está OFF
Uso: _dbg = make_dbg("MeuModulo")
"""
if debug_enabled():
def _dbg(msg: str = "", *args, **kwargs) -> None:
if args or kwargs:
try:
msg = msg.format(*args, **kwargs)
except Exception:
# Não quebra log por erro de formatação
pass
_bi.print(f"[{prefix}][DEBUG] {msg}")
return _dbg
else:
def _dbg(*args, **kwargs) -> None:
return None
return _dbg
def make_dbg_lazy(prefix: str) -> Callable[[Callable[[], object]], None]:
"""
Versão preguiçosa: recebe um callable que é executado quando o debug está ON.
Uso: _dbg_lazy(lambda: f"payload grande: {json.dumps(obj)}")
"""
if debug_enabled():
def _dbg_lazy(builder) -> None:
try:
_bi.print(f"[{prefix}][DEBUG] {builder()}")
except Exception as e:
_bi.print(f"[{prefix}][DEBUG] [lazy-error] {e}")
return _dbg_lazy
else:
def _dbg_lazy(*args, **kwargs) -> None:
return None
return _dbg_lazy

View File

@ -18,6 +18,7 @@ from app.routers import rotas
from app.config import URL_BD
from app.routers.router_registry import RouterRegistry
from fastapi.middleware.cors import CORSMiddleware
# from starlette.middleware.cors import CORSMiddleware
@ -55,6 +56,7 @@ def init_app(init_db=True):
router_registry = RouterRegistry(server, rotas.routers)
router_registry.register_routers()
return server

View File

@ -8,12 +8,23 @@ from app.database.session import sessionmanager
from app.rbac.auth import get_user_db, get_user_manager
from app.rbac.schemas import UserCreate
from fastapi_users.exceptions import UserAlreadyExists
from sqlalchemy import inspect
import json
# ------------------------------------------------------------------------------
# Debug helpers (compartilhados)
# ------------------------------------------------------------------------------
from app.common.debug import make_dbg, make_dbg_lazy
_DBG_NS = "NovoInquilino" # rótulo curto para logar a origem deste módulo
_dbg = make_dbg(_DBG_NS)
_dbg_lazy = make_dbg_lazy(_DBG_NS)
async def check_migrations(engine: AsyncEngine):
"""
Verifica se todas as migrações foram aplicadas.
"""
_dbg("check_migrations(): início")
alembic_config = Config("alembic.ini")
script = ScriptDirectory.from_config(alembic_config)
@ -22,6 +33,7 @@ async def check_migrations(engine: AsyncEngine):
context = MigrationContext.configure(sync_conn)
current_revision = context.get_current_revision()
latest_revision = script.get_current_head()
_dbg(f"check_migrations(): current={current_revision}, latest={latest_revision}")
if current_revision != latest_revision:
raise RuntimeError(
@ -31,33 +43,48 @@ async def check_migrations(engine: AsyncEngine):
await conn.run_sync(sync_check_migrations)
_dbg("check_migrations(): OK (up-to-date)")
async def create_user(session, fk_inquilino_uuid, email, password, is_superuser=False):
async def create_user(session, fk_inquilino_uuid, email, password, nome, is_superuser=False):
"""
Cria um usuário no sistema utilizando o gerenciador de usuários do FastAPI Users.
"""
_dbg("create_user(): início")
try:
_dbg("create_user(): preparando user_db/user_manager")
user_db = await get_user_db(session).__anext__()
user_manager = await get_user_manager(user_db).__anext__()
_dbg("create_user(): user_manager OK")
try:
_dbg(
"create_user(): chamando user_manager.create(UserCreate(...)) "
f"payload={{'nome_completo': {nome!r}, 'email': {email!r}, "
f"'is_superuser': {is_superuser!r}, 'fk_inquilino_uuid': {fk_inquilino_uuid}}}"
)
user = await user_manager.create(
UserCreate(
nome_completo=nome,
email=email,
password=password,
is_superuser=is_superuser,
is_active=True,
fk_inquilino_uuid=fk_inquilino_uuid,
)
)
_dbg(f"create_user(): OK user_id={user.id}")
return user.id
except UserAlreadyExists:
_dbg(f"create_user(): UserAlreadyExists para email={email!r}, consultando id existente...")
result_user = await session.execute(select(RbacUser).filter_by(email=email))
existing_user = result_user.scalars().first()
raise RuntimeError(f"Usuário '{email}' já existe, seu ID é {existing_user.id}")
except Exception as e:
_dbg(f"create_user(): ERRO -> {e!r}")
raise RuntimeError(f"Erro ao criar usuário '{email}': {e}")
@ -66,13 +93,23 @@ async def tenant_create(nome: str, email: str, password: str, cpf_cnpj: str):
Cria um novo tenant (inquilino) no sistema, configura o schema específico
e registra um usuário inicial relacionado ao inquilino.
"""
_dbg(f"tenant_create(): início payload={{'nome': {nome!r}, 'email': {email!r}, 'cpf_cnpj': {cpf_cnpj!r}}}")
async with sessionmanager.session() as db:
try:
# Verificar se o tenant já existe
_dbg("tenant_create(): verificando existência do inquilino por cpf_cnpj...")
result = await db.execute(select(Inquilino).filter_by(cpf_cnpj=cpf_cnpj))
existing_tenant = result.scalars().first()
if existing_tenant is None:
_dbg("tenant_create(): inquilino inexistente (OK para criar)")
else:
data = {c.key: getattr(existing_tenant, c.key) for c in inspect(existing_tenant).mapper.columns}
_dbg("tenant_create(): inquilino já existe -> " + json.dumps(data, ensure_ascii=False, default=str, indent=2))
_dbg("tenant_create(): criando registro do inquilino...")
if existing_tenant:
_dbg("tenant_create(): ABORT -> tenant já existe")
raise RuntimeError(
f"Tenant com CPF/CNPJ '{cpf_cnpj}' já existe. Nome: {existing_tenant.nome}, "
f"UUID: {existing_tenant.uuid}"
@ -83,22 +120,28 @@ async def tenant_create(nome: str, email: str, password: str, cpf_cnpj: str):
db.add(tenant)
await db.commit()
await db.refresh(tenant)
_dbg(f"tenant_create(): inquilino criado uuid={tenant.uuid}")
# Criar o usuário inicial
_dbg("tenant_create(): criando usuário inicial (superuser)...")
user_id = await create_user(
session=db,
nome=nome,
fk_inquilino_uuid=tenant.uuid,
email=email,
password=password,
is_superuser=True,
)
_dbg(f"tenant_create(): usuário criado id={user_id}")
# Nova sessão para associar o papel ao usuário
_dbg("tenant_create(): vinculando papel 'Super Administrador' ao usuário...")
async with sessionmanager.session() as new_db:
# Buscar o papel "Super Administrador"
result_papel = await new_db.execute(select(RbacPapel).filter_by(nome="Super Administrador"))
papel = result_papel.scalars().first()
if not papel:
_dbg("tenant_create(): ERRO -> Papel 'Super Administrador' não encontrado")
raise RuntimeError("Papel 'Super Administrador' não encontrado.")
# Relacionar o papel ao usuário
@ -109,9 +152,14 @@ async def tenant_create(nome: str, email: str, password: str, cpf_cnpj: str):
)
)
await new_db.commit()
_dbg("tenant_create(): papel vinculado OK")
_dbg("tenant_create(): fim OK")
return tenant.uuid
except RuntimeError as e:
_dbg(f"tenant_create(): ERRO (RuntimeError) -> {e!r}")
raise RuntimeError(f"Erro inesperado durante a criação do cliente: '{nome}': {e}")
except Exception as e:
_dbg(f"tenant_create(): ERRO (Exception) -> {e!r}")
raise RuntimeError(f"Erro inesperado durante a criação do cliente: '{nome}': {e}")

View File

@ -0,0 +1,468 @@
# from __future__ import annotations
#
# import os
# import asyncio
# import subprocess
# from dataclasses import dataclass
# from typing import Optional
#
# from app.multi_tenant.criar_tenant import tenant_create # sua função já existente
#
#
# class NovoInquilinoError(Exception):
# """Erro de alto nível no fluxo de criação de inquilino."""
#
#
# @dataclass
# class NovoInquilinoResult:
# tenant: str
# status: str
# alembic_stdout: Optional[str] = None
#
#
# async def _run_alembic_for_tenant(tenant_id: str, alembic_ini_path: Optional[str] = None) -> str:
# """
# Executa `alembic -x tenant=<id> upgrade head` para aplicar migrações
# (histórico centralizado na API do sistema).
#
# Implementação compatível com Windows/Uvicorn:
# - usa subprocess.run síncrono dentro de asyncio.to_thread
# """
# cmd = ["alembic"]
# if alembic_ini_path:
# cmd += ["-c", alembic_ini_path]
# cmd += ["-x", f"tenant={tenant_id}", "upgrade", "head"]
#
# def _run_sync():
# # Se precisar garantir diretório, use cwd="..." aqui.
# return subprocess.run(cmd, capture_output=True, text=True, check=True)
#
# try:
# result = await asyncio.to_thread(_run_sync)
# except subprocess.CalledProcessError as e:
# raise NovoInquilinoError(
# f"Erro Alembic (rc={e.returncode})\nSTDOUT:\n{e.stdout}\nSTDERR:\n{e.stderr}"
# ) from e
# except FileNotFoundError as e:
# # 'alembic' não encontrado no PATH/venv
# raise NovoInquilinoError(
# "Comando 'alembic' não encontrado. Verifique se o virtualenv está ativo e se o Alembic está instalado."
# ) from e
# except Exception as e:
# raise NovoInquilinoError(f"Falha inesperada ao executar Alembic: {e}") from e
#
# return result.stdout
#
#
# async def criar_novo_inquilino_service(
# *,
# nome: str,
# email: str,
# password: str,
# cpf_cnpj: str,
# alembic_ini_path_env: str = "ALEMBIC_INI_PATH",
# ) -> NovoInquilinoResult:
# """
# Caso de uso: cria um novo inquilino e roda migrações do schema dele.
# Mantém paridade com o seu script original.
# """
# print("Criar Novo Inquilino")
# try:
# tenant_identifier = await tenant_create(
# nome=nome, email=email, password=password, cpf_cnpj=cpf_cnpj
# )
# except Exception as e:
# # Falha ao criar registro/base do inquilino
# raise NovoInquilinoError(f"Erro ao criar o tenant: {e}") from e
#
# # Executa migrações a partir do histórico central (API do sistema)
# alembic_ini_path = os.getenv(alembic_ini_path_env) # opcional: apontar para outro repo
# stdout = await _run_alembic_for_tenant(str(tenant_identifier), alembic_ini_path)
#
# return NovoInquilinoResult(
# tenant=str(tenant_identifier),
# status="active",
# alembic_stdout=stdout,
# )
############################################################################################################
# app/multi_tenant/onboarding/novo_inquilino_service.py
from __future__ import annotations
import os
import asyncio
import subprocess
from dataclasses import dataclass
from typing import Optional, Dict, Any, List
from contextlib import asynccontextmanager
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession
from app.multi_tenant.criar_tenant import tenant_create # sua função já existente
from app.database.session import sessionmanager # precisa já estar inicializado no app
# ------------------------------------------------------------------------------
# Debug helpers (compartilhados)
# ------------------------------------------------------------------------------
from app.common.debug import make_dbg, make_dbg_lazy
_DBG_NS = "NovoInquilino" # rótulo curto para logar a origem deste módulo
_dbg = make_dbg(_DBG_NS)
_dbg_lazy = make_dbg_lazy(_DBG_NS)
# ------------------------------------------------------------------------------
# Exceção e resultado de caso de uso
# ------------------------------------------------------------------------------
class NovoInquilinoError(Exception):
"""Erro de alto nível no fluxo de criação de inquilino."""
@dataclass
class NovoInquilinoResult:
tenant: str
status: str
alembic_stdout: Optional[str] = None
# ------------------------------------------------------------------------------
# Helpers de sessão
# ------------------------------------------------------------------------------
@asynccontextmanager
async def _new_session() -> AsyncSession:
"""
Abre uma AsyncSession a partir do sessionmanager (compatível com sua infra).
"""
_dbg("_new_session(): abertura solicitada")
# Muitos session managers expõem um sessionmaker; aqui usamos esse caminho.
sm = sessionmanager.get_sessionmaker()
_dbg("_new_session(): usando get_sessionmaker()")
session: AsyncSession = sm()
_dbg("_new_session(): AsyncSession obtida")
try:
yield session
finally:
await session.close()
_dbg("_new_session(): sessão fechada")
# ------------------------------------------------------------------------------
# Helpers de schema / infra
# ------------------------------------------------------------------------------
def _derive_schema_candidates(tenant_uuid: str, prefix: str = "t_") -> List[str]:
"""
Retorna *todas* as possibilidades de nome de schema que queremos tentar dropar,
na ordem de preferência.
1) t_<uuid_sem_hifen> (ex.: t_01996bc991217d51ab00aacb559f8480)
2) <uuid_com_hifen> (ex.: 01996bcb-9184-7f68-9cf1-b5fe7af7c348) usado pelo seu Alembic
"""
uuid_no_dash = tenant_uuid.replace("-", "")
candidates = [
f"{prefix}{uuid_no_dash}",
tenant_uuid,
]
_dbg("_derive_schema_candidates(): tenant_uuid={0} -> {1}", tenant_uuid, candidates)
return candidates
async def _drop_schema(schema_name: str) -> bool:
"""
DROP SCHEMA IF EXISTS "<schema_name>" CASCADE
Retorna True se executou o comando sem erro (mesmo se o schema não existisse).
"""
_dbg('_drop_schema(): início. schema_name={0}', schema_name)
async with _new_session() as s:
await s.execute(text(f'DROP SCHEMA IF EXISTS "{schema_name}" CASCADE'))
await s.commit()
_dbg('_drop_schema(): OK. schema_name={0}', schema_name)
return True
async def _drop_tenant_schemas_all(tenant_uuid: str, schema_prefix: str) -> Dict[str, Any]:
"""
Tenta dropar *todas* as variações de schema possíveis do tenant.
Retorna um relatório com sucesso/erro por candidato.
"""
report: Dict[str, Any] = {"tenant_uuid": tenant_uuid, "schemas": []}
for schema in _derive_schema_candidates(tenant_uuid, schema_prefix):
try:
await _drop_schema(schema)
report["schemas"].append({"name": schema, "dropped": True})
except Exception as e:
_dbg("_drop_tenant_schemas_all(): erro ao dropar {0}: {1}", schema, e)
report["schemas"].append({"name": schema, "dropped": False, "error": str(e)})
_dbg("_drop_tenant_schemas_all(): report={0}", report)
return report
# ------------------------------------------------------------------------------
# Helpers de limpeza no shared (usuários, vínculos, inquilino)
# ------------------------------------------------------------------------------
async def _delete_users_and_links_all(tenant_uuid: str) -> Dict[str, int]:
"""
Remove vínculos de papéis e usuários para um inquilino no schema 'shared'.
Usa DELETE ... RETURNING 1 para contar afetados de forma portátil.
"""
_dbg("_delete_users_and_links_all(): início. tenant_uuid={0}", tenant_uuid)
stats = {"papel_vinculos": 0, "usuarios": 0}
async with _new_session() as s:
_dbg("_delete_users_and_links_all(): deletando vínculos em shared.rbac_papeis_usuario ...")
res_links = await s.execute(
text(
"""
DELETE FROM shared.rbac_papeis_usuario
WHERE user_uuid IN (
SELECT id FROM shared.rbac_usuarios
WHERE fk_inquilino_uuid = :tenant_uuid
)
RETURNING 1
"""
),
{"tenant_uuid": tenant_uuid},
)
# Contagem via RETURNING
links_rows = res_links.fetchall()
stats["papel_vinculos"] = len(links_rows)
_dbg("_delete_users_and_links_all(): vínculos deletados={0}", stats["papel_vinculos"])
_dbg("_delete_users_and_links_all(): deletando usuários em shared.rbac_usuarios ...")
res_users = await s.execute(
text(
"""
DELETE FROM shared.rbac_usuarios
WHERE fk_inquilino_uuid = :tenant_uuid
RETURNING 1
"""
),
{"tenant_uuid": tenant_uuid},
)
users_rows = res_users.fetchall()
stats["usuarios"] = len(users_rows)
_dbg("_delete_users_and_links_all(): usuários deletados={0}", stats["usuarios"])
await s.commit()
_dbg("_delete_users_and_links_all(): OK. stats={0}", stats)
return stats
async def _delete_tenant_record(tenant_uuid: str) -> int:
"""
Remove o próprio registro do inquilino no shared.inquilinos.
Retorna qtd de linhas afetadas.
"""
_dbg("_delete_tenant_record(): início. tenant_uuid={0}", tenant_uuid)
async with _new_session() as s:
res = await s.execute(
text(
"""
DELETE FROM shared.inquilinos
WHERE uuid = :tenant_uuid
RETURNING 1
"""
),
{"tenant_uuid": tenant_uuid},
)
rows = res.fetchall()
await s.commit()
count = len(rows)
_dbg("_delete_tenant_record(): OK. linhas_deletadas={0}", count)
return count
async def _find_tenant_uuid_by_doc(cpf_cnpj: str) -> Optional[str]:
"""
Busca o uuid do inquilino via cpf_cnpj (schema 'shared').
"""
_dbg("_find_tenant_uuid_by_doc(): início. cpf_cnpj={0}", cpf_cnpj)
async with _new_session() as s:
res = await s.execute(
text("SELECT uuid FROM shared.inquilinos WHERE cpf_cnpj = :doc"),
{"doc": cpf_cnpj},
)
row = res.fetchone()
tenant_uuid = row[0] if row else None
_dbg("_find_tenant_uuid_by_doc(): resultado={0}", tenant_uuid)
return tenant_uuid
# ------------------------------------------------------------------------------
# Limpezas compostas
# ------------------------------------------------------------------------------
async def _cleanup_full_by_tenant_uuid(tenant_uuid: str, schema_prefix: str) -> Dict[str, Any]:
"""
Limpa toda a sujeira que pode ter ficado para um tenant específico:
- DROP de todos os schemas candidatos
- DELETE vínculos + usuários
- DELETE registro do inquilino
"""
_dbg("_cleanup_full_by_tenant_uuid(): início. tenant_uuid={0}", tenant_uuid)
report: Dict[str, Any] = {"tenant_uuid": tenant_uuid}
# 1) Drop dos schemas candidatos
drop_report = await _drop_tenant_schemas_all(tenant_uuid, schema_prefix)
report["schema_names"] = [s["name"] for s in drop_report["schemas"]]
report["dropped_schema"] = any(s["dropped"] for s in drop_report["schemas"])
_dbg("_cleanup_full_by_tenant_uuid(): drop schema OK ({0})", report["schema_names"])
# 2) Usuários + vínculos
users_stats = await _delete_users_and_links_all(tenant_uuid)
report["users_cleanup"] = users_stats
_dbg("_cleanup_full_by_tenant_uuid(): users/links cleanup OK: {0}", users_stats)
# 3) Registro do inquilino
deleted = await _delete_tenant_record(tenant_uuid)
report["tenants_deleted"] = deleted
_dbg("_cleanup_full_by_tenant_uuid(): tenant record delete OK. linhas={0}", deleted)
_dbg("_cleanup_full_by_tenant_uuid(): fim. report={0}", report)
return report
async def _cleanup_full_by_doc(cpf_cnpj: str, schema_prefix: str) -> Dict[str, Any]:
"""
Limpeza quando falhou *antes* de sabermos seguramente o tenant_uuid (p. ex., erro criando usuário).
- Descobre tenant_uuid por cpf_cnpj;
- Se achou, faz a limpeza completa por uuid.
"""
_dbg("_cleanup_full_by_doc(): início. cpf_cnpj={0}", cpf_cnpj)
tenant_uuid = await _find_tenant_uuid_by_doc(cpf_cnpj)
if not tenant_uuid:
report = {"cpf_cnpj": cpf_cnpj, "tenant_uuid": None, "note": "nenhum inquilino encontrado"}
_dbg("_cleanup_full_by_doc(): nenhum inquilino para {0}. report={1}", cpf_cnpj, report)
return report
inner = await _cleanup_full_by_tenant_uuid(tenant_uuid, schema_prefix)
report = {
"cpf_cnpj": cpf_cnpj,
"tenant_uuid": tenant_uuid,
"schema_names": inner.get("schema_names"),
"dropped_schema": inner.get("dropped_schema"),
"users_cleanup": inner.get("users_cleanup"),
"tenants_deleted": inner.get("tenants_deleted"),
}
_dbg("_cleanup_full_by_doc(): fim. report={0}", report)
return report
# ------------------------------------------------------------------------------
# Alembic runner
# ------------------------------------------------------------------------------
async def _run_alembic_for_tenant(tenant_id: str, alembic_ini_path: Optional[str] = None) -> str:
"""
Executa `alembic -x tenant=<id> upgrade head` para aplicar migrações
(histórico centralizado na API do sistema).
Observações:
- Captura STDOUT/STDERR para diagnóstico.
- Em Windows/Uvicorn usamos subprocess.run síncrono dentro de asyncio.to_thread.
"""
cmd = ["alembic"]
if alembic_ini_path:
cmd += ["-c", alembic_ini_path]
cmd += ["-x", f"tenant={tenant_id}", "upgrade", "head"]
_dbg("_run_alembic_for_tenant(): cmd={0}", " ".join(cmd))
def _run_sync():
return subprocess.run(cmd, capture_output=True, text=True, check=True)
try:
result = await asyncio.to_thread(_run_sync)
except subprocess.CalledProcessError as e:
_dbg("_run_alembic_for_tenant(): CalledProcessError rc={0}", e.returncode)
_dbg("_run_alembic_for_tenant(): STDOUT\n{0}\n", e.stdout or "")
_dbg("_run_alembic_for_tenant(): STDERR\n{0}\n", e.stderr or "")
raise NovoInquilinoError(
f"Erro Alembic (rc={e.returncode})\nSTDOUT:\n{e.stdout}\n\nSTDERR:\n{e.stderr}"
) from e
except FileNotFoundError as e:
_dbg("_run_alembic_for_tenant(): 'alembic' não encontrado")
raise NovoInquilinoError(
"Comando 'alembic' não encontrado. Verifique se o virtualenv está ativo e se o Alembic está instalado."
) from e
except Exception as e:
_dbg("_run_alembic_for_tenant(): falha inesperada: {0}", e)
raise NovoInquilinoError(f"Falha inesperada ao executar Alembic: {e}") from e
_dbg("_run_alembic_for_tenant(): OK. returncode={0}", result.returncode)
if result.stdout:
_dbg("_run_alembic_for_tenant(): STDOUT (início)\n{0}\n_run_alembic_for_tenant(): STDOUT (fim)", result.stdout)
if result.stderr:
# Alembic/SQLAlchemy costuma logar no STDERR mesmo em sucesso
_dbg("_run_alembic_for_tenant(): STDERR (início)\n{0}\n_run_alembic_for_tenant(): STDERR (fim)", result.stderr)
# Normalmente não precisamos do stdout; manter só para compat.
return result.stdout or ""
# ------------------------------------------------------------------------------
# Caso de uso principal
# ------------------------------------------------------------------------------
async def criar_novo_inquilino_service(
*,
nome: str,
email: str,
password: str,
cpf_cnpj: str,
alembic_ini_path_env: str = "ALEMBIC_INI_PATH",
schema_prefix: str = "t_",
) -> NovoInquilinoResult:
"""
Fluxo:
1) Cria registro do inquilino + usuário inicial (tenant_create)
2) Executa migrações do schema do tenant (alembic -x tenant=<uuid> upgrade head)
Em qualquer falha, tenta limpar tudo para evitar dados órfãos.
"""
_dbg("criar_novo_inquilino_service(): início")
_dbg("payload: nome={0!r}, email={1!r}, cpf_cnpj={2!r}", nome, email, cpf_cnpj)
_dbg("criar_novo_inquilino_service(): chamando tenant_create(...)")
tenant_uuid: Optional[str] = None
# 1) Criar base do inquilino (inclui usuário inicial via seu fluxo)
try:
tenant_uuid = str(
await tenant_create(nome=nome, email=email, password=password, cpf_cnpj=cpf_cnpj)
)
_dbg("criar_novo_inquilino_service(): tenant_create OK. tenant_uuid={0}", tenant_uuid)
except Exception as e:
_dbg("criar_novo_inquilino_service(): ERRO em tenant_create: {0}", e)
# Limpeza pelo documento, pois talvez não tenhamos tenant_uuid sólido
_dbg("criar_novo_inquilino_service(): iniciando limpeza por cpf_cnpj (falha no tenant_create)")
try:
cleanup = await _cleanup_full_by_doc(cpf_cnpj, schema_prefix)
_dbg("criar_novo_inquilino_service(): limpeza concluída. cleanup={0}", cleanup)
except Exception as cleanup_err:
_dbg("criar_novo_inquilino_service(): limpeza por cpf_cnpj FALHOU: {0}", cleanup_err)
# Re-lança um erro de alto nível
raise NovoInquilinoError(str(e)) from e
# 2) Rodar migrações do tenant
alembic_ini_path = os.getenv(alembic_ini_path_env) # opcional: apontar para outro repo/folder
_dbg("criar_novo_inquilino_service(): alembic_ini_path={0}", alembic_ini_path)
_dbg("criar_novo_inquilino_service(): rodando Alembic para o tenant")
try:
stdout = await _run_alembic_for_tenant(tenant_uuid, alembic_ini_path)
_dbg("criar_novo_inquilino_service(): Alembic OK")
result = NovoInquilinoResult(tenant=tenant_uuid, status="active", alembic_stdout=stdout or "")
_dbg("criar_novo_inquilino_service(): fim com sucesso. result={0}", result)
return result
except Exception as mig_err:
_dbg("criar_novo_inquilino_service(): ERRO na migração: {0}", mig_err)
_dbg("criar_novo_inquilino_service(): iniciando limpeza por tenant_uuid (falha na migração)")
try:
cleanup = await _cleanup_full_by_tenant_uuid(tenant_uuid, schema_prefix)
_dbg("criar_novo_inquilino_service(): limpeza concluída. cleanup={0}", cleanup)
except Exception as cleanup_err:
_dbg("criar_novo_inquilino_service(): limpeza por tenant_uuid FALHOU: {0}", cleanup_err)
# Após limpar, propaga erro
raise

View File

@ -33,7 +33,7 @@ class UserRead(schemas.BaseUser[uuid.UUID]):
class UserCreate(schemas.BaseUserCreate):
fk_inquilino_uuid: UUID
nome: str = Field(min_length=3, max_length=100)
nome_completo: str = Field(min_length=3, max_length=100)
class UserUpdate(schemas.BaseUserUpdate):

View File

@ -1,6 +1,7 @@
from app.database import models
from app.routers.rotas_dinamicas import create_dynamic_router
from app.routers.router_pessoa import router as pessoa
from app.routers.router_tenant_admin import router as admin_tenants_router
from app.s3.router_s3 import router as s3
from app import schemas
from app.rbac.routes_login import router as fastapi_user
@ -76,12 +77,5 @@ fastapi_logado_router = fastapi_logado
s3_router = s3
# Lista de roteadores para serem registrados
routers = [
fastapi_user_router,
fastapi_logado_router,
tipo_endereco,
endereco,
pessoa_router,
papel,
s3_router,
admin_tenants_router
]

View File

@ -0,0 +1,37 @@
from __future__ import annotations
from fastapi import APIRouter, HTTPException, status
from app.schemas.tenant_admin import NovoInquilinoRequest, NovoInquilinoResponse
from app.multi_tenant.onboarding.novo_inquilino_service import (
criar_novo_inquilino_service,
NovoInquilinoResult,
NovoInquilinoError,
)
router = APIRouter(prefix="/admin/tenants", tags=["Admin - Tenants"])
@router.post("", status_code=status.HTTP_201_CREATED, response_model=NovoInquilinoResponse)
async def criar_novo_inquilino(payload: NovoInquilinoRequest) -> NovoInquilinoResponse:
try:
print("try")
result: NovoInquilinoResult = await criar_novo_inquilino_service(
nome=payload.nome,
email=payload.email,
password=payload.password,
cpf_cnpj=payload.cpf_cnpj, # já vem sanitizado/validado
)
return NovoInquilinoResponse(
tenant=result.tenant,
status=result.status,
alembic_stdout=result.alembic_stdout,
# campos opcionais; preencha se o seu serviço retornar
schema_name=None,
)
except NovoInquilinoError as e:
print("except NovoInquilinoError as e")
raise HTTPException(status_code=500, detail=str(e))
# except Exception as e:
# print("except NovoInquilinoError as e")
# raise HTTPException(status_code=500, detail=f"Erro inesperado: {e}")

View File

@ -0,0 +1,59 @@
from __future__ import annotations
from typing import Literal, Optional
from pydantic import BaseModel, EmailStr, Field, ConfigDict, field_validator
class NovoInquilinoRequest(BaseModel):
model_config = ConfigDict(extra="forbid") # rejeita campos desconhecidos
nome: str = Field(..., min_length=1, description="Nome do cliente/inquilino")
email: EmailStr
password: str = Field(..., min_length=6)
cpf_cnpj: str = Field(..., min_length=11, max_length=18, description="CPF/CNPJ com ou sem máscara")
# @field_validator("nome")
# @classmethod
# def _strip_nome(cls, v: str) -> str:
# v = v.strip()
# if not v:
# raise ValueError("Nome não pode ser vazio")
# return " ".join(v.split()) # colapsa espaços internos
#
# @field_validator("cpf_cnpj", mode="before")
# @classmethod
# def _sanitize_cpf_cnpj(cls, v: str) -> str:
# # remove tudo que não for dígito
# if isinstance(v, str):
# digits = "".join(ch for ch in v if ch.isdigit())
# return digits
# return v
#
# @field_validator("cpf_cnpj")
# @classmethod
# def _validate_cpf_cnpj_len(cls, v: str) -> str:
# # valida tamanho (11 = CPF, 14 = CNPJ). Validação algorítmica pode ficar na classe de validações especiais depois
# if len(v) not in (11, 14):
# raise ValueError("CPF/CNPJ deve ter 11 (CPF) ou 14 (CNPJ) dígitos após sanitização")
# return v
#
# @field_validator("subdominio")
# @classmethod
# def _normalize_subdominio(cls, v: Optional[str]) -> Optional[str]:
# if v is None:
# return v
# v = v.strip().lower()
# if not v:
# return None
# return v
class NovoInquilinoResponse(BaseModel):
model_config = ConfigDict(extra="ignore")
tenant: str
status: Literal["active", "failed", "provisioning"]
schema_name: Optional[str] = None
subdominio: Optional[str] = None
alembic_stdout: Optional[str] = None