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
with data of auditing cycles found in
s3://trase-storage/brazil/beef/indicators/in/2025-02-14-compilacao-tac-ciclo-unificado-aud-2023.csv
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:
- Boi na Linha compiled dataset
- Holly Gibbs Lab data
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 (trueorfalse).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
cnpjentries. - Source attribution must be preserved for each record.
- All original
cnpjvalues 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_datasource.trase_duckdb.source_brazil.tac_2023_cycle_updated_2025model.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