use regex::Regex;
use std::{fmt::Display, sync::LazyLock};
pub fn array_to_vec<T, U, const N: usize>(array: [T; N]) -> Vec<U>
where
U: std::convert::From<T>,
{
array.into_iter().map(T::into).collect()
}
pub fn try_convert<T, U>(slice: &[T]) -> Vec<U>
where
T: Copy,
U: TryFrom<T>,
<U as TryFrom<T>>::Error: Display,
{
slice
.iter()
.map(|&type_t| match U::try_from(type_t) {
Ok(type_u) => type_u,
Err(why) => {
let t = std::any::type_name::<T>();
let u = std::any::type_name::<U>();
panic!("Error converting from {t} to {u}: {why}")
}
})
.collect()
}
pub const CST_ALL: [u16; 99] = {
let mut output = [0; 99];
let mut index: usize = 0;
while index < output.len() {
output[index] = index as u16 + 1;
index += 1;
}
output
};
pub const BASE_CALC_SOMA: [u16; 99] = {
let mut output = [0; 99];
let mut index: usize = 0;
while index < output.len() {
output[index] = (index + 101) as u16;
index += 1;
}
output
};
pub const CST_CREDITO: [u16; 14] = [50, 51, 52, 53, 54, 55, 56, 60, 61, 62, 63, 64, 65, 66];
pub const CST_CREDITO_BASICO: [u16; 7] = [50, 51, 52, 53, 54, 55, 56];
pub const CST_CREDITO_PRESUMIDO: [u16; 7] = [60, 61, 62, 63, 64, 65, 66];
pub const CST_RECEITA_BRUTA: [u16; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 49];
pub const CSTS_NAO_TRIBUTADOS: [u16; 6] = [4, 6, 7, 8, 9, 49];
pub const CODIGO_DA_NATUREZA_BC: [u16; 18] = {
let mut output = [0; 18];
let mut index: usize = 0;
while index < output.len() {
output[index] = (index + 1) as u16;
index += 1;
}
output
};
pub const CFOP_VENDA_DE_IMOBILIZADO: [u16; 3] = [5551, 6551, 7551];
pub const CFOP_DE_EXPORTACAO: [u16; 1026] = {
let mut output = [0; 1026];
let fim_de_exportacao: [u16; 26] = [
1500, 1501, 1503, 1504, 1505, 1506, 2500, 2501, 2503, 2504, 2505, 2506, 3500, 3503, 5500,
5501, 5502, 5503, 5504, 5505, 6500, 6501, 6502, 6503, 6504, 6505,
];
let mut index: usize = 0;
while index < output.len() {
if index < 26 {
output[index] = fim_de_exportacao[index];
} else {
output[index] = (index - 26) as u16 + 7000;
}
index += 1;
}
output
};
pub const PATTERN: &str = r#"(?xi)
# Esta é uma lista com possíveis Receitas Não Operacionais (outras receitas)
# a depender das atividades que constituam objeto da empresa:
Atualiz.*Monet| # Atualização Monetária
Vend.*Imobiliz| # Venda de Imobilizado
Var.*Camb| # Variação Cambial
Desc.*Financ| # Descontos Financeiros
Desc.*Obtido| # Descontos Obtidos
Desp.*N.*Oper| # Despesas Não Operacionais
Rec.*Financ| # Receitas Financeiras
Rec.*N.*Oper| # Receitas Não Operacionais
Outras?\s*Rec| # Outras Receitas (mesmo que Receitas Não Operacionais)
Outras?\s*Desp| # Outras Despesas
Juro| # Juros sobre Capital Próprio
Selic| # Selic é a taxa básica de juros da economia
Hedge
"#;
pub static OUTRAS_RECEITAS_REGEX: LazyLock<Regex> =
LazyLock::new(|| Regex::new(PATTERN).expect("OUTRAS_RECEITAS_REGEX regex inválida!"));
#[cfg(test)]
mod functions {
use super::*;
#[test]
fn find_other_revenues() {
let lines = vec![
"foo bar",
"Atualização Monetária",
"Outras Receitas Operacionais",
"Juros sobre Capital Próprio",
"Descontos",
];
let mut result = Vec::new();
for line in lines {
let find: bool = OUTRAS_RECEITAS_REGEX.is_match(line);
result.push(find);
}
assert_eq!(vec![false, true, true, true, false], result);
}
#[test]
fn get_cst_all_options() {
let csts: Vec<Option<u16>> = array_to_vec(CST_ALL);
println!("csts: {csts:?}");
assert_eq!(csts[0], Some(1));
assert_eq!(csts[98], Some(99));
}
#[test]
fn get_cfop_options() {
let cfops = CFOP_DE_EXPORTACAO.map(Some);
println!("cfops: {cfops:?}");
assert_eq!(cfops[0], Some(1500));
assert_eq!(cfops[26], Some(7000));
}
#[test]
fn convert() {
let nats: Vec<Option<u16>> = CODIGO_DA_NATUREZA_BC.into_iter().map(Some).collect();
println!("nats: {nats:?}");
assert_eq!(nats[0], Some(1));
assert_eq!(nats[17], Some(18));
}
#[test]
fn map_to_option() {
let nats = CODIGO_DA_NATUREZA_BC.map(Some);
println!("nats: {nats:?}");
assert_eq!(nats[0], Some(1));
assert_eq!(nats[17], Some(18));
}
}