"""billing_accounts

Revision: 0185
Revision ID: d3e47057f56
Revises: ebacad20699
Create Date: 2020-03-23 15:07:43.470616

"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.sql import select, func
from sqlalchemy.dialects import postgresql


# revision identifiers, used by Alembic.
revision = 'd3e47057f56'
down_revision = 'ebacad20699'
branch_labels = None
depends_on = None


organizations = sa.Table(
    'organizations',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('created_by_id', sa.Integer(), nullable=True),
    sa.Column('created_at', sa.DateTime(), nullable=True),
    sa.Column('updated_at', sa.DateTime(), nullable=True),
    sa.Column('is_user_org', sa.Boolean(), nullable=True),
    sa.Column('billing_account_id', sa.Integer(), nullable=True),
    sa.Column('name', sa.String(), nullable=True),
    sa.Column('company', sa.String(), nullable=True),
    sa.Column('email', sa.String(), nullable=True),
    sa.Column('telephone', sa.String(), nullable=True),
    sa.Column('subscription_required', sa.Boolean(), nullable=True),
    sa.Column('trial_ends_at', sa.DateTime(), nullable=True),
    sa.Column('payment_method', sa.String(), nullable=True),
    sa.Column('prepaid_until', sa.DateTime(), nullable=True),
    sa.Column('can_self_export', sa.Boolean(), nullable=True),
    sa.Column('max_allowed_users', sa.Integer(), nullable=True),
    sa.Column('billing_address_city', sa.String(), nullable=True),
    sa.Column('billing_address_country', sa.String(), nullable=True),
    sa.Column('billing_address_line1', sa.String(), nullable=True),
    sa.Column('billing_address_line2', sa.String(), nullable=True),
    sa.Column('billing_address_state', sa.String(), nullable=True),
    sa.Column('billing_address_zip', sa.String(), nullable=True),
    sa.Column('billing_brand', sa.String(), nullable=True),
    sa.Column('billing_country', sa.String(), nullable=True),
    sa.Column('billing_exp_month', sa.String(), nullable=True),
    sa.Column('billing_exp_year', sa.String(), nullable=True),
    sa.Column('billing_last4', sa.String(), nullable=True),
    sa.Column('billing_name', sa.String(), nullable=True),
    sa.Column('eu_vat_country', sa.String(), nullable=True),
    sa.Column('eu_vat_number', sa.String(), nullable=True),
    sa.Column('eu_vat_rate', sa.Float(), nullable=True),
    sa.Column('has_stripe_source', sa.Boolean(), nullable=True),
    sa.Column('plan_last_charge_amount', sa.Float(), nullable=True),
    sa.Column('plan_last_charge_successful', sa.Boolean(), nullable=True),
    sa.Column('plan_last_charged_at', sa.DateTime(), nullable=True),
    sa.Column('plan_name', sa.String(), nullable=True),
    sa.Column('plan_next_charge_at', sa.DateTime(), nullable=True),
    sa.Column('plan_status', sa.String(), nullable=True),
    sa.Column('stripe_customer_id', sa.String(), nullable=True),
    sa.Column('stripe_subscription_id', sa.String(), nullable=True)
)

organization_members = sa.Table(
    'organization_members',
    sa.MetaData(),
    sa.Column('org_id', sa.Integer, primary_key=True),
    sa.Column('user_id', sa.Integer, primary_key=True)
)

invoices = sa.Table(
    'invoices',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('customer_id', sa.Integer, primary_key=True)
)


def upgrade():
    conn = op.get_bind()

    accounts = op.create_table('billing_accounts',
        sa.Column('id', sa.Integer(), nullable=False),
        sa.Column('created_by_id', sa.Integer(), nullable=True),
        sa.Column('created_at', sa.DateTime(), nullable=True),
        sa.Column('updated_at', sa.DateTime(), nullable=True),
        sa.Column('name', sa.String(), nullable=True),
        sa.Column('company', sa.String(), nullable=True),
        sa.Column('payment_method', sa.String(), nullable=True),
        sa.Column('seat_count', sa.Integer(), nullable=True),
        sa.Column('auto_adjust_seat_count', sa.Boolean(), nullable=True),
        sa.Column('scheduled_seat_deletion', sa.Integer(), nullable=True),
        sa.Column('scheduled_seat_deletion_at', sa.DateTime(), nullable=True),
        sa.Column('billing_name', sa.String(), nullable=True),
        sa.Column('billing_email', sa.String(), nullable=True),
        sa.Column('billing_phone', sa.String(), nullable=True),
        sa.Column('billing_address_line1', sa.String(), nullable=True),
        sa.Column('billing_address_line2', sa.String(), nullable=True),
        sa.Column('billing_address_zip', sa.String(), nullable=True),
        sa.Column('billing_address_city', sa.String(), nullable=True),
        sa.Column('billing_address_state', sa.String(), nullable=True),
        sa.Column('billing_address_country', sa.String(), nullable=True),
        sa.Column('billing_type', sa.String(), nullable=True),
        sa.Column('billing_brand', sa.String(), nullable=True),
        sa.Column('billing_country', sa.String(), nullable=True),
        sa.Column('billing_exp_month', sa.String(), nullable=True),
        sa.Column('billing_exp_year', sa.String(), nullable=True),
        sa.Column('billing_last4', sa.String(), nullable=True),
        sa.Column('eu_vat_country', sa.String(), nullable=True),
        sa.Column('eu_vat_number', sa.String(), nullable=True),
        sa.Column('eu_vat_rate', sa.Float(), nullable=True),
        sa.Column('plan_name', sa.String(), nullable=True),
        sa.Column('plan_status', sa.String(), nullable=True),
        sa.Column('plan_current_period_start', sa.DateTime(), nullable=True),
        sa.Column('plan_current_period_end', sa.DateTime(), nullable=True),
        sa.Column('plan_cancel_at_period_end', sa.Boolean(), nullable=True),
        sa.Column('plan_last_invoice_at', sa.DateTime(), nullable=True),
        sa.Column('plan_last_invoice_amount', sa.Float(), nullable=True),
        sa.Column('plan_next_charge_at', sa.DateTime(), nullable=True),
        sa.Column('plan_cancelled_at', sa.DateTime(), nullable=True),
        sa.Column('plan_has_invoice_items', sa.Boolean(), nullable=True),
        sa.Column('plan_last_invoice_item_added_at', sa.DateTime(), nullable=True),
        sa.Column('stripe_customer_id', sa.String(), nullable=True),
        sa.Column('stripe_subscription_id', sa.String(), nullable=True),
        sa.Column('has_stripe_payment_method', sa.Boolean(), nullable=True),
        sa.ForeignKeyConstraint(['created_by_id'], ['users.id'], ondelete='SET NULL'),
        sa.PrimaryKeyConstraint('id')
    )
    op.create_index(op.f('ix_billing_accounts_stripe_customer_id'), 'billing_accounts', ['stripe_customer_id'], unique=False)
    op.create_index(op.f('ix_billing_accounts_stripe_subscription_id'), 'billing_accounts', ['stripe_subscription_id'], unique=False)
    op.create_index(op.f('ix_billing_accounts_has_stripe_payment_method'), 'billing_accounts', ['has_stripe_payment_method'], unique=False)
    op.create_index(op.f('ix_billing_accounts_plan_current_period_end'), 'billing_accounts', ['plan_current_period_end'], unique=False)
    op.create_index(op.f('ix_billing_accounts_plan_status'), 'billing_accounts', ['plan_status'], unique=False)
    op.create_index(op.f('ix_billing_accounts_invoice_items'), 'billing_accounts', ['plan_has_invoice_items', 'plan_last_invoice_item_added_at'], unique=False)

    op.add_column('organizations', sa.Column('billing_account_id', sa.Integer(), nullable=True))
    op.add_column('organizations', sa.Column('locked', sa.Boolean(), nullable=True))
    op.create_index(op.f('ix_organizations_billing_account_id'), 'organizations', ['billing_account_id'], unique=False)
    op.create_foreign_key('organizations_billing_account_id_fkey', 'organizations', 'billing_accounts', ['billing_account_id'], ['id'], ondelete='CASCADE')
    op.execute("UPDATE organizations SET locked = true, cache_id = generate_cache_id(id) WHERE plan_status = 'locked'")

    op.drop_constraint('invoices_customer_id_fkey', 'invoices')
    op.add_column('invoice_items', sa.Column('tax_amount', sa.Float(), nullable=True))
    op.add_column('invoice_items', sa.Column('tax_rate', sa.Float(), nullable=True))

    op.execute("""
        UPDATE invoice_items SET tax_rate = invoices.tax_rate FROM invoices WHERE invoices.id = invoice_items.invoice_id
    """)

    q = select([
        organizations,
        select([func.count(organization_members.c.user_id)]).where(
            sa.and_(organization_members.c.org_id==organizations.c.id, organization_members.c.user_id!=None)).label('nb_members')
    ]).where(sa.and_(organizations.c.subscription_required==True, organizations.c.is_user_org==False))

    for org in conn.execute(q):
        r = conn.execute(accounts.insert().values(
            created_by_id=org.created_by_id,
            created_at=org.created_at,
            updated_at=org.updated_at,
            name=org.name,
            company=org.company,
            payment_method='manual' if org.prepaid_until or org.payment_method != 'stripe' else 'stripe',
            seat_count=org.max_allowed_users if org.prepaid_until else org.nb_members,
            auto_adjust_seat_count=True,
            scheduled_seat_deletion=0,
            billing_name=org.billing_name,
            billing_email=org.email,
            billing_phone=org.telephone,
            billing_address_line1=org.billing_address_line1,
            billing_address_line2=org.billing_address_line2,
            billing_address_zip=org.billing_address_zip,
            billing_address_city=org.billing_address_city,
            billing_address_state=org.billing_address_state,
            billing_address_country=org.billing_address_country,
            billing_type='card',
            billing_brand=org.billing_brand,
            billing_country=org.billing_country,
            billing_exp_month=org.billing_exp_month,
            billing_exp_year=org.billing_exp_year,
            billing_last4=org.billing_last4,
            eu_vat_country=org.eu_vat_country,
            eu_vat_number=org.eu_vat_number,
            eu_vat_rate=org.eu_vat_rate,
            plan_name='kantree_team_monthly_eur' if org.plan_status == 'trialing' else ('kantree_eur' if not org.plan_name else org.plan_name),
            plan_status=org.plan_status,
            plan_current_period_start=org.plan_last_charged_at,
            plan_current_period_end=org.trial_ends_at if org.plan_status == 'trialing' else (org.prepaid_until if org.prepaid_until else org.plan_next_charge_at),
            plan_cancel_at_period_end=False,
            plan_last_invoice_amount=org.plan_last_charge_amount,
            plan_last_invoice_at=org.plan_last_charged_at,
            plan_next_charge_at=org.plan_next_charge_at,
            plan_has_invoice_items=False,
            stripe_customer_id=org.stripe_customer_id,
            stripe_subscription_id=org.stripe_subscription_id,
            has_stripe_payment_method=org.has_stripe_source
        ))
        account_id = r.inserted_primary_key[0]
        conn.execute(organizations.update().where(organizations.c.id==org.id)\
            .values(billing_account_id=account_id))
        conn.execute(invoices.update().where(invoices.c.customer_id==org.id)\
            .values(customer_id=account_id))

    conn.execute(invoices.update().where(sa.and_(invoices.c.customer_id==organizations.c.id, ~organizations.c.subscription_required))\
        .values(customer_id=None))

    op.create_foreign_key('invoices_customer_id_fkey', 'invoices', 'billing_accounts', ['customer_id'], ['id'], ondelete='SET NULL')

def downgrade():
    pass
