Skip to content

Tac Zdc 2023

s3://trase-storage/brazil/beef/indicators/silver/tac_zdc_2023.parquet

Dbt path: trase_production.main_brazil.tac_zdc_2023

Explore on Metabase: Full table; summary statistics

Containing yaml file link: trase/data_pipeline/models/brazil/beef/indicators/_schema_brazil_beef_indicators_commitments.yml

Model file link: trase/data_pipeline/models/brazil/beef/indicators/silver/tac_zdc_2023.py

Dbt test runs & lineage: Test results · Lineage

Full dbt_docs page: Open in dbt docs (includes lineage graph -at the bottom right-, tests, and downstream dependencies)

Tags: TAC, brazil, ZDC, G4, 2023, beef


tac_zdc_2023

Description

You can preview this data in Metabase here.

Find in this page information about the TAC, how the current file was built, and the field documentation.

Terms of Conduct Adjustment (TAC)

The Terms of Conduct Adjustment (Termos de Ajustamento de Conduta - TAC) are signed socio-environmental commitments from the Federal Public Ministry (Ministério Público Federal).

TAC description

The Termo de Ajustamento de Conduta (TAC) in the Brazilian beef sector is a legal instrument, first developed in Pará in 2009 and then spreading to other states, designed to ensure companies—particularly slaughterhouses—comply with environmental and labor regulations, especially around deforestation and illegal land use in cattle supply chains.

In the beef sector, TACs emerged as a response to widespread illegal deforestation linked to cattle ranching in the Amazon. The goal was to pressure slaughterhouses to avoid buying cattle from farms with illegal activities (e.g., forced labor, deforestation) or non-compliant with other criterias (e.g., land tenure and environmental regularization). Companies usually had a time limit to present a compliance plan, which was approved by Brazilian Federal Prosecuter's Office. Nowadays, the Boi na Linha protocol establishes a common ground for legal and socio-environmental standards.

Are TACs signed voluntarily?

Yes, TACs are formally voluntary, but in practice there is strong institutional pressure to sign. * Companies can refuse to sign, but may face legal action, reputational damage, or restrictions on access to public financing and major buyers. * Many large buyers (e.g., supermarkets, meat exporters) require suppliers to have signed and comply with a TAC.

So while not mandatory per se, signing is often strategically necessary.

Who signs the TAC da Carne?

A TAC is signed by a company, and the agreement affects the entire company. However, major slaughter companies, such as JBS or Marfrig, which operate in multiple states, can sign agreements for establishments in a specific state or group of states within the Legal Amazon. The TAC documents for companies with multiple establishments normally specify a tax number of a central office and not a specific slaughterhouse (or do not specify the tax number at all). Still, for companies with one (or a few) operational establishments, the tax number can be included, and it is typically associated with the slaughterhouse (CNPJ with 14 digits).

It implies that even if a company decides to open new slaughterhouses or modify existing CNPJs, all active establishments within a determined state will still have to be engaged. See below one example.

Company CNPJ on TAC? TAC Scope Geographic Limitation Example & Notes
JBS Central CNPJ (often without 14 digits) All establishments in Legal Amazon except Pará State-based (AC, MT, then extended) JBS TAC – See Preâmbulo 13 & Cláusula 6.7
Frigol Central office CNPJ (outside Legal Amazon) Only establishments in Pará Yes Frigol TAC – Cláusula 1.1
Marfrig Central office CNPJ (outside Legal Amazon) Only establishments in Mato Grosso Yes Similar to Frigol
Frinorte (Tomé Açu) Local slaughterhouse CNPJ (14 digits) Single establishment No Local-only agreement, CNPJ identifies facility
  • Company-Level Responsibility:

    • The TAC typically states that it is signed by the company, not just a facility. However, it limits its applicability to establishments in a specific state or region, meaning only those suppliers are affected.
  • CNPJ Usage:

    • Large companies usually do not specify all slaughterhouse CNPJs.
    • Smaller companies often do specify a single 14-digit CNPJ tied to one slaughterhouse.
    • In large companies, the headquarters CNPJ may be listed, but that doesn't mean all national operations are included.
  • Expansion of Scope Over Time:

    • Companies like JBS have had multiple TACs or amendments to expand to other states, indicating that each state may require a separate agreement or addendum.

Do TACs have limited 2-year validity?

Not necessarily. Most TACs in the cattle sector do not have a fixed expiration date. Many TACs explicitly state that they are indefinite: "O presente TERMO tem prazo indeterminado". This means the agreement remains valid as long as the company continues operating and has not been released from its obligations.

  • The 2-year idea may come from:
    • Misinterpretation of monitoring or reporting intervals (e.g., "apresentar relatório a cada 2 anos").
    • Older or generic TAC models in other sectors (e.g., environmental remediation).

So in the cattle sector, TACs are typically valid for an indefinite period — especially for large slaughterhouses under ongoing monitoring. They remain binding unless formally rescinded or replaced.

TAC Monitoring Obligations

Companies that sign TACs must: * Check their suppliers against lists of embargoed farms (from IBAMA, state agencies). * Ensure that no cattle are purchased from farms involved in: * Illegal deforestation * Slave-like labor * Overlapping Indigenous lands or conservation units * Provide animal movement records (GTAs) and other documentation.

Other details may be found at TAC Boi na Linha's website

TAC data updated by Boi na Linha

TAC data based on info provided by Boi na Linha (Imaflora) as a reference, available for the states of Amazonas, Acre, Mato Grosso, Pará, Rondônia (and 1 from Tocantins -TO-). It includes the slaughterhouses that adopted the terms of adjustment of conduct and in which year they did so.

The Boi na Linha lists are available here though they are not so friendly pdfs, and they might be changing the system (currently writing this in 2023-04). This information is frequently updated, but not on a regular schedule that we are aware of.

The primary sources of information are the state offices of the Federal Public Prosecutor's Office who have authorized the disclosure to Boi na Linha.


2023 update of the TAC with auditing data

The current file combines the consolidated TAC source found in

s3://trase-storage/brazil/beef/indicators/in/tac_boi_na_linha_com_data.csv
which you can explore in Metabase here

with data of auditing cycles found in

s3://trase-storage/brazil/beef/indicators/in/2025-02-14-compilacao-tac-ciclo-unificado-aud-2023.csv
which you can explore in Metabase here

You can also see more detailed documentation of these source files by following the links in the Depends On -> Nodes link in the current page.

It only keeps relevant columns from the source files, and for slaughterhouses from the auditing cycle file for which there is no data in the consolidated TAC file (25 slaughterhouses), it adds their CNPJ number, which is taken mostly from the slaughterhouse logistics file in s3://trase-storage/brazil/logistics/slaughterhouses/slaughterhouse_map_v5/2025-03-25-br_beef_logistics_map_v5.csv, and in one case from the GTA data.

For 13 of those slaughterhouses, the signing year and the pdf with the signed agreement was found in https://www.boinalinha.org/publicacoes , accessed on 2025-04-15, and the corresponding link reported on the source field.

So for the 25 new CNPJs/geocodes added to the TAC data based on this the auditing cycle file, there are important things to point out: * If the signing year was not found in https://www.boinalinha.org/publicacoes , they are marked as NULL * They don't indicate if the CNPJ has a G4 Public Commitment

These new records have marked in the field source_file if they come from the new data (see field description).

tac_signatories_combined file created in 2025

This dataset consolidates information from two key sources: the Holly Gibbs Lab and Boi na Linha. It includes only fields relevant to identifying slaughterhouses and the year they signed a TAC.

This combined dataset is based on the following input files:

Dataset Contents

The dataset includes the following fields:

  • cnpj: Unique identifier from Brazil's National Registry of Legal Entities (Cadastro Nacional da Pessoa Jurídica – CNPJ).
  • cnpj8: The first 8 digits of the CNPJ, representing the root entity (e.g., headquarters or parent company).
  • parent_cnpj8: Root CNPJ of the parent company, which may control multiple slaughterhouses. Note: A TAC signed by a subsidiary does not imply commitment by the entire corporate group.
  • signing_year: Year in which the slaughterhouse signed the TAC (Terms of Conduct Adjustment).
  • state: Brazilian state where the slaughterhouse is located.
  • legal_amazon: Boolean indicating whether the slaughterhouse is located within the Legal Amazon region (true or false).
  • source: Origin of the data (i.e., the source dataset for each record).

Data Processing

The dataset is generated and cleaned using the following script:
trase/data_pipeline/models/brazil/indicators/actors/zd_commitments/out/tac_signatories_combined.py

Acceptance Criteria

  • The combined dataset must not contain duplicate cnpj entries.
  • Source attribution must be preserved for each record.
  • All original cnpj values from both source datasets must be included.

History

  • 2025-06: Jailson created the "combined" file
  • 2025-07: IMAFLORA and dPaP Team reviewed "combined" file

Details

Column Type Description
company_name VARCHAR [string] Cleaned name of the company (uppercase and without accents), based on the company_label field.
company_label VARCHAR [string] For the data coming from the tac_boi_na_linha_com_data table (see source_file field), it comes from the 'Empresa' field. For the data coming from the tac_2023_cycle_updated_2025 table, it comes from the 'EMPRESA_BNL' field.
cnpj VARCHAR [string] Tax number of the company, 0 padded in the left until 14 characters. For most of the records, it comes from the 'CNPJ' field of the tac_boi_na_linha_com_data table. For the records coming from the tac_2023_cycle_updated_2025 table, the CNPJ was found mostly manually checking on the logistics map file, and in one case based on the GTA data.
geocode VARCHAR [string] Geocode of the municipality, based on the municipality_name and state_name fields
state_name VARCHAR [string] Official TRASE name of the state, based on the UF field of the state_uf field.
municipality_name VARCHAR [string] Official TRASE name of the municipality, based on the municipio field of the municipality_label field.
signing_year BIGINT [int] Year the TAC aggreement was signed. For the new records coming from the tac_2023_cycle_updated_2025 table, it is the minimum between 2023 and the auditing cycle. OBS: needs checking if we can get the real signing year for these records.
tac BOOLEAN
municipality_label VARCHAR
state_uf VARCHAR
beef_trase_id VARCHAR [string] Built concatenating 'BR-BEEF-SLAUGHTERHOUSE-' with the cnpj field. It seems to be used in scripts later on to identify slaughterhouses with ZDCs.
reporting_cycle_year INTEGER [int] Year of the reporting cycle (to check: if this is when they are going to be audited) coming from the tac_2023_cycle_updated_2025 table. It is mainly focused in 2023, but includes years from both before (from 2007) and after (until 2030).
source VARCHAR [sring] Where the original data comes from (a webpage, a news article, a legal document, etc.). For data coming from the tac_boi_na_linha_com_data table, it is the 'Source' field. For the data coming from the tac_2023_cycle_updated_2025 table, it is the 'OBSERVACAO' field.
source_file VARCHAR [string] Name of the source file from which the basic data comes from. Values are: tac_boi_na_linha_com_data and tac_2023_cycle_updated_2025.

Models / Seeds

  • source.trase_duckdb.source_brazil.tac_boi_na_linha_com_data
  • source.trase_duckdb.source_brazil.tac_2023_cycle_updated_2025
  • model.trase_duckdb.postgres_regions_without_geometry

Sources

  • ['source_brazil', 'tac_boi_na_linha_com_data']
  • ['source_brazil', 'tac_2023_cycle_updated_2025']

No called script or script source not found.

"""
Update of the TAC and G4 commitments for year 2023.

It only keeps relevant columns from the source files, and for slaughterhouses from the auditing cycle 
file for which there isno data in the consolidated TAC file (25 slaughterhouses), it adds their CNPJ number,
which is taken mostly from the slaughterhouse logistics file

The script takes the existing TAC data csv from 
's3://trase-storage/brazil/beef/indicators/in/tac_boi_na_linha_com_data.csv'
which seems to be last updated in 2022, and updates it with new data from 
Boi na Linha in 
's3://trase-storage/brazil/beef/indicators/in/2025-02-14-compilacao-tac-ciclo-unificado-aud-2023.csv'

For 24 records, the CNPJ data is identified manually matching similar names of the
same state and municipality as the logistics map in 
's3://trase-storage/brazil/logistics/slaughterhouses/slaughterhouse_map_v5/2025-03-25-br_beef_logistics_map_v5.csv'
and for 1 record the CNPJ is identified based on GTA data.
"""

import polars as pl

YEAR = 2023


def normalize_column(df, col):
    """
    Trim, normalize, uppercase, remove extra spaces of the selected column
    """
    df = df.with_columns(
        [
            pl.col(col)
            .str.strip_chars()
            # Replace multiple spaces with a single space
            .str.replace(r"\s+", " ")
            # Convert accents and diacritics (see https://stackoverflow.com/a/77217563)
            .str.normalize("NFKD")
            .str.replace_all(r"\p{CombiningMark}", "")
            .str.to_uppercase()
            .alias(col)
        ]
    )
    return df


def add_geocode(df, regions_lf, municipality_col, state_col):
    """
    Add geocode to the dataframe based on the municipality and state columns.
    """

    unnested_regions_lf = regions_lf.explode("synonyms").unique()

    # Join with regions_lf to get the geocode
    df = df.join(
        unnested_regions_lf,
        left_on=[municipality_col, state_col],
        right_on=["synonyms", "parent_name"],
        how="left",
        validate="m:1",
    )

    # Assign 'name' to municipality_col, and 'trase_id' to geocode
    df = df.with_columns(
        pl.col("name").alias(municipality_col), pl.col("trase_id").alias("geocode")
    ).drop("name", "trase_id")

    # In geocode, keep from character 4 onwards
    df = df.with_columns(pl.col("geocode").str.slice(3))

    return df


def run_model(dbt, cursor):

    # get sources, models, and rename fields
    base_tac_lf = (
        dbt.source("source_brazil", "tac_boi_na_linha_com_data").pl().lazy()
    ).unique()
    new_tac_lf = (
        dbt.source("source_brazil", "tac_2023_cycle_updated_2025").pl().lazy()
    ).unique()
    brazil_regions_lf = dbt.ref("postgres_regions_without_geometry").pl().lazy()
    brazil_regions_lf = (
        brazil_regions_lf.filter(
            (pl.col("country") == pl.lit("BRAZIL"))
            & (pl.col("level") == pl.lit(6))
            & (pl.col("trase_id").str.len_chars() == pl.lit(10))
        )
        .select("name", "synonyms", "trase_id", "parent_name")
        .unique()
    )

    base_tac_columns = {
        "Empresa": "company_label",
        "UF": "state_uf",
        "Município": "municipality_label",
        "TAC": "tac",
        "CNPJ": "cnpj",
        "TRASE_ID": "beef_trase_id",
        "Data": "signing_year",
        "Source": "source",
    }

    new_tac_columns = {
        "EMPRESA": "company_label_new",
        "EMPRESA_DPAP": "company_label_dpap",
        "EMPRESA_BNL": "company_label_bnl",
        "ESTADO": "state_uf_bnl",
        "MUNICIPIO": "municipality_label_bnl",
        "PERIODO": "reporting_cycle_year",
        "TAC": "tac",
        "OBSERVACAO": "source_bnl",
    }

    base_tac_lf = base_tac_lf.select(list(base_tac_columns.keys()))
    base_tac_lf = base_tac_lf.rename(base_tac_columns)
    new_tac_lf = new_tac_lf.select(list(new_tac_columns.keys()))
    new_tac_lf = new_tac_lf.rename(new_tac_columns)

    # Add a source file identifier
    base_tac_lf = base_tac_lf.with_columns(
        pl.lit("tac_boi_na_linha_com_data").alias("source_file")
    )
    new_tac_lf = new_tac_lf.with_columns(
        pl.lit("tac_2023_cycle_updated_2025").alias("source_file_new")
    )

    base_tac_lf = base_tac_lf.with_columns(
        pl.col("signing_year").cast(pl.Int32).alias("signing_year")
    )
    # Clean reporting cycle (take last 4 digits and turn to int)
    new_tac_lf = new_tac_lf.with_columns(
        pl.col("reporting_cycle_year")
        .str.slice(-4)
        .cast(pl.Int32)
        .alias("reporting_cycle_year")
    )
    # Filter for signatories and only 2023 reporting cycle (LATER ADD ALL CYCLES)
    new_tac_lf = new_tac_lf.filter((pl.col("tac") == pl.lit("Signatario"))).drop("tac")

    # Clean location information
    state_uf_mapping = {
        "RJ": "RIO DE JANEIRO",
        "MG": "MINAS GERAIS",
        "ES": "ESPIRITO SANTO",
        "SP": "SAO PAULO",
        "RN": "RIO GRANDE DO NORTE",
        "AL": "ALAGOAS",
        "PI": "PIAUI",
        "MA": "MARANHAO",
        "CE": "CEARA",
        "PE": "PERNAMBUCO",
        "SE": "SERGIPE",
        "PB": "PARAIBA",
        "BA": "BAHIA",
        "SC": "SANTA CATARINA",
        "PR": "PARANA",
        "RS": "RIO GRANDE DO SUL",
        "MS": "MATO GROSSO DO SUL",
        "GO": "GOIAS",
        "MT": "MATO GROSSO",
        "DF": "DISTRITO FEDERAL",
        "RO": "RONDONIA",
        "AM": "AMAZONAS",
        "AP": "AMAPA",
        "RR": "RORAIMA",
        "TO": "TOCANTINS",
        "PA": "PARA",
        "AC": "ACRE",
    }

    # Normalize state name
    base_tac_lf = base_tac_lf.with_columns(
        state_name=pl.col("state_uf").replace(state_uf_mapping)
    )
    new_tac_lf = new_tac_lf.with_columns(
        state_name_new=pl.col("state_uf_bnl").replace(state_uf_mapping)
    )

    # Normalize municipality name
    base_tac_lf = base_tac_lf.with_columns(
        municipality_name=pl.col("municipality_label")
    )
    base_tac_lf = normalize_column(base_tac_lf, "municipality_name")
    new_tac_lf = new_tac_lf.with_columns(
        municipality_name_new=pl.col("municipality_label_bnl")
    )
    new_tac_lf = normalize_column(new_tac_lf, "municipality_name_new")

    # Add geocodes
    base_tac_lf = add_geocode(
        base_tac_lf, brazil_regions_lf, "municipality_name", "state_name"
    )
    new_tac_lf = add_geocode(
        new_tac_lf, brazil_regions_lf, "municipality_name_new", "state_name_new"
    )

    # Normalize company names
    base_tac_lf = base_tac_lf.with_columns(company_name=pl.col("company_label"))
    base_tac_lf = normalize_column(base_tac_lf, "company_name")
    new_tac_lf = new_tac_lf.with_columns(company_name_bnl=pl.col("company_label_bnl"))
    new_tac_lf = normalize_column(new_tac_lf, "company_name_bnl")

    # Adjust some names so they match with the base TAC
    company_renames = {
        "ABATEDOURO DE BOVINOS SAMPAIO LTDA": "ABATEDOURO BOVINO SAMPAIO LTDA",
        "FRIGOSUL - FRIGORIFICO SUL LTDA": "FRIGORIFICO SUL LTDA",
        "MATADOURO E FRIGORIFICO TOME-ACU LTDA": "MATADOURO E FRIGORIFICO TOME-ACU LTDA. - EPP/ MATADOURO E FRIFORIFICO AGUA BRANCA",
    }

    new_tac_lf = new_tac_lf.with_columns(
        company_name_bnl=pl.col("company_name_bnl").replace(company_renames)
    )
    # Adjust this record manually as the company_label_bnl one has a line return in it
    new_tac_lf = new_tac_lf.with_columns(
        company_name_bnl=pl.when(
            pl.col("company_label_dpap")
            == pl.lit("ATIVO ALIMENTOS EXPORTADORA E IMPORTADORA")
        )
        .then(pl.lit("ATIVO ALIMENTOS EXP. E IMP. EIRELI"))
        .otherwise(pl.col("company_name_bnl"))
    )

    # Remove records from which we don't have CNPJ data from (i.e. not in the slaughterhouse map, or the GTA data)
    # In particular, FRIGORIFICO SANTA CRUZ LTDA (geocode 1500800) and PROBOI COMERCIO ATACADISTA DE BOVINOS LTDA (geocode 1504208)
    new_tac_lf = new_tac_lf.filter(
        ~(
            (pl.col("company_name_bnl") == pl.lit("FRIGORIFICO SANTA CRUZ LTDA"))
            & (pl.col("geocode") == pl.lit("1500800"))
        )
        & ~(
            (
                pl.col("company_name_bnl")
                == pl.lit("PROBOI COMERCIO ATACADISTA DE BOVINOS LTDA")
            )
            & (pl.col("geocode") == pl.lit("1504208"))
        )
    )
    # Add data of the new TAC to the base TAC with a full join
    base_tac_lf = base_tac_lf.join(
        new_tac_lf,
        left_on=["company_name", "geocode"],
        right_on=["company_name_bnl", "geocode"],
        how="full",
        coalesce=True,
        validate="1:1",
    )

    # Turn all 'tac' with 'S' or null to true
    base_tac_lf = base_tac_lf.with_columns(
        pl.when(pl.col("tac").is_null() | (pl.col("tac") == "S"))
        .then(pl.lit(True))
        .otherwise(pl.lit(False))
        .alias("tac")
    )

    # For companies of the new TAC that are not in the base TAC, we manually add the CNPJ,
    # which is taken from the slaughterhouse logistics map and GTA data, based on manual searches
    # where geocode match but have slight name variatons.
    # Using 'company_name_bnl' as name reference, and adding year and source description if found in https://www.boinalinha.org/publicacoes/
    logistics_map_records = [
        ("A. M SANTOS LTDA", "1200203", "9057339000107", None, None),
        (
            "C CARVALHO DE SOUZA - CCML FRIGORIFICO",
            "1200302",
            "3238170000105",
            None,
            None,
        ),
        (
            "COOPERFRIGU – COOP. DOS PRODUTORES DE CARNE E DERIVADOS DE GURUPI",
            "1709500",
            "2964051000169",
            None,
            None,
        ),
        ("CORREIA & MOURA LTDA", "1200203", "21952943000194", None, None),
        (
            "FALCAO INDUSTRIA DE ALIMENTOS LTDA",
            "1300706",
            "11958002000104",
            2024,
            "Listed in https://www.boinalinha.org/publicacoes/  under 'REFRIGERATOR FRIGORACA/ Falcão Food Industry LTDA: TAC Document (05/16/2024)'. TAC pdf here: https://www.boinalinha.org/wp-content/uploads/2024/07/Frigoraca_TAC.pdf",
        ),
        (
            "FALCAO INDUSTRIA DE ALIMENTOS LTDA",
            "1301852",
            "11958002000538",
            2024,
            "Listed in https://www.boinalinha.org/publicacoes/  under 'REFRIGERATOR FRIGORACA/ Falcão Food Industry LTDA: TAC Document (05/16/2024)'. TAC pdf here: https://www.boinalinha.org/wp-content/uploads/2024/07/Frigoraca_TAC.pdf",
        ),
        ("FRICARNES DISTRIBUIDORA EIRELI", "1200104", "8279380000238", None, None),
        (
            "FRIGORACA AMAZONAS LTDA",
            "1301704",
            "15032861000200",
            2024,
            "Listed in https://www.boinalinha.org/publicacoes/  under 'REFRIGERATOR FRIGORACA/ Falcão Food Industry LTDA: TAC Document (05/16/2024)'. TAC pdf here: https://www.boinalinha.org/wp-content/uploads/2024/07/Frigoraca_TAC.pdf",
        ),
        ("FRIGORIFICO BOI VERDE TK LTDA", "1200609", "51010183000167", None, None),
        ("FRIGORIFICO FRIGORACA LTDA", "1100205", "9675688000184", None, None),
        (
            "FRIGORIFICO RIO MARIA LTDA",
            "1502152",
            "4749233000223",
            2009,
            "Listed in https://www.boinalinha.org/publicacoes/  under 'TAC PA – Rio Maria Cold Storage'. TAC pdf here: https://www.boinalinha.org/wp-content/uploads/2024/08/PA_TAC_Rio_Maria.pdf",
        ),
        ("FRIGORIFICO SANTA CRUZ LTDA", "1501725", "4422772003864", None, None),
        (
            "FTS - FRIGORIFICO TAVARES DA SILVA LTDA",
            "1508407",
            "25264597000374",
            2009,
            "Listed in https://www.boinalinha.org/publicacoes/  under 'TAC PA – Fribev / Tavares da Silva Refrigerator'. TAC pdf here: https://www.boinalinha.org/wp-content/uploads/2024/08/PA_TAC_Tavares_da_Silva.pdf",
        ),
        (
            "INDUSTRIA E COM. DE CARNES E DERIVADOS BOI BRASIL LTDA",
            "1700707",
            "4603630000373",
            2021,
            "Listed in https://www.boinalinha.org/publicacoes/  under 'TO Commitment Term - Boi Brasil'. TAC pdf here: https://www.boinalinha.org/wp-content/uploads/2024/10/Termo-de-Compromisso-TO-Boi-Brasil.pdf",
        ),
        (
            "INDUSTRIA E COM. DE CARNES E DERIVADOS BOI BRASIL LTDA",
            "1702109",
            "4603630000888",
            2021,
            "Listed in https://www.boinalinha.org/publicacoes/  under 'TO Commitment Term - Boi Brasil'. TAC pdf here: https://www.boinalinha.org/wp-content/uploads/2024/10/Termo-de-Compromisso-TO-Boi-Brasil.pdf",
        ),
        (
            "JBS S/A",
            "1702109",
            "2916265009620",
            2021,
            "Listed in https://www.boinalinha.org/publicacoes/  under 'TO - JBS Commitment Term'. TAC pdf here: https://www.boinalinha.org/wp-content/uploads/2024/10/Termo-de-Compromisso-TO-JBS.pdf",
        ),
        (
            "LACERDA ALIMENTOS LTDA",
            "1100205",
            "5467742000145",
            2013,
            "Listed in https://www.boinalinha.org/publicacoes/  under 'TAC RO - Lacerda Refrigerator'. TAC pdf here: https://www.boinalinha.org/wp-content/uploads/2022/08/TAC-RO-Frigorifico-Lacerda.pdf",
        ),
        (
            "LKJ – FRIGORIFICO LTDA",
            "1702109",
            "21393000000179",
            2021,
            "Listed in https://www.boinalinha.org/publicacoes/  under 'TO - LKJ Commitment Term'. TAC pdf here: https://www.boinalinha.org/wp-content/uploads/2024/10/Termo-de-Compromisso-TO-LKJ.pdf",
        ),
        (
            "MINERVA INDUSTRIA E COMERCIO DE ALIMENTOS S/A",
            "1100288",
            "67620377006236",
            2021,
            "Listed in https://www.boinalinha.org/publicacoes/  under 'TO Commitment Term - Minerva'. TAC pdf here: https://www.boinalinha.org/wp-content/uploads/2024/10/Termo-de-Compromisso-TO-Minerva.pdf",
        ),
        (
            "MINERVA INDUSTRIA E COMERCIO DE ALIMENTOS S/A",
            "5105622",
            "67620377008018",
            None,
            None,
        ),
        (
            "MINERVA INDUSTRIA E COMERCIO DE ALIMENTOS S/A",
            "5106307",
            "67620377007470",
            None,
            None,
        ),
        ("MINERVA", "1702109", "67620377001862", None, None),
        (
            "PLENA ALIMENTOS S/A",
            "1716109",
            "10198974000185",
            2021,
            "Listed in https://www.boinalinha.org/publicacoes/  under 'TO Commitment Term - Plena Alimentos'. TAC pdf here: https://www.boinalinha.org/wp-content/uploads/2024/10/Termo-de-Compromisso-TO-Plena-Alimentos.pdf",
        ),
        ("VALE DO ARAGUAIA CARNE LTDA", "5106257", "35811606000191", None, None),
    ]

    # Add companies from the new tac, found in the GTA records
    gta_records = [
        (
            "FRIGORIFICO SANTAREM LTDA- EPP",
            "1506807",
            "6172948000100",
            2011,
            "Listed in https://www.boinalinha.org/publicacoes/  under 'TAC PA – Frigosan/ Refrigerator Santarém'. TAC pdf here: https://www.boinalinha.org/wp-content/uploads/2024/08/PA_TAC_FRIGOSAN_FRIGORIFICO_SANTAREM.pdf",
        ),
    ]

    manually_added_records = pl.DataFrame(
        logistics_map_records + gta_records,
        schema=[
            "company_name_bnl",
            "geocode",
            "cnpj_manual",
            "signing_year_manual",
            "source_manual",
        ],
    ).lazy()

    base_tac_lf = base_tac_lf.join(
        manually_added_records,
        left_on=["company_name", "geocode"],
        right_on=["company_name_bnl", "geocode"],
        how="left",
        validate="m:1",
    )

    # Take relevant information from the manually added records
    base_tac_lf = base_tac_lf.with_columns(
        cnpj=pl.when(pl.col("cnpj").is_null())
        .then(pl.col("cnpj_manual"))
        .otherwise(pl.col("cnpj")),
        signing_year=pl.when(pl.col("signing_year").is_null())
        .then(pl.col("signing_year_manual"))
        .otherwise(pl.col("signing_year")),
        source=pl.when(~pl.col("source_manual").is_null())
        .then(pl.col("source_manual"))
        .otherwise(pl.col("source")),
    ).drop("cnpj_manual", "signing_year_manual", "source_manual")
    base_tac_lf = base_tac_lf.with_columns(cnpj=pl.col("cnpj").str.zfill(14))

    # Where company_label, state_uf, municipality_label, beef_trase_id are null, take the new ones
    base_tac_lf = base_tac_lf.with_columns(
        company_label=pl.when(pl.col("company_label").is_null())
        .then(pl.col("company_label_new"))
        .otherwise(pl.col("company_label")),
        state_name=pl.when(pl.col("state_name").is_null())
        .then(pl.col("state_name_new"))
        .otherwise(pl.col("state_name")),
        municipality_name=pl.when(pl.col("municipality_name").is_null())
        .then(pl.col("municipality_name_new"))
        .otherwise(pl.col("municipality_name")),
        state_uf=pl.when(pl.col("state_uf").is_null())
        .then(pl.col("state_uf_bnl"))
        .otherwise(pl.col("state_uf")),
        municipality_label=pl.when(pl.col("municipality_label").is_null())
        .then(pl.col("municipality_label_bnl"))
        .otherwise(pl.col("municipality_label")),
        source=pl.when(pl.col("source").is_null())
        .then(pl.col("source_bnl"))
        .otherwise(pl.col("source")),
        source_file=pl.when(pl.col("source_file").is_null())
        .then(pl.col("source_file_new"))
        .otherwise(pl.col("source_file")),
        beef_trase_id=pl.when(pl.col("beef_trase_id").is_null())
        .then(pl.lit("BR-BEEF-SLAUGHTERHOUSE-") + pl.col("cnpj"))
        .otherwise(pl.col("beef_trase_id")),
    ).drop(
        "company_label_new",
        "company_label_dpap",
        "company_label_bnl",
        "state_name_new",
        "municipality_name_new",
        "state_uf_bnl",
        "municipality_label_bnl",
        "source_bnl",
        "source_file_new",
    )

    base_tac_lf = base_tac_lf.select(
        "company_name",
        "company_label",
        "cnpj",
        "geocode",
        "state_name",
        "municipality_name",
        "signing_year",
        "tac",
        "municipality_label",
        "state_uf",
        "beef_trase_id",
        "reporting_cycle_year",
        "source",
        "source_file",
    ).unique()

    return base_tac_lf


def model(dbt, cursor):
    import traceback

    dbt.config(materialized="external")

    # Encapsuling in try/except to print the full traceback in case of error
    # When debugging, don't use Polars lazy data loading, as it will not show the traceback
    try:
        new_tac = run_model(dbt, cursor)
    except Exception as e:
        # Print a full traceback
        traceback.print_exc()
        raise
    return new_tac