use std::path::Path;
use crate::datasets::sec::error::Result;
use crate::datasets::sec::parsers::form4::Form4;
use super::super::identity::Identities;
use super::super::provenance::Provenance;
use super::super::sinks::{write_info_row, Sinks};
use super::super::util::{
accession_from_path, format_float, person_nid_from_cik, strip_leading_zeros,
};
use super::FormReport;
pub(crate) fn emit_form4(
f4: &Form4,
path: &Path,
sinks: &mut Sinks,
identities: &mut Identities,
extracted_at: &str,
report: &mut FormReport,
) -> Result<()> {
let issuer_cik = strip_leading_zeros(&f4.issuer_cik);
let reporter_cik = strip_leading_zeros(&f4.reporter_cik);
let person_nid = person_nid_from_cik(&reporter_cik);
let accession = accession_from_path(path).unwrap_or_default();
let document = path
.file_name()
.and_then(|n| n.to_str())
.unwrap_or("")
.to_string();
let prov_base = Provenance::for_filing(
&f4.document_type,
&accession,
&reporter_cik,
&document,
extracted_at,
);
identities.ensure_person(sinks, &person_nid, &f4.reporter_name, &reporter_cik)?;
let mut emit_role = |role_type: &str, title: &str| -> Result<()> {
let role_nid = format!("{}-{}-{}", reporter_cik, issuer_cik, role_type);
write_info_row(
&mut sinks.role,
&[
role_nid.as_str(),
person_nid.as_str(),
issuer_cik.as_str(),
role_type,
title,
"", ],
&prov_base,
)?;
report.rows_written += 1;
Ok(())
};
if f4.is_director {
emit_role("director", "")?;
}
if f4.is_officer {
emit_role("officer", &f4.officer_title)?;
}
if f4.is_ten_percent_owner {
emit_role("ten_pct_owner", "")?;
}
if f4.is_other {
emit_role("other", "")?;
}
for (i, t) in f4.transactions.iter().enumerate() {
let prov = prov_base.clone().with_lot(i);
let nid_base = format!("{}-{}", accession, i);
let total_value = if t.price_per_share > 0.0 && t.shares > 0.0 {
format_float(t.shares * t.price_per_share)
} else {
String::new()
};
let is_derivative_cell = if t.is_derivative { "1" } else { "0" };
let make_row = |direction: &str| -> [String; 14] {
[
format!("{}-{}", nid_base, direction),
person_nid.clone(),
issuer_cik.clone(),
direction.to_string(),
t.security_title.clone(),
t.transaction_date.clone(),
t.transaction_code.clone(),
format_float(t.shares),
format_float(t.price_per_share),
total_value.clone(),
t.direct_indirect.clone(),
is_derivative_cell.to_string(),
String::new(), String::new(), ]
};
match t.acquired_disposed.as_str() {
"A" => {
write_info_row(&mut sinks.insider_transaction, &make_row("purchase"), &prov)?;
report.rows_written += 1;
}
"D" => {
write_info_row(&mut sinks.insider_transaction, &make_row("sale"), &prov)?;
report.rows_written += 1;
}
_ => {
}
}
let holding_row = [
format!("{}-h", nid_base),
person_nid.clone(),
issuer_cik.clone(),
t.security_title.clone(),
t.transaction_date.clone(),
format_float(t.shares_owned_after),
String::new(), t.direct_indirect.clone(),
is_derivative_cell.to_string(),
];
write_info_row(&mut sinks.holding, &holding_row, &prov)?;
report.rows_written += 1;
}
Ok(())
}