#reading #parser #read-write #file #read-file #qicken

qif

library that can read and write QIF (Quicken Interchange File)

1 unstable release

new 0.1.0 Mar 9, 2025

#363 in Database interfaces

Download history 53/week @ 2025-03-04

53 downloads per month

MIT license

62KB
1.5K SLoC

=QIF=

Version
0.1
Author
Bryce Campbell
License
see LICENSE
Description

A rust port of my Swift Library that can read and write QIF files

==Notes==

This crate was created with the aim of bringing QIF support to the CLI version of BCheckbook.

It has been tested on Rust 1.84.1 on macOS 15.3, though it should work on other platforms just fine.

===Version History===

0.1
initial release.

===Limits===

Like the original library I wrote in Swift, this was designed with only noninvestment and noninvoice data in mind.

While implementing them may seem trivial, there are potential conflicts as the QIF prefixes, as found on Wikipedia.

Also, the check number field is assumed to always be numerical.

Even though, there can be other values present in QIF values. This decision was made to keep things simplistic, since the Rust project I plan to use this with only allows numerical input.

===Questions===

  1. Why create this when there is already a parsing crate for rust?

    When I went looking for ways of reading QIF files, I did encounter qif_parser, which many people seem to like.

    However, I could not really use it if I wanted to generate a QIF file, which is what I wanted to do.

    Also, while I could have utilized it for the import functionality, trying to figure out how it worked and would mean I'd just be reimplementing things anyway.

    As such, it felt more worth it to just make it myself.

  2. Does this work the same as your original library, since this is a Rust port?

    While the design is the same, due to a focused need for only single entry components, there are some differences. For example, while my Swift library uses dictionaries, which Rust calls HashMaps, to store different types of QIF details, this port has those same sections as their own fields. This was done because making custom types hashable is not as easy to do in Rust.

    However, things should be just as simple.

  3. Are the QIF files produced here compatible with your iOS and macOS apps that use the original library?

    They should be compatible with the iOS apps when I get around to getting the library updated in the project.

    However, I am having troubles with the macOS app at this time, as there are updates that need to be pushed, but due to issues with third party libraries that would end up making the app unusable, I cannot push those updates out.

    Until the issues on the macOS side can be resolved, I suggest not using the QIF files generated by this library with the macOS GUI application.

===Usage===

To utilize this crate, add either of the following to Cargo.toml:

qif = "0.1"

====Reading====

To read a file, you would do something like this:

use qif::QIF;

fn main() {
let format = Date::DateFormat::MonthDayFullYear;

let qif = QIF::load_from_file("path/to/qif", &format);

if let Some(bank) = qif.bank {
    println!("{}", bank)
}
}

This will attempt to read a file and display details regarding bank transactions.

====Writing to File====

To write QIF data to a file, you would do something like this:

use qif::{ QIF, Section, Transaction };

fn main() {
...
let format = Date::DateFormat::MonthDayFullYear;
let bank_section = Section::builder()
        .set_type("Bank")
        .add_transaction(sam_hill)
        .add_transaction(fake_street)
        .add_transaction(velociraptor_entertainment)
        .build().unwrap();

let qif = QIF::builder()
        .set_field(bank_section)
        .build();

qif.save("path/to/qif", &format).unwrap();
}

This will take the bank transactions and save them to a QIF file.

====Creating a Transaction====

Transactions can be created like this:

use qif::Transaction;

fn main() {
let today = Local::now();

let format = DateFormat::MonthDayFullYear;

let transaction = Transaction::builder()
    .set_date(&today.format(format.chrono_str()).to_string(), &format)
    .set_check_number(1260)
    .set_vendor("Sam Hill Credit Union")
    .set_address("Sam Hill Credit Union")
    .set_category("Opening Balance")
    .set_amount(500.0)
    .set_memo("Open Account")
    .set_status("*")
    .build();
}

The date format above is optional, but it provides a convenience factor in that it houses some default schemes for chrono formats. The example provided above uses the MM/DD/YYYY format, and the status denotes it as reconciled.

====Creating a Split====

Splits can be created like this:

use qif::Split;

fn main() {
let split = Split::builder()
    .set_category("Opening Balance")
    .set_memo("Bonus for new Account")
    .set_amount(50.0)
    .build();
}

By substiting out set_amount for set_amount_via_percentage, you can have the calculations done for you, but you must also pass the original transaction's amount to the function.

Splits are then added to transactions like this:

use qif::{Split, Transaction };

fn main() {
    let transaction = Transaction::builder()
    .set_date(&today.format(format.chrono_str()).to_string(), &format)
    .set_check_number(1260)
    .set_vendor("Sam Hill Credit Union")
    .set_address("Sam Hill Credit Union")
    .set_category("Opening Balance")
    .set_amount(500.0)
    .set_memo("Open Account")
    .set_status("*")
    .add_split(split)
    .build();
}

===Contributing===

If you think you can help out making this even better, feel free to fork this project and make a pull request.

Please keep in mind that I may refuse the request, but if things work as they should, then I will likely accept it.

===Support===

While I have been writing more Rust code than Swift these days, I still do not think I can provide too much support, so you should expect to be on your own.

However, I am willing to check things out, so feel free to contact me at the email below:

tonyhawk2100@gmail.com

Dependencies

~3.5–4.5MB
~76K SLoC