npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

parser-de-notas-de-corretagem

v0.10.226

Published

Parse Brazilian brokerage notes PDFs (Rico, Clear, and Inter holders available)

Downloads

3,218

Readme

Parse Brazilian brokerage notes PDFs (Rico, Clear, and Inter holders available)

npm CI Assets auto update

Easing the PITA of making IRPF. Inter support only v0.8.0 onwards ❗

Note: This is a JS/TS package. If you want the end-user solution, check the Leitor de notas de corretagem

Example result

The price and average fields already include the fees paid

[
  {
    "number": "11111",    // Brokerage note number
    "buyTotal": "4054.58",
    "sellTotal": "0.00",
    "buyFees": "1.24",
    "sellFees": "0.00",
    "fees": "1.24",
    "date": "02/02/2022", // Can also output in yyyy-MM-dd format changing `NoteParser.dateFormat`
    "holder": "rico",
    "deals": [
      {
        "type": "buy",
        "code": "FLRY3",
        "quantity": 62,
        "average": "16.30",
        "price": "1010.91",
        "date": "02/02/2022",
        "cnpj": "60.840.055/0001-31",
        "isFII": false
      },
      {
        "type": "buy",
        "code": "ALZR11",
        "quantity": 5,
        "average": "112.80",
        "price": "564.02",
        "date": "02/02/2022",
        "cnpj": "28.737.771/0001-85",
        "isFII": true
      },
      {
        "type": "buy",
        "code": "HGRU11",
        "quantity": 5,
        "average": "112.03",
        "price": "560.17",
        "date": "02/02/2022",
        "cnpj": "29.641.226/0001-53",
        "isFII": true
      },
      {
        "type": "buy",
        "code": "VISC11",
        "quantity": 15,
        "average": "97.38",
        "price": "1460.69",
        "date": "02/02/2022",
        "cnpj": "17.554.274/0001-25",
        "isFII": true
      },
      {
        "type": "buy",
        "code": "XPML11",
        "quantity": 5,
        "average": "91.76",
        "price": "458.79",
        "date": "02/02/2022",
        "cnpj": "28.757.546/0001-00",
        "isFII": true
      }
    ]
  }
]

Install

npm i parser-de-notas-de-corretagem

Usage

Full NodeJS example

import fs from 'fs';
import path from 'path';
import { Deal, NoteParser, type NegotiationNote } from 'parser-de-notas-de-corretagem';

async function main() {

  console.log(`Leitor de Notas de Negociação - GNU GPLv3`);

  const assets = new NoteParser();
  try {

    // Get all negotiation notes inside a PDF, even with password
    const possiblePDFpasswords: string[] = ['123', '456'];
    let pdfPath = path.join(__dirname, 'note.pdf');
    let parseResult: NegotiationNote[]
    try {
      parseResult = await assets.parseNote(path.basename(pdfPath), fs.readFileSync(pdfPath), possiblePDFpasswords);
    } catch (error: unknown) {
      if (error instanceof UnknownAsset) {
        console.log(`Unknown asset found: ${error.asset}`)
        // Ignore unknown assets and parse again. Unknown assets will have `code` as `UNDEF: <name>`
        parseResult = await assets.parseNote(path.basename(pdfPath), fs.readFileSync(pdfPath), possiblePDFpasswords, true);
      } else throw error
    }

    // Merge all negotiation notes
    let allDeals: Deal[][] = [];
    parseResult.forEach(note => {
      note.deals.forEach(deal => {
        let index = allDeals.findIndex(el => el.some(subEl => subEl.code === deal.code));
        if (index === -1) {
          allDeals.push([deal]);
        } else {
          allDeals[index].push(deal);
        }
      })
    })

    // Generate a .csv result
    let result: string = `Código\tCNPJ\tData\tC/V\tQuantidade\tPreço+custos\n`;
    allDeals.forEach(asset => {
      asset.forEach(deal => {
        result += `${deal.code}\t${deal.cnpj}\t${deal.date}\t${deal.type=='buy'?'C':'V'}\t${deal.quantity}\t${deal.price.replace(/\./g, ',')}\n`;
      })
      result += `\n`;
    });

    fs.writeFileSync(path.join(__dirname, '..', '..', 'Resultado.csv'), result);

    console.log(`Todas as ${parseResult.length} notas foram processadas`);
    console.log(`O arquivo "Resultado.csv" foi gerado no diretório atual.`);

  } catch (error) {
    console.log(error);
  }
}

main();

Browser

Since only Uint8Array is accepted, use the following code to convert a string using the browser

if (typeof fileContent === 'string') fileContent = Uint8Array.from(fileContent, x => x.charCodeAt(0));
await assetsParser.parseNote(filePath, fileContent, filePasswords);

Add a custom stock

There are many assets out there and some of them (like funds) are kind of hard to keep track. If some asset is not recognized, parseNote will throw the error UnknownAsset

const assets = new NoteParser();
try {
  await assets.parseNote(filePath, fileContent, filePasswords)
} catch (error) {
  if (error instanceof UnknownAsset) {
    console.log(`Unknown asset found: ${error.asset}`)
  } else console.log(error)
}

One can parse the note ignoring this error by passing continueOnError as true. Unknown assets will have the code UNDEF: <name> whereas the <name> is the name of the asset as in the note.

const assets = new NoteParser();
await assets.parseNote(filePath, fileContent, filePasswords, true)

For unknown assets to be properly parsed, one can add custom stocks with .defineStock

const assets = new NoteParser();
// Old stocks aren't available by default, but you can add them.
// CNPJ as the third argument is optional
assets.defineStock('BIDI3', 'BANCO INTER ON');
assets.defineStock('BIDI11', 'BANCO INTER UNT');
// Some codes can appear with multiple names. Add as many as needed
assets.defineStock('KDIF11', 'KINEA INFRAF FIDC', '26.324.298/0001-89');
assets.defineStock('KDIF11', 'FDC KINEAINF FIDC', '26.324.298/0001-89');
// Backward compatible with the below too
assets.defineStock('KDIF11_2', 'FDC KINEAINF FIDC', '26.324.298/0001-89');

P.S

  • Total values include fees
  • The values can deviate from cents. It's always a good call to double-check if the result is as expected. Check the License
  • Inter broker has only a few tests, so please open Issues if you find something wrong
  • Local auto-update isn't persistent. New releases are done everyday with persistent updates
  • Other brokers may work with the internal PDF architecture is the same as the supported brokers

Contributors

Thanks to whom sent the notes for the tests ❤️. Personal data is not stored neither used on tests, only the notes' content.

Thanks? U welcome

Consider thanking me: send a "Thanks!" 👋 by PIX 😊

a09e5878-2355-45f7-9f36-6df4ccf383cf

License

As license, this software is provided as is, free of charge, without any warranty whatsoever. Its author is not responsible for its usage. Use it by your own risk.

GNU GPLv3