pax_global_header00006660000000000000000000000064136241535140014516gustar00rootroot0000000000000052 comment=0367cdea984ab50bd3eb7dbf4a0fe547811336b2 ledger2beancount-2.0/000077500000000000000000000000001362415351400146025ustar00rootroot00000000000000ledger2beancount-2.0/.appveyor.yml000066400000000000000000000007301362415351400172500ustar00rootroot00000000000000build: false cache: - C:\strawberry environment: PYTHON: 'C:\Python36' install: - if not exist "C:\strawberry" cinst strawberryperl - set PATH=C:\strawberry\perl\bin;C:\strawberry\perl\site\bin;C:\strawberry\c\bin;%PATH% - cd C:\projects\%APPVEYOR_PROJECT_NAME% - cpanm --notest --installdeps . - set PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH% - python -m pip install -U hg+https://bitbucket.org/blais/beancount/ build_script: - cd tests - runtests.bat ledger2beancount-2.0/.editorconfig000066400000000000000000000014201362415351400172540ustar00rootroot00000000000000# EditorConfig: http://EditorConfig.org # top-most EditorConfig file root = true [*] charset = utf-8 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true [Makefile] indent_style = tab [*.bat] indent_size = 4 indent_style = space [*.ledger] indent_size = 4 indent_style = space [*.beancount] indent_size = 2 indent_style = space [tests/accounts.ledger] trim_trailing_whitespace = false [tests/accounts.beancount] trim_trailing_whitespace = false [tests/balance-assertion.beancount] trim_trailing_whitespace = false [tests/hledger.beancount] trim_trailing_whitespace = false [tests/metadata.ledger] trim_trailing_whitespace = false [tests/metadata.beancount] trim_trailing_whitespace = false [tests/spacing.ledger] trim_trailing_whitespace = false ledger2beancount-2.0/.gitignore000066400000000000000000000001101362415351400165620ustar00rootroot00000000000000*-stamp docs/ledger2beancount.1 docs/ledger2beancount.5 docs/manual.pdf ledger2beancount-2.0/.travis.yml000066400000000000000000000006111362415351400167110ustar00rootroot00000000000000dist: xenial language: python python: - "3.6" env: - BEANCOUNT="beancount>=2.1.2" - BEANCOUNT="hg+https://bitbucket.org/blais/beancount/" matrix: allow_failures: - env: BEANCOUNT="hg+https://bitbucket.org/blais/beancount/" addons: apt: packages: - cpanminus - ledger install: - sudo cpanm --notest --installdeps . - pip install $BEANCOUNT script: - make test ledger2beancount-2.0/AUTHORS000066400000000000000000000001071362415351400156500ustar00rootroot00000000000000Stefano Zacchiroli Martin Michlmayr ledger2beancount-2.0/LICENSE000066400000000000000000001045131362415351400156130ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ledger2beancount-2.0/Makefile000066400000000000000000000011511362415351400162400ustar00rootroot00000000000000all: test docs L2C = bin/ledger2beancount TEST_DEPS = $(wildcard tests/*) $(L2C) test: test-stamp test-stamp: $(TEST_DEPS) cd tests && ./runtests touch $@ check: test docs/ledger2beancount.1: docs/ledger2beancount.1.scd scdoc < $< > $@ docs/ledger2beancount.5: docs/ledger2beancount.5.scd scdoc < $< > $@ docs/manual.pdf: docs/manual.md pandoc -f markdown+definition_lists $< -o $@ pdf: docs/manual.pdf man: docs/ledger2beancount.1 docs/ledger2beancount.5 docs: pdf man clean: rm -f test-stamp docs/ledger2beancount.1 docs/ledger2beancount.5 docs/manual.pdf .PHONY: all check clean test pdf man docs ledger2beancount-2.0/README.md000066400000000000000000000102461362415351400160640ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/zacchiro/ledger2beancount.svg?branch=master)](https://travis-ci.org/zacchiro/ledger2beancount) ledger2beancount ================ A script to automatically convert [Ledger](https://www.ledger-cli.org/)-based textual ledgers to [Beancount](http://furius.ca/beancount/) ones. Conversion is based on (concrete) syntax, so that information that is not meaningful for accounting reasons but still valuable (e.g., comments, formatting, etc.) can be preserved. Please [read the manual](docs/manual.md) on how to install, configure and use ledger2beancount. The [supported features](docs/manual.md#features) are documented in the manual, too. Usage ----- ledger2beancount accepts input from `stdin` or from a file and will write the converted data to `stdout`. You can run ledger2beancount like this: ledger2beancount test.ledger > test.beancount Installation ------------ Please see [the manual](docs/manual.md#installation) for dependencies and installation instructions. Features -------- The majority of ledger features are supported by ledger2beancount. Here is an overview of fully supported, partly supported and unsupported features. Please refer to [the manual](docs/manual.md#features) for more details. ### Fully supported * Accounts * Account declarations (`account ...`) * Conversion of invalid account names * Mapping of account names * Directive `apply account` * Account aliases (`alias`) * Balance assignments * Balance assertions * Comments * Comments in and outside of transactions * Directives `comment` and `test` * Commodities * Commodity declarations (`commodity ...`) * Commodity symbols like `$`, `£` and `€` * Commodities placed in front and after the amount * Conversion of invalid commodities * Mapping of commodities * Directives * `bucket` / `A` * `include` * `Year` / `Y`, `apply year` * Flags * State flags (posting flags) * Transaction state (transaction flags) * Inline math * Very simple inline math only * Lots * Lot dates * Lot notes * Per unit and total costs and prices * Conversion of ledger price to beancount cost * Metadata * Payees * Obtain payee from metadata * Split payee into payee and narration * Assign payee based on narration * Tags * Directive `apply tag` * Mapping `#tags` to `^links` ### Partly supported * Amounts * Decimal comma (not supported in beancount) * Dates * Dates on posting-level (no equivalence in beancount) * Auxiliary dates (no equivalence in beancount) * Effective dates (no equivalence in beancount) * Deferred postings (no equivalence in beancount) * Directives * `eval`: skipped (not supported in beancount) * `payee`: skipped (not needed in beancount) * `python`: skipped (not supported in beancount) * `tag`: skipped (not needed in beancount) * `value`: skipped (not supported in beancount) * Fixated prices (`=$10` and the `fixed` directive) * Tags and links on posting-level (not supported by beancount) * Transaction codes: stored as metadata (no equivalence in beancount) * Virtual postings: can be skipped or converted to real postings * Virtual posting costs: recognised but skipped (no equivalence in beancount) ### Not supported * Amounts without commodities * Automated transactions * Directives * `assert` * `C` (commodity equivalences) * `check` * `D` * `define` and `def` * `expr` * `N` * Timeclock (`I`, `i`, `O`, `o`, `b`, `h`) * Periodic transactions Authors ------- * Stefano Zacchiroli `` * Martin Michlmayr `` License ------- This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ledger2beancount-2.0/bin/000077500000000000000000000000001362415351400153525ustar00rootroot00000000000000ledger2beancount-2.0/bin/ledger2beancount000077500000000000000000001301611362415351400205250ustar00rootroot00000000000000#!/usr/bin/env perl # Copyright (C) 2016-2018 Stefano Zacchiroli # (C) 2018-2019 Martin Michlmayr # (C) 2020 Software in the Public Interest, Inc. # License: GNU General Public License (GPL), version 3 or above # convert a ledger-cli main ledger file to beancount format use warnings; use strict; use experimental 'smartmatch'; use utf8; use feature 'unicode_strings'; use open qw/:std :locale/; use Config::Onion; use Date::Calc qw/Add_Delta_Days/; use DateTime::Format::Strptime qw/strftime/; use File::BaseDir qw/config_home/; use Getopt::Long::Descriptive; use POSIX qw/ceil/; use String::Interpolate qw(safe_interpolate); use Unicode::Normalize; my ($opt, $usage) = describe_options( "ledger2beancount %o ", [ "config|c=s", "configuration file", { default => "ledger2beancount.yml" } ], [ "help|h", "print usage message and exit", { shortcircuit => 1 } ], ); print($usage->text), exit if $opt->help; my $config_file = $opt->config; # Config::Onion expects filename without extension die "Config file must end in .yml" unless $config_file =~ s/\.(yml|yaml)$//; my @config_files = ($config_file, config_home('ledger2beancount', 'config')); my $config; foreach my $config_file (@config_files) { $config = Config::Onion->load($config_file); # We don't actually use the Config::Onion feature to load several # config files. We merely use it to set some defaults. last if defined $config; } $config->set_default(date_format => "%Y-%m-%d"); $config->set_default(date_format_no_year => "%m-%d"); $config->set_default(account_open_date => "1970-01-01"); $config->set_default(commodities_date => "1970-01-01"); $config->set_default(payee_tag => ""); $config->set_default(payer_tag => ""); $config->set_default(payee_match => []); $config->set_default(ledger_indent => 4); $config->set_default(beancount_indent => 2); $config->set_default(automatic_declarations => 1); $config->set_default(decimal_comma => 0); $config->set_default(convert_virtual => 0); $config->set_default(commodity_map => {"\$" => "USD", "£" => "GBP", "€" => "EUR", "¥" => "JPY"}); # Make config variables easier to access $config = $config->get; if (ref $config->{payee_match} ne ref []) { die "Config variable payee_match has to be a Yaml list"; } # regular expression snippets used for ledger parsing my $date_RE = qr/\d+[^ =]+/; my $hledger_date_RE = qr#(\d{4}[./-])?\d{1,2}[./-]\d{1,2}#; my $flags_RE = qr/[*!]/; my $txn_header_RE = qr/^(?$date_RE)(=(?$date_RE))?(\s+|$)(?$flags_RE)?(\s*\((?[^)]*)\))?\s*(?.*)/; my $hledger_payee_narration_RE = qr/(?[^|]+?)\s*\|\s*(?.*)/; my $tags_RE = qr/(?[\w:-]+)/; my $hledger_tags_RE = qr/(?[^ ]+:.*)/; # An account can be pretty much anything but it has to be followed by # two spaces, a tab or new line (see $posting_RE). # To keep the regex simpler, we parse the () and [] for virtual accounts # as part of the account name and strip these brackets later. my $account_RE = qr/[^\s;][^\t]*?/; my $value_RE = qr/[\d.,]+/; my $value_exp_RE = qr/$value_RE([\h*\/+-]*$value_RE)?/; # A quoted commodity ("LU0274208692") can contain anything # between quotes. my $commodity_quoted_RE = qr/(["'])(?:(?=(\\?))\g{-1}.)*?\g{-2}/; # An unquoted commodity may not contain certain characters my $commodity_unquoted_RE = qr/(?!-)[^;\s0-9=)("'{}@*\/+,.-]+/; my $commodity_RE = qr/$commodity_quoted_RE|$commodity_unquoted_RE/; # Ledger supports three different amount formats: # [minus] amount commodity my $amount_mnc_RE = qr/(?-?)(?$value_exp_RE)\s*(?$commodity_RE)/; # -10.00 EUR # commodity [minus] amount my $amount_cmn_RE = qr/(?$commodity_RE)\s*(?-?)(?$value_exp_RE)/; # EUR -10.00 # [minus] commodity amount my $amount_mcn_RE = qr/(?-?)(?$commodity_RE)\s*(?$value_exp_RE)/; # -EUR 10.00 my $amount_RE = qr/(?\(?)($amount_mnc_RE|$amount_cmn_RE|$amount_mcn_RE)(\)?)/; my $comment_top_level_RE = qr/[;#%|*]\s?(?.*?)/; my $comment_RE = qr/;\s*(?.*)/; my $metadata_RE = qr/;\s*(?[^\h:][^\h]*?):(?:)?(\s*$|\s+(?.*))/; my $hledger_metadata_RE = qr/(?[^:]+):\s*(?.+)/; my $posting_RE = qr/(?((?$flags_RE)\s+)?(?$account_RE)( | \t|\t|\s*$)\s*(?$amount_RE)?(?\s*;\s*\[(?$date_RE)?(=(?$date_RE))?\])?)/; my $price_RE = qr/^P\s+(?$date_RE)\s+(\d\d:\d\d(:\d\d)?\s+)?(?$commodity_RE)\s+(?.*)/; # Maximum limit for beancount commodities my $BEANCOUNT_COMMODITY_MAX_LEN = 24; my @beancount_root_names = qw/Assets Liabilities Equity Income Expenses/; my @output; # Used to store the output of the script # Store accounts and commodities encountered and declared # value == undef: seen # value == 1: declared my %account_declared; my %commodity_declared; # Store some ledger directives relevant for processing my @ledger_apply; # Capture open "apply" statements my %ledger_alias; # Capture "alias" statements my $ledger_bucket; # Use bucket if there's only one posting # Conversion notes for users from ledger2beancount my @conversion_notes; # Keep track of all ledger accounts and commodities to check for # collisions after remapping is done. my %ledger_accounts; my %ledger_commodities; my %ledger_metadata; # Declarations sub map_commodity($); sub print_tags($@); # indent some content at a given depth in beancount style sub indent($$) { my ($depth, $content) = @_; return ' ' x ($depth * $config->{beancount_indent}) . $content; } sub escape_beancount_string($) { my ($s) = @_; $s =~ s/\\/\\\\/g; $s =~ s/"/\\"/g; return $s; } # return a beancount string literal, with a given content sub mk_beancount_string($) { my ($s) = @_; return '"' . escape_beancount_string($s) . '"'; } # Print a date in ISO 8601 format (YYYY-MM-DD) sub pp_date($$) { my ($date_str, $year) = @_; my $date; my $date_complete = DateTime::Format::Strptime->new( pattern => $config->{date_format}, on_error => "undef", ); $date = $date_complete->parse_datetime($date_str); if ($date) { return strftime("%F", $date); } elsif (length $date_str >= 6) { die "Can't parse date $date_str (set date_format and date_format_no_year)"; } my $date_no_year = DateTime::Format::Strptime->new( pattern => $config->{date_format_no_year}, on_error => "undef", ); $date = $date_no_year->parse_datetime($date_str); if ($date) { if ($year) { $date->set_year($year); return strftime("%F", $date); } else { die "Date without year but no Y/year directive: $date_str"; } } else { die "Can't parse date $date_str (set date_format_no_year)"; } } # parse a ledger value. Usually to extract "semantic" values from typed # metadata sub parse_ledger_value($) { my ($raw) = @_; my $value; if ($raw =~ /^\[(?$date_RE)\]$/) { $value = pp_date $+{date}, 0; } else { $value = $raw; } return $value; } # Return the commodity from an amount sub parse_commodity($) { my ($amount) = @_; return $+{commodity} if $amount =~ /$amount_RE/; } # Simple parsing state machine: we need to look ahead for payee metadata, as in # beancount they appear on the first line of a transaction, whereas in ledger # they appear as a regular metadata ("x-payee"). The following functions # support the parsing state machine for this: my ($in_txn, $in_postings, %cur_txn_header, @cur_txn_lines, @cur_txn_assertions, @cur_txn_tags, @cur_txn_meta); # reset current parsing state, reinitializing it to the empty state sub reset_cur_txn() { $in_txn = 0; # whether we are currently in a txn block $in_postings = 0; # whether we are currently within postings (i.e., past txn metadata) %cur_txn_header = (); # txn header, i.e., its first line @cur_txn_lines = (); # txn lines, i.e., all lines except the header @cur_txn_assertions = (); # balance assertions related to txn @cur_txn_tags = (); # posting tags @cur_txn_meta = (); # posting metadata } reset_cur_txn(); # pretty print the transaction header (i.e., its first line) in beancount # format sub pp_cur_header() { my $buf = ""; $buf .= $cur_txn_header{date} . " "; $buf .= $cur_txn_header{flag} . " "; if (exists $cur_txn_header{payee}) { $buf .= (mk_beancount_string $cur_txn_header{payee}) . " "; } $buf .= mk_beancount_string $cur_txn_header{narration}; if (exists $cur_txn_header{comment}) { $buf .= " ; " . $cur_txn_header{comment}; } if (exists $cur_txn_header{tags}) { $buf .= $cur_txn_header{tags}; } return $buf; } # pretty print subsequent lines (all but the first) of a transaction, in # beancount format sub pp_cur_lines() { return (join "\n", @cur_txn_lines) . "\n"; } # pretty print pending balance assertions, in beancount format sub pp_cur_assertions() { return (join "\n", @cur_txn_assertions) . "\n"; } # pretty print a single metadata key/value pair, in beancount format sub pp_metadata($$) { my ($key, $value) = @_; return "$key: $value"; } # Print an amount ([minus] value commodity) sub pp_amount($$$$) { my ($minus, $value, $commodity, $inline_math) = @_; if ($config->{decimal_comma}) { $value =~ s/\.//g; $value =~ s/,/./; # issue #204 } # ledger allows amounts without a leading zero (e.g. 0.10) but # beancount doesn't. $value = "0$value" if $value =~ /^[\.,]/; return sprintf "%s%s%s%s %s", $inline_math ? "(" : "", $minus =~ "^-" ? "-" : "", $value, $inline_math ? ")" : "", map_commodity $commodity; } # check if a tag should be a link based on link_match sub is_link($) { my ($key) = @_; return 1 if $key =~ /^\^/; foreach my $link_RE (@{$config->{link_match}}) { return 1 if $key =~ /$link_RE/; } return 0; } # format string according to whether it should be a link or a tag sub pp_tag_link(@) { my ($key) = @_; if ($key =~ /^\^/) { return $key; } elsif (is_link $key) { return "^" . $key; } else { return "#" . $key; } } # pretty print in-transaction tags, in beancount format sub pp_tags(@) { my @tags = @_; return join(' ', map pp_tag_link($_), @tags); } # dump the current parsing state to stdout. Used for debugging purposes only sub dump_cur_txn() { if ($in_txn) { print "D: cur_header: " . pp_cur_header() . "\n"; print "D: cur_lines_begin\n"; print pp_cur_lines(); print "D: cur_lines_end\n"; } else { print "D: no txn\n"; } } # set the current transaction header (= first line), overriding the previous # value (which should *usually* be empty, but it is the caller responsibility # to ensure this is the case) sub push_header($$$) { my ($date, $flag, $narration) = @_; $in_txn = 1; $cur_txn_header{date} = $date; $cur_txn_header{flag} = $flag; $cur_txn_header{narration} = $narration; } # set the current transaction payee, complementing the transaction header sub push_payee($) { my ($payee) = @_; $cur_txn_header{payee} = $payee; } # add a transaction line. Call this multiple times to accumulate lines that will # be emitted as soon as the transaction is over sub push_line($$) { my ($depth, $line) = @_; push @cur_txn_lines, indent($depth, $line); } # add a balance assertion to be published at the end of current transaction sub push_assertion($$) { my ($account, $amount) = @_; # beancount evaluates balance assertions at the beginning of the day, # whereas ledger evaluates them at the end of the txn. So we schedule the # balance assertion for *after* the original txn. This assumes that there # are no *other* txn in the same day that change the balance again. my $assertion_date = sprintf("%04d-%02d-%02d", Add_Delta_Days(split(/-/, $cur_txn_header{date}), 1)); push @cur_txn_assertions, "$assertion_date balance $account $amount"; } # add a metadata line. Wrapper around push_line() for metadata sub push_metadata($$$) { my ($depth, $key, $value) = @_; push_line $depth, pp_metadata($key, $value); } # add a comment line. Wrapper around push_line() for comments sub push_comment($$) { my ($depth, $comment) = @_; push_line $depth, "; $comment"; } sub push_deferred_meta($) { my ($depth) = @_; foreach (@cur_txn_meta) { push_line $depth, $_; } @cur_txn_meta = (); } # Handle metadata sub handle_metadata($$$) { my ($depth, $metadata, $defer) = @_; my $key = map_metadata($metadata->{key}); if (not $in_postings and ($key eq $config->{payee_tag} or $key eq $config->{payer_tag})) { # ASSUMPTION: payer_tag always occurs later than payee_tag, which # is currently enforced in our ledger. This is to guarantee that we # promote payers to payees, because that's the sensible thing to do # with Beancount push_payee $metadata->{value}; } else { # Check if we should store as metadata or as links # We check for $in_postings since posting-level links are not allowed if (lc $key ~~ [ map lc $_, @{$config->{link_tags}} ] && !$in_postings) { print_tags $depth, "^$metadata->{value}"; } else { # Metadata values can be empty my $value = $metadata->{value} ? $metadata->{value} : ""; if (defined($metadata->{typed})) { $value = parse_ledger_value $value; } else { $value = mk_beancount_string $value; } if ($defer) { push @cur_txn_meta, pp_metadata($key, $value); } else { push_metadata $depth, $key, $value; } } } } # Process hledger tags # hledger tags can have values (metadata) or not (tags) sub handle_hledger_tags($$$) { my ($depth, $l, $defer) = @_; # hledger doesn't know the ledger :foo:bar: syntax. However, this # is parsed as tag "foo" (without the colon!) with value "bar:". $l =~ s/^://; foreach $_ (split /\s*,\s*/, $l) { if (/$hledger_metadata_RE/) { if ($+{key} eq "date" || $+{key} eq "date2") { my $key = $+{key}; my $date = $+{value}; my $year = $1 if $cur_txn_header{date} =~ /^(\d{4})-/; if ($date !~ /^$hledger_date_RE/) { die "Can't parse date after hledger tag $key: $date"; } if (defined $config->{postdate_tag} && $key eq "date") { push @cur_txn_meta, pp_metadata $config->{postdate_tag}, pp_date $date, $year; } if (defined $config->{auxdate_tag} && $key eq "date2") { push @cur_txn_meta, pp_metadata $config->{auxdate_tag}, pp_date $date, $year; } push_deferred_meta $depth if !$defer; } else { handle_metadata $in_postings ? 2 : 1, \%+, $defer; } } else { s/:$//; # The $in_postings check is a workaround since there are no posting-level tags if ($defer || $in_postings) { push @cur_txn_tags, $_; } else { print_tags $depth, $_; } } } } # Process comments; in particular, look for tags # Returns the comment (after stripping tags) sub handle_comment($$$) { my ($depth, $l, $defer) = @_; if ($config->{hledger} && $l =~ /;\s*(?.*?)$hledger_tags_RE/) { handle_hledger_tags $depth, $+{tags}, $defer; return $+{comment}; } elsif ($l =~ /^$metadata_RE/) { # metadata comment handle_metadata $in_postings ? 2 : 1, \%+, $defer; return; } elsif ($l =~ /^$comment_RE\s+:$tags_RE:\s*$/ or $l =~ /^;\s+:$tags_RE:\s+(?.*)$/) { # tags comment # The $in_postings check is a workaround since there are no posting-level tags if ($defer || $in_postings) { push @cur_txn_tags, split /:/, $+{tags}; } else { print_tags $depth, split /:/, $+{tags}; } return $+{comment}; } elsif ($l =~ /^$comment_RE/) { # (every other) comment return $+{comment}; } else { die "Can't process comment: $l"; } } # return a pretty printed transaction, resetting the current parsing state. This # is usually called as soon as the end of a transaction (usually an empty line) # is encountered sub pop_txn() { my $buf = ""; $buf .= pp_cur_header() . "\n"; $buf .= pp_cur_lines(); $buf .= "\n" . pp_cur_assertions() if @cur_txn_assertions; reset_cur_txn(); return $buf; } # map a (ledger) metadata key to the desired (beancount) metadata key. Relies # on the config variable metadata_map # Beancount syntax: "Keys must begin with a lowercase character from a-z and # may contain (uppercase or lowercase) letters, numbers, dashes and # underscores." sub map_metadata($) { my ($key) = my ($ledger_key) = @_; # For backwards compatibility with older ledger2beancount configs $key = $config->{metadata_map}{lc $key} if exists $config->{metadata_map}{lc $key}; $key = $config->{metadata_map}{$key} if exists $config->{metadata_map}{$key}; $key = lcfirst $key; # Make first letter lowercase $key =~ s/^([^\p{letter}])/x$1/; # Make sure first character is a letter $key .= "x" if length $key == 1; # Work around lack of Unicode support (beancount #161) $key = NFKD $key; $key =~ s/\p{NonspacingMark}//g; $key =~ s/[^a-zA-Z0-9_-]/-/g; # Replace disallowed characters $key = $config->{metadata_map}{$key} if exists $config->{metadata_map}{$key}; # payee_tag and payer_tag don't show up in the beancount file, so # no need to warn about them. if ($key ne $config->{payee_tag} and $key ne $config->{payer_tag}) { $ledger_metadata{$ledger_key} = 1; } return $key; } # Apply any "apply account" statements to the account sub map_account_apply($) { my ($account) = @_; foreach my $a (reverse @ledger_apply) { if (${$a}[0] eq "account") { ${$a}[1] =~ s/:+$//; $account = ${$a}[1] . ":" . $account; } } return $account; } # map a ledger account to a beancount account # ledger account: can be pretty much anything, as long as it's followed # by two spaces, a tab or the end of the line. # beancount accounts: "account names begin with a capital letter or a # number and are followed letters, numbers or dash (-) characters. All # other characters are disallowed." (Letters and numbers may be UTF-8) sub map_account($) { my ($account) = my ($ledger_account) = @_; if (exists $ledger_alias{$account}) { $account = $ledger_alias{$account}; } else { $account = map_account_apply $account; } $ledger_accounts{$account} = 1; # Map accounts according to the config $account = $config->{account_map}{$account} if exists $config->{account_map}{$account}; foreach $_ (sort keys %{$config->{account_regex}}) { if ($account =~ s/$_/safe_interpolate($config->{account_regex}{$_})/eg) { $config->{account_map}{$ledger_account} = $account; last; } } # Ensure account names are valid in beancount $account =~ s/(^|:)(\p{lower})/$1\U$2\E/g; # Make first letter uppercase $account =~ s/(^|:)[^\p{letter}\p{number}]/$1X/g; # Make sure first character is a letter or number $account =~ s/[^\p{letter}\p{number}:-]/-/g; # Replace disallowed characters $account =~ s/:+$//g; # Ensure account doesn't end in a colon; this is unusual but legal in ledger $account = $config->{account_map}{$account} if exists $config->{account_map}{$account}; my $root = $1 if $account =~ /([^:]+)/; # beancount doesn't allow just a root account (e.g. Income) as an # account name. It has to be Income:Subaccount if ($account eq $root) { print_warning_once("Account $account not allowed; it needs a subaccount, e.g. $account:Subaccount"); $account .= ":Subaccount"; } if (!($root ~~ @beancount_root_names)) { print_warning_once("Non-standard root name $root used; please set beancount options name_*"); } $account_declared{$account} = undef if not defined $account_declared{$account}; return $account; } # Replace ledger account names with corresponding beancount account names # while trying to keep the whitespace intact by padding where necessary. sub replace_account($) { my ($l) = @_; if ($l =~ /^$posting_RE/) { my $old = $+{account}; my $new = map_account $old; if ($l !~ s/\Q$old\E$/$new/) { if (length($new) <= length($old)) { $new .= " "x abs(length($new) - length($old)); $l =~ s/\Q$old\E/$new/; } else { my $orig_old = $old; $old .= " "x (length($new) - length($old)); # Ensure there are two spaces or a tab after the account name return $l if $l =~ s/\Q$old\E /$new /; return $l if $l =~ s/\Q$old\E\t/$new\t/; # We can't preserve space return $l if $l =~ s/\Q$orig_old\E/$new/; } } return $l; } else { die "Not a posting: $l"; } } # map a ledger commodity to a beancount commodity # beancount commodity: up to 24 characters long, beginning with a capital # letter and ending with a capital letter or a number. The middle # characters may include "_-'." sub map_commodity($) { my ($commodity) = @_; $ledger_commodities{$commodity} = 1; $commodity = $config->{commodity_map}{$commodity} if exists $config->{commodity_map}{$commodity}; $commodity =~ s/(^")|("$)//g; # Check again after removing the quote $commodity = $config->{commodity_map}{$commodity} if exists $config->{commodity_map}{$commodity}; $commodity = substr (uc $commodity, 0, $BEANCOUNT_COMMODITY_MAX_LEN); # Work around lack of Unicode support (beancount #161) $commodity = NFKD $commodity; $commodity =~ s/\p{NonspacingMark}//g; # Dash (-) is not valid in ledger (even with quoted commodity) but valid # in beancount $commodity =~ s/[^a-zA-Z0-9_'.-]/-/g; # Replace disallowed characters $commodity =~ s/^[^\p{letter}]/X/g; # Make sure first character is a letter $commodity =~ s/[^\p{letter}\p{number}]$/X/g; # Make sure last character is a letter or number $commodity .= "X" if length $commodity == 1; $commodity = $config->{commodity_map}{$commodity} if exists $config->{commodity_map}{$commodity}; $commodity_declared{$commodity} = undef if not defined $commodity_declared{$commodity}; return $commodity; } # Replace commodity in string with beancount commodity # Also rewrites the amounts from the various formats supported in ledger # to [minus] amount commodity sub replace_commodity($) { my ($s) = @_; if ($s =~ /( |\t|\t )$amount_RE/) { $s =~ s/( |\t|\t )$amount_RE/$1@{[pp_amount $+{minus}, $+{num}, $+{commodity}, $+{inline_math}]}/; } elsif ($s =~ /$amount_RE/) { $s =~ s/$amount_RE/@{[pp_amount $+{minus}, $+{num}, $+{commodity}, $+{inline_math}]}/; } return $s; } # emit a single line sub print_line($$) { my ($depth, $line) = @_; push @output, indent($depth, $line), "\n"; } # emit a top-level comment: the comment marker ; is put as the first # character and the rest is indented according to depth. sub print_comment_top_level($$) { my ($depth, $comment) = @_; if (!$comment) { push @output, ";\n"; } else { push @output, "; ", indent($depth, $comment), "\n"; } } # Add warning to output file sub print_warning($) { my ($warning) = @_; push @conversion_notes, $warning; } # Add warning to output file, but only once sub print_warning_once($) { my ($warning) = @_; push @conversion_notes, $warning if !($warning ~~ @conversion_notes); } # Strip indentation from a line and return the depth and line sub strip_indentation($) { my ($line) = @_; chomp $line; # handle line indentation once and for all $line =~ /^(?\s*)(?.*)/; my $depth = ceil(length($+{indent}) / $config->{ledger_indent}); # round up with ceil() because we mix 4 (postings) and 2 (posting tags) indent in ledger return ($depth, $+{line}); } sub print_tags($@) { my ($depth, @ledger_tags) = @_; return if not scalar @ledger_tags; my @tags = grep {!is_link $_} @ledger_tags; my @links = grep {is_link $_} @ledger_tags; if (!$in_postings) { $cur_txn_header{tags} .= "\n" . indent $depth, pp_tags @ledger_tags; } else { # XXX workaround for the fact that per-posting tags are currently not # allowed. See: # https://groups.google.com/forum/#!topic/beancount/XPtFOnqCVws push_line $depth, "tags: \"" . join(', ', @tags) . "\"" if @tags; push_line $depth, "links: \"" . join(', ', @links) . "\"" if @links; } } # Process a ledger transaction sub process_txn(@) { my @txn = @_; # Count total postings and postings that have amounts. This is needed # to distinguish different kinds of balance assignments. my $total_postings = 0; my $postings_with_amount = 0; my @accounts; foreach my $l (@txn) { my ($depth, $l) = strip_indentation($l); if ($l =~ /^$posting_RE/) { $total_postings++; $postings_with_amount++ if $+{amount}; push @accounts, $+{account}; } } foreach my $l (@txn) { # print "D: line: ", "\n"; dump_cur_txn(); print "\n"; (my $depth, $l) = strip_indentation($l); if ($l =~ /^$comment_RE/) { my $comment = handle_comment $depth, $l, 0; push_comment $depth, $comment if $comment; } elsif ($l =~ /^$posting_RE/) { print_tags $depth+1, @cur_txn_tags; @cur_txn_tags = (); my $account = $+{account}; # Check for virtual and deferred accounts if ($account =~ /^\(/) { # Ignore virtual postings with parentheses print_warning_once "Virtual posting in parentheses ignored"; next; } elsif ($account =~ /^\[(.*)\]/) { if ($config->{convert_virtual}) { $account = $1; $l =~ s/\Q[$account]\E/$account /; # Make them real } else { print_warning_once "Virtual posting in bracket ignored (see convert_virtual option)"; next; } } elsif ($account =~ /^<(.*)>/) { $account = $1; $l =~ s/\Q<$account>\E/$account /; } $in_postings = 1; my $postdate = $+{postdate}; my $auxdate = $+{auxdate}; my $has_amount = $+{amount} ? 1 : 0; # Strip the auxdate info $l =~ s/\s*\Q$+{datestrip}\E// if $+{datestrip}; $l = replace_account $l; if ($l =~ /^$posting_RE(\s*(?\{\{?)\s*(?=\s*)?(?$amount_RE)\s*(?\}\}?))?\s*(\[(?$date_RE)\])?\s*(\((?[^@].*)\))?\s*(\(?(?@@?)\)?\s*?(?=\s*)?(?$amount_RE))?(\s*=\s*(?$amount_RE))?(\s*$comment_RE)?/) { # posting with unit price and optional lot price # XXX refactor/merge with previous regex case my $lot_info = ""; $lot_info .= ", " . pp_date $+{date}, 0 if (defined $+{date}); $lot_info .= ", " . mk_beancount_string $+{lot_note} if (defined $+{lot_note}); if (defined $+{lot_price} && not defined $+{lot_cost}) { # No ledger lot cost, only price. This one is tricky # because this convention can be used for two different # purposes: # 1) For conversion between currencies where you do not # generally wish to retain the cost. # 2) To acquire/dispose of commodities (e.g. shares) # where you want to retain the cost. # # Most currencies have 3 characters (e.g. EUR, USD, GBP) # whereas commodities often have more (e.g. the ISIN). # Therefore, we assume the cost should not be kept if # both currencies have 3 characters. Since this won't # work in all cases, we also check for a list of # commodities. Similarly, we allow users to configure # commodities that should be treated as currencies. my $commodity1 = map_commodity $+{commodity}; my $commodity2 = map_commodity parse_commodity $+{lot_price}; if (!$+{fixated_price} && ((length $commodity1 == 3 && length $commodity2 == 3 && !($commodity1 ~~ @{$config->{currency_is_commodity}})) || $commodity1 ~~ @{$config->{commodity_is_currency}} || $commodity2 ~~ @{$config->{commodity_is_currency}})) { $l = sprintf "$+{posting} %s %s", "@" x length $+{at}, replace_commodity $+{lot_price}; } else { $l = sprintf "$+{posting} %s%s%s%s", "{" x length $+{at}, replace_commodity $+{lot_price}, $lot_info, "}" x length $+{at}; } } elsif (defined $+{lot_cost}) { $l = "$+{posting} $+{curlyopen}" . replace_commodity($+{lot_cost}) . "$lot_info$+{curlyclose}"; # ledger requires you to specify both lot cost and lot price # due to a bug. If both are the same, don't put in the price. if (defined $+{lot_price} && ($+{lot_cost} ne $+{lot_price})) { $l .= " $+{at} " . replace_commodity $+{lot_price}; } } else { $l = $+{posting}; } if ($+{commodity} && !defined $+{lot_cost}) { # Apply any fixated costs if needed foreach my $a (reverse @ledger_apply) { if (${$a}[0] eq "fixed") { my ($commodity, $fixated) = split /\s+/, ${$a}[1], 2; $fixated = replace_commodity $fixated; $l =~ s/($+{amount})/$1 {$fixated}/ if $+{commodity} eq $commodity; } } } if ($+{comment}) { my $comment = handle_comment $depth, "; $+{comment}", 1; $l .= " ; $comment" if $comment; } if ($+{assertion}) { push_assertion $+{account}, replace_commodity $+{assertion}; if ($total_postings == 2 && $postings_with_amount == 0) { # We have two postings, i.e. two accounts; remove the current # account from the list of accounts to find out which account # we have to pad against. @accounts = grep { $_ ne $+{account} } @accounts; print_line 0, sprintf "%s pad %s %s", $cur_txn_header{date}, map_account $+{account}, map_account $accounts[0]; print_line 0, pp_cur_assertions; # Skip transaction (the transaction itself is just two # null postings, which are not valid in beancount) pop_txn(); return; } elsif ($total_postings > 2 && ($total_postings-$postings_with_amount) == 2) { print_warning_once "Balance assignments with 2 null postings not supported"; } $l =~ s/\s*=\s*\Q$+{assertion}\E//; } if ($has_amount) { push_line $depth, replace_commodity $l; } else { push_line $depth, $l; } } else { die "Can't parse: $l"; } # Show all metadata that was on the same line as the posting push_deferred_meta $depth + 1; push_metadata $depth + 1, $config->{postdate_tag}, pp_date $postdate, 0 if defined $postdate && defined $config->{postdate_tag}; push_metadata $depth + 1, $config->{auxdate_tag}, pp_date $auxdate, 0 if defined $auxdate && defined $config->{auxdate_tag}; } elsif ($l =~ /^\h*$/) { # whitespace or blank line push_line 0, ""; } else { # there shouldn't be anything die "Don't know how to process transaction line: $l\n"; } } print_tags 2, @cur_txn_tags; if ($total_postings == 1) { if (defined $ledger_bucket) { # We only saw one posting and a ledger bucket is defined push_line 1, map_account $ledger_bucket; } else { # Transactions can have a single posting as long as the # amount is 0 (otherwise it would fail to balance). This # can be used to add standalone balance assertions. # In theory, we should check that the amount == 0, but # the transaction would fail to balance in ledger if # that wasn't the case. print_line 0, pp_cur_assertions if @cur_txn_assertions; pop_txn(); return; } } elsif ($total_postings == 2 && $postings_with_amount == 2) { # Handle implicit conversions. We only support simple implicit # conversions with 2 postings. my $amount1; my $commodity1; foreach my $l (@cur_txn_lines) { # Parse beancount posting to get the amount and commodity if ($l =~ /^\s+([*!]\s+)?[\p{Uppercase_Letter}][^\s]+\s+-?([\d.]+ ([A-Z][A-Z0-9_'.-]*[A-Z0-9](\s*[@\{])?))/) { last if $4; # skip if we have a cost or price my $match = $2; if (!$amount1) { $commodity1 = $3; $amount1 = $match; } else { next if $commodity1 eq $3; $l =~ s/$match/$match @@ $amount1/; } } } } push @output, pop_txn(); } # Read one ledger stanza (everything indented by whitespace) sub read_stanza($) { my ($input_ref) = @_; my @stanza = (); my $l; do { $l = @{$input_ref}[0]; push @stanza, shift @{$input_ref} if $l =~ /^\h+/; } while ($l =~ /^\h+/ && @{$input_ref}); return @stanza; } # MAIN CONVERSION LOOP unshift(@ARGV, '-') unless @ARGV; open my $input, $ARGV[0] or die "Can't read $ARGV[0]"; my @input = <$input>; close $input; my $year; # To store year declaration while (@input) { my $l = shift @input; chomp $l; my $depth = 0; my @stanza; # The two tests for ignore_marker have to be the first thing since they # have to take precedence over other tests. if ($config->{ignore_marker} && $l =~ /;\s*:?$config->{ignore_marker}\s+begin/) { do { $l = shift @input; } while $l !~ /;\s*:?$config->{ignore_marker}\s+end/; } elsif ($config->{ignore_marker} && $l =~ /;\s*:?$config->{ignore_marker}/) { next; } elsif ($config->{keep_marker} && $l =~ /;\s*:?$config->{keep_marker}\s+begin/) { $l = shift @input; do { if ($l =~ /^$comment_top_level_RE$/) { print_line $depth, $+{comment}; } $l = shift @input; } while $l !~ /;\s*:?$config->{keep_marker}\s+end/; } elsif ($config->{keep_marker} && $l =~ /^$comment_top_level_RE\s*;\s*:?$config->{keep_marker}/) { print_line $depth, $+{comment}; } elsif ($l =~ /^[!@]?include\s+(?.*)/) { # include my $filename = $+{filename}; $filename =~ s/(.ledger|.dat)$//; print_line $depth, "include \"$filename.beancount\""; } elsif ($l =~ /^$comment_top_level_RE/) { # beancount issue #282 if ($l =~ /^\|\s?(?.*)/) { print_comment_top_level $depth, $+{comment}; } else { # Rewrite the Emacs modeline $l =~ s/-\*- ledger -\*-/-*- mode: beancount -*-/; print_line $depth, $l; } } elsif ($l =~ /^[!@]?(?alias)\s+(?$account_RE)\s*=\s*(?.*)/) { # alias $ledger_alias{$+{account}} = map_account_apply $+{val}; } elsif ($l =~ /^[!@]?apply\s+(?account)\s+(?.*)/) { # apply account push @ledger_apply, [$+{type}, $+{val}]; } elsif ($l =~ /^[!@]?apply\s+(?fixed)\s+(?.*)/) { # apply fixed push @ledger_apply, [$+{type}, $+{val}]; } elsif ($l =~ /^[!@]?apply\s+(?tag)\s+(?.*)/) { # apply tag # `apply tag` can be converted to beancount in three ways: # * using pushtag/poptag for tags # * applying links to each transactions # * applying metadata to each transactions if ("; $+{val}" =~ /$metadata_RE/) { push @ledger_apply, ["metadata", {%+}]; } elsif (is_link $+{val}) { push @ledger_apply, ["link", $+{val}]; } else { print_line $depth, "pushtag " . pp_tag_link $+{val}; push @ledger_apply, [$+{type}, $+{val}]; } } elsif ($l =~ /^[!@]?apply\s+(?year)\s+(?\d+)/) { # apply year $year = $+{val}; push @ledger_apply, [$+{type}, $+{val}]; } elsif ($l =~ /^[!@]?apply\s+.*/) { # apply .* # ledger seems to silently ignore all other apply statements next; } elsif ($l =~ /^[!@]?end/) { # end next if !@ledger_apply; # end without any apply my $a = pop @ledger_apply; if (${$a}[0] eq "tag") { print_line $depth, "poptag " . pp_tag_link ${$a}[1] } elsif (${$a}[0] eq "year") { # apply year can be nested, so restore the previous year foreach my $a (reverse @ledger_apply) { if (${$a}[0] eq "year") { $year = ${$a}[1]; last; } } } } elsif ($l =~ /^[!@]?(bucket|A)\s+(.*)/) { # bucket $ledger_bucket = $2; } elsif ($l =~ /^[!@]?(comment|test)/) { # block comment $l = shift @input; # block comments may or may not be indented. If the first line has # indentation, strip the same indentation, from all other comments. my $strip_indent = $l =~ /^(\h+)/ ? $1 : ""; while ($l !~ /^end\s+(comment|test)/) { chomp $l; $l =~ s/^$strip_indent//; print_comment_top_level $depth, $l; $l = shift @input; } } elsif ($l =~ /^[!@]?(define|def)\s/) { # define print_warning_once "The `$1` directive is not supported"; print_comment_top_level 0, $l; } elsif ($l =~ /^[!@]?(fixed|endfixed)/) { # Fixated price print_warning_once "Fixated prices are not supported"; print_comment_top_level 0, $l; } elsif ($l =~ /^(Y\s*|year\s+)(\d{4})/) { # year declaration $year = $2; } elsif ($l =~ /^$price_RE/) { $l = sprintf "%s price %s ", pp_date($+{date}, $year), map_commodity $+{commodity1}; if ($+{commodity2} =~ /$amount_RE/) { $l .= pp_amount $+{minus}, $+{num}, $+{commodity}, $+{inline_math}; } else { die "Can't parse second commodity in price directive: $+{commodity2}"; } $l =~ s/"//g; print_line $depth, $l; } elsif ($l =~ /^([=~].*)/) { # automated transaction (=) or periodic transaction (~) print_warning_once "Automated or periodic transaction skipped"; print_comment_top_level $depth, $1; @stanza = read_stanza \@input; foreach $l (@stanza) { ($depth, $l) = strip_indentation $l; print_comment_top_level $depth, $l; } } elsif ($l =~ /^[!@]?account\s+(.*)/) { # account declaration my ($account, $comment); # account foo ; bar # In ledger, this is parsed as account "foo ; bar"; in hledger as # account "foo" with comment "bar". # If there are two spaces, ledger will also parse it part of the # account name, but such an account name is invalid so treat it # as a comment. if ($config->{hledger}) { ($account, $comment) = split /\s*;\s*/, $1, 2; } else { ($account, $comment) = split /\s\s+;\s*/, $1, 2; } $account = map_account $account; @stanza = read_stanza \@input; # Avoid duplicate account declarations if two accounts are mapped # to the same account and both have account declarations. if ($account_declared{$account}) { print_warning_once "Skipped second account declaration for $account (old $1)"; next; } $account_declared{$account} = 1; print_line $depth, sprintf "$config->{account_open_date} open %s%s", $account, $comment ? " ; $comment" : ""; foreach $l (@stanza) { ($depth, $l) = strip_indentation $l; if ($l =~ /^note\s+(.*)/) { # note print_line $depth, pp_metadata "description", mk_beancount_string $1; } elsif ($l =~ /^$metadata_RE/) { # metadata print_line $depth, pp_metadata $+{key}, mk_beancount_string $+{value}; } else { print_comment_top_level $depth, $l; } } } elsif ($l =~ /^[!@]?commodity\s+(.*)/) { # commodity declaration my ($commodity, $comment); $commodity = $1; if ($commodity =~ /^(".*")(.*)/) { $commodity = $1; $comment = $1 if $2 =~ /\s*;\s*(.*)/; } else { ($commodity, $comment) = split /\s*;\s*/, $commodity, 2; } $commodity = map_commodity $commodity; @stanza = read_stanza \@input; # Avoid duplicate commodity declarations if two commodities are # mapped to the same commodity and both have commodity declarations. if ($commodity_declared{$commodity}) { print_warning_once "Skipped second commodity declaration for $commodity (old $1)"; next; } $commodity_declared{$commodity} = 1; print_line $depth, sprintf "$config->{commodities_date} commodity %s%s", $commodity, $comment ? " ; $comment" : ""; foreach $l (@stanza) { ($depth, $l) = strip_indentation $l; if ($l =~ /^note\s+(.*)/) { # note print_line $depth, pp_metadata "name", mk_beancount_string $1; } elsif ($l =~ /^format\s+(.*)/) { # format next; # skip directive, not needed in beancount } elsif ($l =~ /^$metadata_RE/) { # metadata print_line $depth, pp_metadata $+{key}, mk_beancount_string $+{value}; } else { print_comment_top_level $depth, $l; } } } elsif ($l =~ /^[!@]?(payee\s+.*)/) { # payee declaration print_comment_top_level $depth, $1; @stanza = read_stanza \@input; foreach $l (@stanza) { ($depth, $l) = strip_indentation $l; print_comment_top_level $depth, $l; } } elsif ($l =~ /^[!@]?(python)/) { # Python # The python directive is special in the sense that empty # lines don't end the directive. do { print_comment_top_level $depth, $l; $l = shift @input; chomp $l; } while ($l =~ /^(\s+|$)/ && @input); unshift @input, $l; } elsif ($l =~ /^[!@]?(tag\s+.*)/) { # tag declaration # Not needed in beancount and there's no equivalent read_stanza \@input if $input[0] =~ /^\h+/; } elsif ($l =~ /^[!@]?(N|D|C|I|i|O|o|b|h|assert|check|expr|eval|value)(\s|$)/) { print_warning_once "Unsupported directive `$1` skipped"; # Not supported in beancount print_comment_top_level $depth, $l; } elsif ($l =~ /^[0-9]/) { if ($l =~ /$txn_header_RE/) { # txn header $in_postings = 0; # You can have a comment on the same line as the payee my ($narration, $comment) = split / +;\s*|\t+;\s*/, $+{narration}, 2; $narration = "" if not $narration; push_header pp_date($+{date}, $year), $+{flag} ? $+{flag} : "txn", $narration; $comment = handle_comment $depth + 1, "; $comment", 0 if $comment; $cur_txn_header{comment} = $comment if $comment; push_metadata $depth + 1, $config->{auxdate_tag}, pp_date($+{auxdate}, $year) if defined $+{auxdate} && defined $config->{auxdate_tag}; push_metadata $depth + 1, $config->{code_tag}, mk_beancount_string $+{code} if defined $+{code} && defined $config->{code_tag}; # Determine payee based on the narration field if ($config->{hledger} && $narration =~ /$hledger_payee_narration_RE/) { push_payee $+{payee}; $cur_txn_header{narration} = $+{narration}; } foreach my $custom_narration_RE (@{$config->{payee_split}}) { if ($narration =~ /$custom_narration_RE/) { push_payee $+{payee}; $cur_txn_header{narration} = $+{narration}; last; } } # Config `payee_match` is an array of hashes my @payee_match = @{$config->{payee_match}}; my $match = 0; while (!$match && @payee_match) { my $payee_match = shift @payee_match; foreach my $custom_narration_RE (keys %{$payee_match}) { if ($narration =~ /$custom_narration_RE/) { push_payee ${$payee_match}{$custom_narration_RE}; $match = 1; } } } # ledger "apply tag" foreach my $a (reverse @ledger_apply) { if (${$a}[0] eq "metadata") { handle_metadata 1, ${$a}[1], 0; } elsif (${$a}[0] eq "link") { print_tags 1, ${$a}[1]; } } } elsif ($l !~ /^$date_RE/) { die "Cannot process date in transaction header: $l\n"; } else { die "Cannot process transaction header: $l\n"; } @stanza = read_stanza \@input; process_txn @stanza; } elsif ($l =~ /^\h*$/) { print_line 0, ""; } elsif ($l =~ /^--/) { # ledger option next; } else { print_warning "Unknown line. Please report. Line: $l"; print_line 0, $l; } } # Check for renames foreach (sort keys %ledger_accounts) { my $map = map_account $_; if ($_ ne $map && !($map ~~ [values %{$config->{account_map}}])) { print_warning "Account $_ renamed to $map"; } } foreach (sort keys %ledger_commodities) { my $map = map_commodity $_; if ($_ ne $map && $_ ne qq("$map") && !($map ~~ [values %{$config->{commodity_map}}])) { print_warning "Commodity $_ renamed to $map"; } } foreach (sort keys %ledger_metadata) { my $map = map_metadata $_; if ($_ ne $map && !($map ~~ [values %{$config->{metadata_map}}])) { print_warning "Metadata key $_ renamed to $map"; } } # Check for collisions my %mapped_accounts; foreach (keys %ledger_accounts) { push @{$mapped_accounts{map_account $_}}, $_; } foreach (sort keys %mapped_accounts) { if (@{$mapped_accounts{$_}} > 1) { print_warning "Collision for account $_: " . join ", ", sort @{$mapped_accounts{$_}}; } } my %mapped_commodities; foreach (keys %ledger_commodities) { push @{$mapped_commodities{map_commodity $_}}, $_; } foreach (sort keys %mapped_commodities) { if (@{$mapped_commodities{$_}} > 1) { print_warning "Collision for commodity $_: " . join ", ", sort @{$mapped_commodities{$_}}; } } my %mapped_metadata; foreach (keys %ledger_metadata) { push @{$mapped_metadata{map_metadata $_}}, $_; } foreach (sort keys %mapped_metadata) { if (@{$mapped_metadata{$_}} > 1) { print_warning "Collision for metadata $_: " . join ", ", sort @{$mapped_metadata{$_}}; } } # Print everything if (@conversion_notes) { print ";", "-"x70, "\n"; print "; ledger2beancount conversion notes:\n"; print ";\n"; print "; - $_\n" foreach @conversion_notes; print ";", "-"x70, "\n"; print "\n"; } print "option \"operating_currency\" \"$_\"\n" foreach @{$config->{operating_currencies}}; if ($config->{beancount_header}) { open my $beancount_header, $config->{beancount_header} or die "Can't file beancount header: $config->{beancount_header}"; print foreach <$beancount_header>; close $beancount_header; } if ($config->{automatic_declarations}) { # Print missing account and commodity declarations for my $a (sort keys %account_declared) { printf "$config->{account_open_date} open $a\n" if not defined $account_declared{$a}; } for my $c (sort keys %commodity_declared) { printf "$config->{commodities_date} commodity $c\n" if not defined $commodity_declared{$c}; } } # Print the converted beancount output print $_ for (@output); ledger2beancount-2.0/bin/ledger2beancount-ledger-config000077500000000000000000000012311362415351400232230ustar00rootroot00000000000000#!/usr/bin/env perl # Copyright (C) 2018 Martin Michlmayr # License: GNU General Public License (GPL), version 3 or above # obtain configuration data from ~/.ledgerrc for ledger2beancount use strict; use warnings; unshift(@ARGV, "$ENV{HOME}/.ledgerrc") unless @ARGV; open my $input, $ARGV[0] or die "Can't read $ARGV[0]"; my $format; while (<$input>) { if (/^--input-date-format\s+"?(.*)"?/) { $format = $1; } elsif (!$format && /^--date-format\s+"?(.*)"?/) { $format = $1; } elsif (/^--decimal-comma/) { print "decimal_comma: true\n"; } } close $input; print "date_format: \"$format\"\n" if $format; ledger2beancount-2.0/cpanfile000066400000000000000000000004441362415351400163100ustar00rootroot00000000000000 requires 'Config::Onion'; requires 'Date::Calc'; requires 'DateTime::Format::Strptime', '>= 1.58'; requires 'experimental'; requires 'File::BaseDir'; requires 'Getopt::Long::Descriptive'; requires 'POSIX'; requires 'String::Interpolate'; requires 'Unicode::Normalize'; requires 'YAML::XS'; ledger2beancount-2.0/docs/000077500000000000000000000000001362415351400155325ustar00rootroot00000000000000ledger2beancount-2.0/docs/changelog.md000066400000000000000000000077671362415351400200240ustar00rootroot00000000000000# ledger2beancount releases ## 2.0 (2020-02-22) * Handle comments in `account` and `commodity` declarations * Handle transactions with a single posting (without `bucket`) * Handle empty metadata values * Rewrite Emacs modeline ## 1.8 (2019-06-12) * Add support for `apply year` * Fix incorrect account mapping of certain accounts * Handle fixated commodity and postings without amount * Improve behaviour for invalid `end` without `apply` * Improve error message when date can't be parsed * Deal with account names consisting of a single letter * Ensure account names don't end with a colon * Skip ledger directives `eval`, `python`, and `value` * Don't assume all filenames for `include` end in `.ledger` * Support `price` directives with commodity symbols * Support decimal commas in `price` directives * Don't misparse balance assignment as commodity * Ensure all beancount commodities have at least 2 characters * Ensure all beancount metadata keys have at least 2 characters * Don't misparse certain metadata as implicit conversion * Avoid duplicate `commodity` directives for commodities with name collisions * Recognise deferred postings * Recognise `def` directive ## 1.7 (2019-04-22) * Don't misparse account and commodity with mixed tab/space separators * Rename account names consisting of a root name without subaccount * Warn when non-standard root names are used * Avoid duplicate open directives for accounts with name collisions * Don't warn for renamed tags that won't show up in the beancount file * Add `account_regex` option to mass rename account names * Add man page and improve documentation ## 1.6 (2019-03-25) * Add support for fixated prices and costs * Handle account names that contain brackets * Don't parse trailing tabs as part of the account name * Escape backslashes in the narration ## 1.5 (2019-01-30) * Replace commodities in balance assertions * Add support for posting-level dates * Add support for hledger features * Add support for balance assignments * Handle comments on the same line as the payee * Handle comments, tags and metadata on postings with balance assertions * Handle metadata on postings with cost or price information * Handle simple implicit conversions ## 1.4 (2018-12-01) * Don't parse trailing whitespace as part of the account name * Replace commodities in lot costs * Avoid mangling of lot cost with other lot information * Don't require whitespace between {} and @ in lot information ## 1.3 (2018-09-29) * Handle tags on the same line as postings correctly * Allow (commented) beancount entries in ledger input file * Handle amounts without leading zeroes ## 1.2 (2018-05-17) * Updates for beancount 2.1.0: * Allow UTF-8 letters and digits in account names * Allow full-line comments in transactions * Allow transaction tags and links on multiple lines * Handle posting tags on multiple lines * Always convert posting-level tags to metadata * Improve parsing of the transaction header ## 1.1 (2018-05-01) * Happy International Workers' Day release! * Handle block comments without indentation correctly * Preserve comments for postings with lots * Use beancount's `pushtag/poptag` for ledger's `apply tag` * Handle `tag` directives with associated commands correctly * Allow option `link_match` to work with `tag_as_metadata: true` * Handle posting-level tags without indentation correctly with `tag_as_metadata: false` * Ensure `payee_match` is predictable * Preserve comments for postings with lots * Embed an optional beancount header to the converted file to specify beancount options * Convert ledger metadata keys to valid beancount metadata keys * Add conversion notes when accounts, commodities or metadata keys are automatically renamed by ledger2beancount * Add capability to ignore certain lines * Keep whitespace intact when renaming account names * Improve documentation on assigning payees based on transactions * Add more test cases * Run the test suite only if something has changed ## 1.0 (2018-03-30) * Initial release with support for the majority of features from ledger ledger2beancount-2.0/docs/contributing.md000066400000000000000000000013551362415351400205670ustar00rootroot00000000000000Bugs and contributions ====================== If you find any bugs in ledger2beancount or believe the conversion from ledger to beancount could be improved, please [open an issue](https://github.com/zacchiro/ledger2beancount/issues). Please include a small test case so we can reproduce the problem. If you'd like to contribute code to ledger2beancount, please submit a [pull request on GitHub](https://github.com/zacchiro/ledger2beancount/pulls) or send a `git format-patch` patch (series) to the authors via email (see the `AUTHORS` file). Please move sure you add a test case under `tests` and update the documentation (`docs/manual.md`, and possibly `README.md` and `examples/illustrated.md`). You can run the test suite with `make test`. ledger2beancount-2.0/docs/ledger2beancount.1.scd000066400000000000000000000040001362415351400216010ustar00rootroot00000000000000ledger2beancount(1) # NAME ledger2beancount - ledger to beancount converter # SYNOPSIS *ledger2beancount* [options] _input.ledger_ > _output.beancount_ *cat* _input.ledger_ | *ledger2beancount* [options] > _output.beancount_ # DESCRIPTION *ledger2beancount* is a script to automatically convert *ledger*(1)-based textual ledgers to *beancount* files. Conversion is based on (concrete) syntax, so that information that is not meaningful for accounting reasons but still valuable (e.g., comments, formatting, etc.) can be preserved. # OPTIONS *-c, --config* Specify a configuration file. The options of the configuration file are described in *ledger2beancount*(5) and the *ledger2beancount* manual. *-h, --help* Show help message and quit. # USAGE *ledger2beancount* accepts input from _stdin_ or from a file and will write the converted data to _stdout_. You can run *ledger2beancount* like this on the example provided: *ledger2beancount* _examples/simple.ledger_ > _simple.beancount_ After you convert your *ledger*(1) file, you should validate the generated beancount file with *bean-check*(1) and fix all errors: *bean-check* _simple.beancount_ You should also inspect the generated *beancount* file to see if it looks correct to you. Please note that *ledger2beancount* puts notes at the beginning of the generated *beancount* file if it encounters problems with the conversion. # FILES _$PWD/ledger2beancount.yml_ The configuration file for the current directory. _$HOME/.config/ledger2beancount/config.yml_ The default configuration file. # BUGS If you find any bugs in *ledger2beancount* or believe the conversion from *ledger* to *beancount* could be improved, please open an issue on GitHub: https://github.com/zacchiro/ledger2beancount/issues Please include a small test case so we can reproduce the problem. # AUTHORS Stefano Zacchiroli and Martin Michlmayr # SEE ALSO *ledger2beancount*(5), *ledger*(1), *bean-check*(1) The full documentation for *ledger2beancount* can be found in its manual. ledger2beancount-2.0/docs/ledger2beancount.5.scd000066400000000000000000000113241362415351400216140ustar00rootroot00000000000000ledger2beancount(5) # NAME ledger2beancount - configuration file for *ledger2beancount*(1) # INPUT OPTIONS The following options may be needed for *ledger2beancount* to interpret your *ledger* files correctly. *date_format* The date format used in your *ledger* file (default: *%Y-%m-%d*). *date_format_no_year* The date format for dates without the year when *ledger*'s *Y*/*year* directive is used (default: *%m-%d*). *ledger_indent* Sets the indentation level used in your ledger file (default: *4*). *decimal_comma* true|false Parses amounts with the decimal comma (e.g. *10,00 EUR*). Set this option to *true* if you use option *--decimal-comma* in *ledger*. *hledger* true|false Tells *ledger2beancount* whether to attempt to parse *hledger*(1)-specific features. # OTHER OPTIONS *beancount_indent* Sets the indentation level for the generated beancount file (default: *2*). *operating_currencies* A list of frequently used currencies. This is used by *fava*, the web UI for beancount. *automatic_declarations* true|false Emit account and commodity declarations. (Default: *true*) Note: the declarations done in ledger via *account* and *commodity* declarations are always converted. If this option is *true*, declarations are created for those which have not been explicitly declared in *ledger* but used. *account_open_date* The date used to open accounts (default: *1970-01-01*). *commodities_date* The date used to create commodities (default: *1970-01-01*). *beancount_header* Specifies a file which serves as a beancount "header", i.e. it's put at the beginning of the converted beancount file. You can use such a header to specify options for beancount, such as *option "title"*, define *plugin* directives or beancount *query* information. *ignore_marker* Specifies a marker that tells *ledger2beancount*(1) to ignore a line if the marker is found. *keep_marker* Specifies a marker that tells *ledger2beancount*(1) to take a line from the input that is commented out, uncomment it and display it in the output. *convert_virtual* true|false Specifies whether virtual postings should be converted. If set to *true*, virtual postings in brackets will be made into real accounts. (Virtual postings in parentheses are always ignored, regardless of this option.) *account_map* Specifies a hash of account names to be mapped to other account names. *account_regex* Specifies a hash of regular expressions to replace account names. *commodity_map* Specifies a mapping of *ledger* commodities to beancount commodities. *metadata_map* Specifies a mapping of *ledger* metadata keys to corresponding *beancount* keys. *payee_tag* and *payer_tag* Specify a metadata tag (after the mapping done by *metadata_map*) used to set the payee. *payee_split* Specifies a list of regular expressions to split *ledger*'s payee field into payee and narration. You have to use the named capture groups *payee* and *narration*. *payee_match* Specifies a list of regular expressions and corresponding payees. The whole *ledger* payee becomes the narration and the matched payee from the regular expression becomes the payee. *postdate_tag* Specifies the metadata tag to be used to store posting dates. (Use the empty string if you don't want the metadata to be added to beancount.) *auxdate_tag* Specifies the metadata tag to be used to store auxiliary dates (also known as effective dates; or *date2* in *hledger*). (Use the empty string if you don't want the metadata to be added to beancount.) *code_tag* Specifies the metadata tag to be used to store transaction codes. (Use the empty string if you don't want the metadata to be added to beancount.) *link_match* Specifies a list of regular expressions that will cause a tag to be rendered as a link. *link_tags* Specifies a list of metadata tags whose values should be converted to *beancount* links instead of metadata. Tags are case insensitive and values must not contain whitespace. *currency_is_commodity* Specifies a list of commodities that should be treated as commodities rather than currencies even though they consist of 3 characters (which is usually a characteristic of a currency). Expects beancount commodities (i.e. after transformation and mapping). *commodity_is_currency* Specifies a list of commodities that should be treated as currencies (in the sense that cost is not retained). Expects beancount commodities (i.e. after transformation and mapping). # AUTHORS Stefano Zacchiroli and Martin Michlmayr # SEE ALSO *ledger2beancount*(1), *ledger*(1), *hledger*(1) The full documentation for *ledger2beancount* can be found in its manual. ledger2beancount-2.0/docs/manual.md000066400000000000000000001065121362415351400173360ustar00rootroot00000000000000--- title: ledger2beancount subtitle: Ledger to Beancount converter author: - Stefano Zacchiroli - Martin Michlmayr keywords: ledger, beancount, conversion, accounting, bookkeeping date: February 2020 documentclass: scrartcl urlcolor: blue toc: true --- # Introduction ledger2beancount is a script to automatically convert [Ledger](https://www.ledger-cli.org/)-based textual ledgers to [Beancount](http://furius.ca/beancount/) ones. Conversion is based on (concrete) syntax, so that information that is not meaningful for accounting reasons but still valuable (e.g., comments, formatting, etc.) can be preserved. ledger2beancount aims to be compatible with the latest official release of beancount. # Installation ledger2beancount is a Perl script and relies on the following Perl modules: * Config::Onion * Date::Calc * DateTime::Format::Strptime * File::BaseDir * Getopt::Long::Descriptive * String::Interpolate * YAML::XS You can install the required Perl modules with [cpanminus](https://metacpan.org/pod/distribution/App-cpanminus/bin/cpanm): cpanm --installdeps . If you use Debian, you can install the dependencies with this command: sudo apt install libconfig-onion-perl libdate-calc-perl \ libfile-basedir-perl libyaml-libyaml-perl \ libgetopt-long-descriptive-perl libdatetime-format-strptime-perl \ libstring-interpolate-perl Note that String::Interpolate (libstring-interpolate-perl) is not in Debian stable. ledger2beancount itself consists of one script. You can clone the repository and run the script directly or copy it to `$HOME/bin` or a similar location: git clone https://github.com/zacchiro/ledger2beancount/ ./bin/ledger2beancount examples/simple.ledger ## Arch Linux ledger2beancount is available on [AUR](https://aur.archlinux.org/packages/ledger2beancount/). ## Debian ledger2beancount is [available in Debian](https://packages.debian.org/ledger2beancount). ## macOS You can install `cpanm` from Homebrew: brew install cpanminus ## Microsoft Windows You can install [Strawberry Perl](http://strawberryperl.com/) on Windows and use `cpanm` as described above to install the required Perl modules. ledger2beancount is not packaged for Windows but you can clone this Git repository and run the script. # Configuration ledger2beancount can use a configuration file. It will search for the config file `ledger2beancount.yml` in the current working directory. If that file is not found, it will look for `$HOME/.config/ledger2beancount/config.yml`. You can also pass an alternative config file via `--config/-c`. The file must end in `.yml` or `.yaml`. See the sample config file for the variables you can use. While the configuration file is optional, you may have to define a number of variables for ledger2beancount to work correctly with your ledger files: * `ledger_indent` sets the indentation level used in your ledger file (by default `4`). * `date_format` has to be configured if you don't use the date format `YYYY-MM-DD`. * `decimal_comma` has to be set to `true` if you use commas as the decimal separator (for example, `10,12 EUR` meaning 10 Euro and 12 cents). * `commodity_map` defines mappings from ledger to beancount commodities. You have to set this if you use commodity codes like `€` or `£` (to map them to `EUR` and `GBP`, respectively). Additionally, these options are useful to configure beancount: * `operating_currencies`: a list of the currencies you frequently use. * `beancount_header`: a file which is embedded at the beginning of the converted beancount file which can include beancount `option` statements, `plugin` directives, `query` information and more. Other variables can be set to use various functionality offered by ledger2beancount. Please read the [section on features](#features) to learn about these variables and refer to the [complete list of configuration options](#configuration-options) at the end of the manual. # Usage ledger2beancount accepts input from `stdin` or from a file and will write the converted data to `stdout`. You can run ledger2beancount like this on the example provided: ledger2beancount examples/simple.ledger > simple.beancount After you convert your ledger file, you should validate the generated beancount file with `bean-check` and fix all errors: bean-check simple.beancount You should also inspect the generated beancount file to see if it looks correct to you. Please note that ledger2beancount puts notes at the beginning of the generated beancount file if it encounters problems with the conversion. If you believe that ledger2beancount could have produced a better conversion or if you get an error message from ledger2beancount, please [file a bug](https://github.com/zacchiro/ledger2beancount/issues) along with a simple test case. You can pipe the output of ledger2beancount to beancount's bean-format if you want to use the conversion as an opportunity to reformat your file. # Beancount compatibility The syntax of beancount is quite stable but it's expected to become slightly less restrictive as some missing features are implemented (such as posting-level tags). ledger2beancount aims to be compatible with the latest official release of beancount, but some functionality may require an unreleased version of beancount. You can install the latest development version of beancount directly from the beancount repository: pip3 install hg+https://bitbucket.org/blais/beancount/ Currently, there are no features that require an unreleased version of beancount. ledger2beancount is largely compatible with Beancount 2.0. If you use the following features, you need Beancount 2.1: * UTF-8 letters and digits in account names * Full-line comments in transactions * Transaction tags on multiple lines # Features ledger2beancount supports most of the syntax from ledger. It also offers some features to improve the conversion from ledger to beancount. If you're new to beancount, we suggest you read this section in parallel to the [illustrated ledger file provided](../examples/illustrated.ledger). This example ledger file explains differences between ledger and beancount, shows how ledger syntax is converted to beancount and describes how you can use the features described in this section to improve the conversion from ledger to beancount. The illustrated example uses the same subsections as this section, so it's easy to follow in parallel. You can convert the illustrated ledger file to beancount like this: ledger2beancount --config examples/illustrated.yml examples/illustrated.ledger But please be aware that it doesn't pass `bean-check`. See the comments in the file as to why. Note on **regular expressions**: many of the features described below require you to specify regular expressions in ledger2beancount configuration file. The expected syntax (and semantics) for all such values is that of [Perl regular expressions](https://perldoc.perl.org/perlre.html#Regular-Expressions). ## Accounts ledger2beancount will convert ledger account declarations to beancount `open` statements using the `account_open_date` variable as the opening date. The `note` is used as the `description`. Unlike ledger, beancount requires declarations for all account names. If an account was not declared in your ledger file but used, ledger2beancount will automatically create an `open` statement in beancount. You can turn this off by setting `automatic_declarations` to `false`. This is useful if you have include files and run ledger2beancount several times since duplicate `open` statements for the same account will result in an error from beancount. ledger2beancount replaces ledger account names with valid beancount accounts and therefore performs the following transformations automatically: 1. Replaces space and other invalid characters with dash (`Liabilities:Credit Card` becomes `Liabilities:Credit-Card`) 2. Replaces account names starting with lower case letters with upper case letters (`Assets:test` becomes `Assets:Test`) 3. Ensures the first letter is a letter or number by replacing a non-letter first character with an `X`. While these transformations lead to valid beancount account names, they might not be what you desire. Therefore, you can add account mappings to `account_map` to map the transformed account names to something different. The mapping will work on your ledger account names and on the account names after the transformation. Unlike ledger, beancount expects all account names to start with one of five account types, also known as root names. The default root names are `Assets`, `Liabilities`, `Equity`, `Expenses`, and `Income`. If you want to use other root names, you can configure them using the beancount options `name_assets`, `name_liabilities`, `name_equity`, `name_expenses`, and `name_income`. If you use more than five root names, you will have to rename them. ledger2beancount offers the `account_regex` option to mass rename account names. If you use the top-level root name `Accrued` to track accounts payable and accounts receivable, you can rename them with this `account_regex` config option: account_regex: ^Accrued:Accounts Payable:(.*): Liabilities:Accounts-Payable:$1 ^Accrued:Accounts Receivable:(.*): Assets:Accounts-Receivable:$1 Ledger's `apply account` and `alias` directives are supported. The mapping of account names described above is done after these directives. ## Amounts In ledger, amounts can be placed after the amount. This is converted to beancount with the the amount first, followed by the commodity. If you use commas as the decimal separator (i.e. values like `10,12`, using the ledger option `--decimal-comma`) you have to set the `decimal_comma` option to `true`. Please note that commas are not supported as the decimal separator in beancount at the moment ([issue 204](https://bitbucket.org/blais/beancount/issues/204)) so your amounts are converted not to use comma as the decimal separator. Commas as separators for thousands (e.g. `1,000,000`) are supported by beancount. Ledger allows amounts without commodities, e.g.: Assets:Test 10.00 While this is allowed in ledger (but not in beancount), it's not recommended and ledger2beancount does not support amounts without commodities. Please add a commodity before using ledger2beancount. ## Commodities Like accounts, ledger2beancount will convert ledger commodity declarations to beancount. The `note` is converted to `name`. As with account names, ledger2beancount will create `commodity` statements for all commodities used in your ledger file (if `automatic_declarations` is `true`). ledger2beancount will automatically convert commodities to valid beancount commodities. This involves replacing all invalid characters with a dash (a character allowed in beancount commodities but not in ledger commodities), stripping quoted commodities, making the commodity uppercase and limiting it to 24 characters. Furthermore, the first character will be replaced with an `X` if it's not a letter and the same will be done for the last character if it's not a letter or digit. Finally, all beancount commodities currently have to consist of at least two characters ([issue 192](https://bitbucket.org/blais/beancount/issues/192)). If you require a mapping between ledger and beancount commodities, you can use `commodity_map`. You can use your ledger commodity names or the names after the transformation in the map to perform a mapping to another commodity name. Commodity symbols (like `$`, `€` and `£`) are supported and converted to their respective commodity codes (like `USD`, `EUR`, `GBP`). Update `commodity_map` if you use other symbols. ## Flags ledger2beancount supports both transaction flags ([transaction state](https://www.ledger-cli.org/3.0/doc/ledger3.html#Transaction-state)) and account flags ([state flags](https://www.ledger-cli.org/3.0/doc/ledger3.html#State-flags)). ## Dates ledger supports a wide range of date formats whereas beancount requires all dates in the format `YYYY-MM-DD` (ISO 8601). The variable `date_format` has to be set if you don't use ISO 8601 for the dates in your ledger file. `date_format` uses the same format as the ledger options `--input-date-format` and `--date-format` (see `man 1 date`). Ledger allows dates without a year if the year is declared using the `Y`, `year` and `apply year` directives. If `date_format_no_year` is set, ledger2beancount can convert such dates to `YYYY-MM-DD`. Posting-level dates are recognized by ledger2beancount and stored as metadata according to the `postdate_tag` (`date` by default) but this has no effect in beancount. There is [a proposal](https://docs.google.com/document/d/1x0qqWGRHi02ef-FtUW172SHkdJ8quOZD-Xli7r4Nl_k/) to support this functionality in a different way, but this is not implemented in beancount yet. While ledger2beancount itself doesn't read your ledger config file, the script `ledger2beancount-ledger-config` can be used to parse your ledger config file (`~/.ledgerrc`) or your ledger file (ledger files may contain ledger options) to output the correct config option for ledger2beancount. ## Auxiliary dates Beancount currently doesn't support ledger's [auxiliary dates](https://www.ledger-cli.org/3.0/doc/ledger3.html#Auxiliary-dates) (or effective dates; also known as date2 in hledger) (but there is [a proposal](https://docs.google.com/document/d/1x0qqWGRHi02ef-FtUW172SHkdJ8quOZD-Xli7r4Nl_k/) to support this functionality in a different way), so these are stored as metadata according to the `auxdate_tag` variable. Unset the variable if you don't want auxiliary dates to be stored as metadata. Account and posting-level auxiliary dates are supported. ## Transaction codes Beancount doesn't support ledger's [transaction codes](https://www.ledger-cli.org/3.0/doc/ledger3.html#Codes). These are therefore stored as metatags if `code_tag` is set. ## Narration The ledger payee information, which is generally used as free-form text to describe the transaction, is stored in beancount's narration field and properly quoted. ## Payees Ledger has limited support for payees. A `payee` metadata key can be set but this also overrides the free-form text to describe the transaction. Payees can also be declared explicitly in ledger but this is not required by beancount, so such declarations are ignored (they are preserved as comments). hledger allows the separation of payee and narration using the pipe character (`payee | narration`). This is supported by ledger2beancount if the `hledger` option is enabled. Since ledger has limited support for payees, ledger2beancount offers several features to determine the payee from the transaction itself. You can set `payee_split` and define a list of regular expressions which allow you to split ledger's payee field into payee and narration. You have to use regular expressions with the named capture groups `payee` and `narration`. For example, given the ledger transaction header 2018-03-18 * Supermarket (Tesco) and the configuration payee_split: - (?.*?)\s+\((?Tesco)\) ledger2beancount will create this beancount transaction header: 2018-03-18 * "Tesco" "Supermarket" In other words, `payee_split` allows you to split the ledger payee into payee and narration in beancount. `payee_split` is a list of regular expressions and ledger2beancount stops when a match is found. Furthermore, you can use `payee_match` to match based on the ledger payee field and assign payees according to the match. This variable is a list consisting of regular expressions and the corresponding payees. For example, if your ledger contains a transaction like: 2018-03-18 * Oyster card top-up you can use payee_match: - ^Oyster card top-up: Transport for London to match the line and assign the payee `Transport for London`: 2018-03-18 * "Transport for London" "Oyster card top-up" Unlike `payee_split`, the full payee field from ledger is used as the narration in beancount. Again, ledger2beancount stops after the first match. Beancount comes with a plugin called `fix_payees` which offers a similar functionality to `payee_match`: it renames payees based on a set of rules which allow you to match account names, payees and the narration. The difference is that ledger2beancount's `payee_match` will write the matched payee to the beancount file whereas the `fix_payees` plugin leaves your input file intact and assigns the new payee within beancount. Please note that the `payee_match` is done after `payee_split` and `payee_match` is evaluated even if `payee_split` matched. This allows you to remove some information from the narration using `payee_split` while overriding the found payee using `payee_match`. The regular expressions from `payee_split` and `payee_match` are evaluated in a case sensitive manner by default. If you want case insensitive matches, you can prefix your pattern with `(?i)`, for example: payee_match: - (?i)^Oyster card top-up: Transport for London Finally, metadata describing a payee or payer will be used to set the payee. The tags used for that information can be specified in `payee_tag` and `payer_tag`. Payees identified with these tags will override the payees found with `payee_split` and `payee_match` (although in the case of `payee_split` the narration will be modified as per the regular expression). This allows you to define generic matches using `payee_split` and `payee_match` and override special cases using metadata information. ## Metadata Account and posting metadata are converted to beancount syntax. Metadata keys used in ledger can be converted to different keys in beancount using `metadata_map`. Metadata can also be converted to links (see below). Beancount is more restrictive than ledger in what it allows as metadata keys. ledger2beancount will automatically convert metadata keys to valid beancount metadata keys. This involves replacing all invalid characters with a dash and making sure the first character is a lowercase letter (either by lowercasing a letter or adding the prefix `x`). ledger2beancount also supports [typed metadata](https://www.ledger-cli.org/3.0/doc/ledger3.html#Typed-metadata) (i.e. `key::` instead of `key:`) and doesn't quote the values accordingly, but you should make sure the values are valid in beancount. ## Tags Beancount allows tags for transactions but currently doesn't support tags for postings ([issue 144](https://bitbucket.org/blais/beancount/issues/144)). Because of this, posting-level tags are currently stored as metadata with the key `tags`. This should be seen as a workaround because metadata with the key `tags` is not treated the same way by beancount as proper tags. Ledger's `apply tag` directive is supported. If the string to apply is metadata or a link (according to `link_match`, see below), the information will be added to each transaction between `apply tag` and `end tag`. If it's a tag, beancount's equivalent of `apply tag` is used (`pushtag` and `poptag`). Note that tags can be defined in ledger using a `tag` directive. This is not required in beancount and there's no equivalent directive so all `tag` directives are skipped. ## Links Beancount differentiates between tags and links whereas ledger doesn't. Links can be used in beancount to link several transactions together. ledger2beancount offers two mechanisms to convert ledger tags and metadata to links. First, you can define a list of metadata tags in `link_tags` whose values should be converted to beancount links instead of metadata. For example: link_tags: - Invoice with the ledger input 2018-03-19 * Invoice 4 ; Invoice:: 4 will be converted to 2018-03-19 * Invoice 4 ^4 instead of 2018-03-19 * Invoice 4 #4 Tags are case insensitive. Be aware that the metadata must not contain any whitespace. Since posting-level links are currently not allowed in beancount, they are stored as metadata. Second, you can define regular expressions in `link_match` to determine that a tag should be rendered as a link instead. For example, if you tag your trips in the format `YYYY-MM-DD-foo`, you could use link_match: - ^\d\d\d\d-\d\d-\d\d- to render them as links. So the ledger transaction header 2018-02-02 * Train Brussels airport to city ; :2018-02-02-brussels-fosdem:debian: would become the following in beancount: 2018-02-02 * "Train Brussels airport to city" ^2018-02-02-brussels-fosdem #debian ## Comments Comments are supported. Currently, beancount doesn't accept top-level comments with the `|` marker ([issue 282](https://bitbucket.org/blais/beancount/issues/282)). ledger2beancount changes such comments to use the `;` marker. ## Virtual costs Beancount does not have a concept of [virtual costs](https://www.ledger-cli.org/3.0/doc/ledger3.html#Virtual-posting-costs) ([issue 248](https://bitbucket.org/blais/beancount/issues/248)). ledger2beancount therefore treats them as regular costs (or, rather, as regular prices). ## Lots Lot costs and prices are supported, including per-unit and total lot costs. Lot dates and lot notes are converted to beancount. The behaviour of ledger and beancount is different when it comes to costs. In ledger, the statement Assets:Test 10.00 EUR @ 0.90 GBP creates the lot `10.00 EUR {0.90 GBP}`. In beancount, this is not the case and a cost is only associated if done so explicitly: Assets:Test 10.00 EUR {0.90 GBP} This makes automatic conversion tricky because some statements should be simple conversions without associating a cost whereas it's vital to preserve the cost in other conversions. Generally, it doesn't make sense to preserve the cost for currency conversion (as opposed to conversions involving commodities like shares and stocks). Since most currency codes consist of 3 characters (`EUR`, `GBP`, `USD`, etc), the script makes a simple conversion (`10.00 EUR @ 0.90 GBP`) if both commodities consist of 3 characters. Otherwise it associates a cost (`1 LU0274208692 {48.67 EUR}`). Since some 3 character symbols might be commodities instead of currencies (e.g. `ETH` and `BTH`), the `currency_is_commodity` variable can be used to treat them as commodities and associate a cost in conversions. Similarly, `commodity_is_currency` can be used to configure commodities that should be treated as currencies in the sense that no cost is retained. This is useful if you, for example, track miles or hotel points that are sometimes redeemed for a cash value. Both of these variables expect beancount commodities, i.e. after transformation and mapping. (Note that beancount itself uses the terms "commodity" and "currency" interchangeably.) ## Balance assertions and assignments Ledger [balance assertions](https://www.ledger-cli.org/3.0/doc/ledger3.html#Balance-assertions) are converted to beancount `balance` statements. Please note that beancount evaluates balance assertions at the beginning of the day whereas ledger evaluates them at the end of the day (up to ledger 3.1.1) or at the end of the transaction (newer versions of ledger). Therefore, we schedule the balance assertion for the day *after* the original transaction. This assumes that there are no other transactions on the same day that change the balance again for this account. In addition to balance assertions, ledger also supports [balance assignments](https://www.ledger-cli.org/3.0/doc/ledger3.html#Balance-assignments). ledger2beancount can handle some, but not all types of balance assertions. The most simple case is something like: 2012-03-10 KFC Expenses:Food $20.00 Assets:Cash = $50.00 which can be handled like a balance assertion. However, ledger also allows transactions with two null postings when there's a balance assignment, as in: 2012-03-10 KFC Expenses:Food $20.00 Expenses:Drink Assets:Cash = $50.00 This can't be handled by ledger2beancount. While ledger can calculate how much you spent in `Assets:Cash` and balance it with `Expenses:Drink`, ledger2beancount can't. The transformation of this transaction will lead to two null postings, which `bean-check` will flag as invalid. Finally, ledger allows [transactions solely consisting of two null postings](https://www.ledger-cli.org/3.0/doc/ledger3.html#Resetting-a-balance) when one has a balance assignment: 2012-03-10 Adjustment Assets:Cash = $500.00 Equity:Adjustments ledger2beancount will create a beancount `pad` statement, followed by a `balance` statement the following day, to set the correct balance. ## Automated transactions Ledger's [automated transactions](https://www.ledger-cli.org/3.0/doc/ledger3.html#Automated-Transactions) are not supported in beancount. They are added as comments to the beancount file. ## Periodic transactions Ledger's [periodic transactions](https://www.ledger-cli.org/3.0/doc/ledger3.html#Periodic-Transactions) are not supported in beancount. They are added as comments to the beancount file. ## Virtual postings Ledger's concept of [virtual postings](https://www.ledger-cli.org/3.0/doc/ledger3.html#Virtual-postings) does not exist in beancount. Ledger has two types of virtual postings: those in parentheses (`(Budget:Food)`) which don't have to balance and those in brackets (`[Budget:Food]`) which have to balance. The former violate the accounting equation and can't be converted to beancount. The latter can be converted by making them into "real" accounts. ledger2beancount will do this if the `convert_virtual` option is set to `true`. By default, ledger2beancount will simply skip all virtual postings. If you set `convert_virtual` to `true`, be aware that all account names have to start with one of five assets classes (`Assets`, etc). This is often not the case for virtual postings, so you will have to rename or map these account names. ## Inline math Very simple inline math is supported in postings. Specifically, basic multiplications and divisions are supported, such as shown in the following transactions: 2018-03-26 * Simple inline math Assets:Test1 1 GBP @ (1/1.14 EUR) Assets:Test2 -0.88 EUR 2018-03-26 * Simple inline math Assets:Test1 (1 * 3 GBP) Assets:Test2 -3 GBP Support for more complex inline math would require substantial changes to the parser. ## Implicit conversions ledger allows implicit conversions under some circumstances, such as in this example: 2019-01-29 * Implicit conversion Assets:A 10.00 EUR Assets:B -11.42 USD They are generally a bad idea since they make it very easy to hide problems that are hard to track down. beancount doesn't support implicit conversions. ledger2beancount supports implicit conversions if there are only two postings in a transaction (the most common case). More complex implicit conversations are not supported. ## Fixated prices and costs ledger allows you to ["fix" the cost or price](https://www.ledger-cli.org/3.0/doc/ledger3.html#Fixated-prices-and-costs) at the time of a transaction, which means the amount will not be revalued subsequently when the price of the commodity changes in the `pricedb`. beancount doesn't have a notion of a fixated price or cost. However, you can achieve the same result in beancount. ledger2beancount will always convert ledger fixated prices and costs to costs in beancount. This way, the original cost is always attached to the transaction. You can then use `SUM(COST(position))` to get the original value. ## hledger syntax The syntax of [hledger](http://hledger.org/) is largely compatible with that of ledger. If the `hledger` config option is set to `true`, ledger2beancount will look for some hledger specific features: 1) hledger allows the [separation of a transaction's description into payee and note](http://hledger.org/journal.html#payee-and-note) (narration) using the pipe character (`payee | narration`). 2) hledger allows `date:` and `date2:` to specify [posting dates](http://hledger.org/journal.html#posting-dates) in posting comments in addition to ledger's `[date=date2]` syntax. 3) The syntax of tags is different in hledger: `tag1: tag2:, tag3:` in hledger vs `:tag1:tag2:tag3:` in ledger. ## Ignoring certain lines Sometimes it makes sense to exclude certain lines from the conversion. For example, you may not want a specific `include` directive to be added to the beancount file if the file contains ledger-specific definitions or directives with no equivalence in beancount. ledger2beancount allows you to define a marker in the config file as `ignore_marker`. If this marker is found as a ledger comment on a line, the line will be skipped and not added to the beancount output. For example, given the config setting ignore_marker: NoL2B you could do this: C 1.00 Mb = 1024 Kb ; NoL2B If you want to skip several lines, you can use `$ignore_marker begin` and `$ignore_marker end`. This syntax is also useful for ledger `include` directives, which don't allow a comment on the same line. ; NoL2B begin include ledger-specific-header.ledger ; NoL2B end Since some people use ledger and beancount in parallel using ledger2beancount, it is sometimes useful to put beancount-specific commands in the input file. Of course, they may not be valid in ledger. Therefore, you can put a commented out line in the ledger input, mark it with the `$keep_marker` and ledger2beancount will uncomment the line and put it in the output. Given the input ; 2013-11-03 note Liabilities:CreditCard "Called about fraud" ; L2Bonly ledger2beancount will add the following line to the beancount output: 2013-11-03 note Liabilities:CreditCard "Called about fraud" You can also use `$keep_marker begin` and `$keep_marker end` to denote multiple lines that should be included in the output: ; L2Bonly begin ; 2014-07-09 event "location" "Paris, France" ; 2018-09-01 event "location" "Bologna, Italy" ; L2Bonly end # Unsupported features ## Unsupported in beancount The following features are not supported in beancount and therefore commented out during the conversion from ledger to beancount: * Automated transactions * Commodity conversion (`C AMOUNT1 = AMOUNT2`) * Commodity format (`D AMOUNT`) * Commodity pricing: ignore pricing (`N SYMBOL`) * Timeclock support (`I`, `i`, `O`, `o`, `b`, `h`) * Periodic transactions ## Unsupported in ledger2beancount The following ledger features are currently not supported by ledger2beancount: * The `define` directive Contributions [are welcome!](https://github.com/zacchiro/ledger2beancount/blob/master/docs/contributing.md) # Configuration options ## Input options The following options may be needed for ledger2beancount to interpret your ledger files correctly. date_format : The date format used in your ledger file (default: `%Y-%m-%d`). date_format_no_year : The date format for dates without the year when ledger's `Y`/`year` directive is used (default: `%m-%d`). ledger_indent : Sets the indentation level used in your ledger file (default: `4`). decimal_comma : Parses amounts with the decimal comma (e.g. `10,00 EUR`). Set this option to `true` if you use option `--decimal-comma` in ledger. hledger : Tells ledger2beancount whether to attempt to parse hledger-specific features. ## Other options beancount_indent : Sets the indentation level for the generated beancount file (default: `2`). operating_currencies : A list of frequently used currencies. This is used by fava, the web UI for beancount. automatic_declarations : Emit account and commodity declarations. (Default: `true`) Note: the declarations done in ledger via `account` and `commodity` declarations are always converted. If this option is `true`, declarations are created for those which have not been explicitly declared in ledger but used. account_open_date : The date used to open accounts (default: `1970-01-01`). commodities_date : The date used to create commodities (default: `1970-01-01`). beancount_header : Specifies a file which serves as a beancount "header", i.e. it's put at the beginning of the converted beancount file. You can use such a header to specify options for beancount, such as `option "title"`, define `plugin` directives or beancount `query` information. ignore_marker : Specifies a marker that tells ledger2beancount to ignore a line if the marker is found. keep_marker : Specifies a marker that tells ledger2beancount to take a line from the input that is commented out, uncomment it and display it in the output. convert_virtual : Specifies whether virtual postings should be converted. If set to `true`, virtual postings in brackets will be made into real accounts. (Virtual postings in parentheses are always ignored, regardless of this option.) account_map : Specifies a hash of account names to be mapped to other account names. account_regex : Specifies a hash of regular expressions to replace account names. commodity_map : Specifies a mapping of ledger commodities to beancount commodities. metadata_map : Specifies a mapping of ledger metadata keys to corresponding beancount keys. payee_tag : Specify a metadata tag (after the mapping done by `metadata_map`) used to set the payee. payer_tag : Specify a metadata tag (after the mapping done by `metadata_map`) used to set the payee. payee_split : Specifies a list of regular expressions to split ledger's payee field into payee and narration. You have to use the named capture groups `payee` and `narration`. payee_match : Specifies a list of regular expressions and corresponding payees. The whole ledger payee becomes the narration and the matched payee from the regular expression becomes the payee. postdate_tag : Specifies the metadata tag to be used to store posting dates. (Use the empty string if you don't want the metadata to be added to beancount.) auxdate_tag : Specifies the metadata tag to be used to store auxiliary dates (also known as effective dates; or `date2` in hledger). (Use the empty string if you don't want the metadata to be added to beancount.) code_tag : Specifies the metadata tag to be used to store transaction codes. (Use the empty string if you don't want the metadata to be added to beancount.) link_match : Specifies a list of regular expressions that will cause a tag to be rendered as a link. link_tags : Specifies a list of metadata tags whose values should be converted to beancount links instead of metadata. Tags are case insensitive and values must not contain whitespace. currency_is_commodity : Specifies a list of commodities that should be treated as commodities rather than currencies even though they consist of 3 characters (which is usually a characteristic of a currency). Expects beancount commodities (i.e. after transformation and mapping). commodity_is_currency : Specifies a list of commodities that should be treated as currencies (in the sense that cost is not retained). Expects beancount commodities (i.e. after transformation and mapping). # Bugs and contributions If you find any bugs in ledger2beancount or believe the conversion from ledger to beancount could be improved, please [open an issue](https://github.com/zacchiro/ledger2beancount/issues). Please include a small test case so we can reproduce the problem. See [the contributing guide](contributing.md) for more information on how to contribute to ledger2beancount. ledger2beancount-2.0/examples/000077500000000000000000000000001362415351400164205ustar00rootroot00000000000000ledger2beancount-2.0/examples/illustrated.ledger000066400000000000000000000462351362415351400221520ustar00rootroot00000000000000 ; ------------------------------------------------------------------------ ; Accounts ; ------------------------------------------------------------------------ ; Declarations are converted to ledger ; The variable `account_open_date` (here 2010-03-01) is used as the open date ; The "note" is converted to "description" account Assets:Test note Just a test account ; Note that account declarations are not optional in beancount! account Assets:-Test account Assets:A account Assets:B account Assets:Bar account Assets:Bal account Assets:École account Assets:Föö account Assets:MyLedger account Assets:Test1 account Assets:Test2 account Assets:Wallet account Equity:Opening-Balance account Expenses:Purchase account Liabilities:Credit Card_Test ; Liabilities:Credit Card_Test -> Liabilities:Credit-Card-Test 2018-03-28 * Space and many other characters not allowed in account names Liabilities:Credit Card_Test 10.00 EUR Assets:Wallet ; expenses:purchase -> Expenses:Purchase 2018-03-28 * First letter of each account component has to be upper case expenses:purchase 10.00 EUR Assets:Wallet ; Assets:-Test -> Assets:XTest 2018-03-28 * First letter of each account component has to be an upper case letter or a number Assets:-Test 10.00 EUR Assets:B ; Assets:MyLedger -> Assets:MyBeancount (using `account_map`) 2018-03-28 * Account names can be mapped using `account_map` Assets:MyLedger 10.00 EUR Assets:B ; Account names may contain UTF-8 letters but commodities must not 2018-03-28 * Account names may contain UTF-8 letters Assets:Föö 10.00 EUR Assets:École ; ------------------------------------------------------------------------ ; Amounts ; ------------------------------------------------------------------------ ; With `decimal_comma` false (the default), commas as thousand separator ; are retained as they are allowed by beancount. 2018-03-28 * Amounts can contain commas as thousand separator Assets:A 1,000,000.00 EUR Assets:B ; Set `decimal_comma` to `true` if you use `--decimal-comma` in ledger ; Beancount currently doesn't support decimal commas, so they are ; replaced. ; With `decimal_comma: true`, the following is accepted by ; ledger2beancount and converted to 10.12 EUR. ;2018-03-28 * Amounts can contain commas as thousand separator ; Assets:A 10,12 EUR ; Assets:B ; ------------------------------------------------------------------------ ; Commodities ; ------------------------------------------------------------------------ ; Declarations are converted to ledger ; The variable `commodities_date` is used as the open date ; The "note" is converted to "name" commodity EUR note Euro ; £10.00 -> 10.00 EUR 2018-03-28 * Commodity symbols like £ have to be converted Expenses:Purchase £10.00 Assets:Wallet ; EUR 10.00 -> 10.00 EUR 2018-03-28 * Commodities in front of the amount are converted to amount, followed by commodity Expenses:Purchase EUR 10.00 Assets:Wallet ; "DE0002635307" -> DE0002635307 2018-03-28 * Quoted commodities are stripped" Assets:A 1 "DE0002635307" Assets:B ; "C mm.di!y" -> C-MM.DI-Y 2018-03-28 * Commodities are converted to valid beancount commodities Assets:A 1 "C mm.di!y" Assets:B ; "M&M" -> MILESMORE (using `commodity_map`) 2018-03-28 * Commodities can be mapped to other commodities Assets:A 10.00 "M&M" Assets:B ; ------------------------------------------------------------------------ ; Flags ; ------------------------------------------------------------------------ ; beancount: 2018-03-28 txn "Without a transaction flag beancount requires 'txn'" 2018-03-28 Without a transaction flag beancount requires 'txn' Assets:A 10.00 EUR Assets:B 2018-03-28 ! Transactions flags are supported Assets:A 10.00 EUR Assets:B 2018-03-28 Posting flags are supported ! Assets:A 10.00 EUR * Assets:B ; ------------------------------------------------------------------------ ; Dates ; ------------------------------------------------------------------------ ; `date_format` can be adapted to your date format if you don't use ; `YYYY-MM-DD`. beancount only supports `YYYY-MM-DD` ; ledger allows you to set the date so you can skip the year. ; ledger2beancount supports this if `date_format_no_year` is set. ; A complete date in `YYYY-MM-DD` format is generated since beancount ; requires complete dates. Y 2017 ; 03/28 -> 2017-03-28 03/28 * Date without year Assets:A 10.00 EUR Assets:B ; ------------------------------------------------------------------------ ; Auxiliary dates ; ------------------------------------------------------------------------ ; Beancount currently doesn't have a concept of aux dates like ledger does, ; although there;s a proposal in beancount to support dates on the posting ; level. In the meantime, aux dates are converted to metadata. 2018-03-28=2018-03-27 * Ledger supports aux dates but beancount currently does not Assets:A 10.00 EUR Assets:B 2018-03-28 * Same for aux dates on postings Assets:A 10.00 EUR ; [=2018-03-27] Assets:B ; ------------------------------------------------------------------------ ; Transaction codes ; ------------------------------------------------------------------------ ; If `code_tag` is set, transaction codes will be converted to metadata 2018-03-28 * (100) Code can be converted to metadata (if `code_tag` is set) Assets:A 10.00 EUR Assets:B ; ------------------------------------------------------------------------ ; Narration ; ------------------------------------------------------------------------ ; The narration has to be quoted in beancount ; beancount: 2018-03-28 * "Ledger's payee becomes the narration" 2018-03-28 * Ledger's payee becomes the narration Assets:A 10.00 EUR Assets:B ; beancount: 2018-03-28 * "Ledger's payee becomes the narration - \"quotes\" are handled" 2018-03-28 * Ledger's payee becomes the narration - "quotes" are handled Assets:A 10.00 EUR Assets:B ; ------------------------------------------------------------------------ ; Payees ; ------------------------------------------------------------------------ ; Ledger does not distinguish between payee and narration (a description, ; basically a "memo" field). Beancount does. ; ledger2beancount offers several features to obtain a payee. ; `payee_split`: can be used split the ledger payee into payee and ; narration ; For example: ; payee_split: ; - (?.*?)\s+\((?.*)\) ; This puts everything in brackets as the payee. The rest is used ; as the narration ; beancount: 2018-03-28 * "Tesco" "Supermarket" 2018-03-28 * Supermarket (Tesco) Assets:A 10.00 GBP Assets:B ; `payee_match` will assign a payee based on the match ; payee_match: ; - ^Oyster top-up: TfL ; Assign payee "TfL" to everything matching "Oyster top-up". ; beancount: 2018-03-28 * "TfL" "Oyster top-up" 2018-03-28 * Oyster top-up Assets:A 10.00 EUR Assets:B ; `payee_tag` and `payer_tag` ; Use metadata with the key from `payee_tag` or `payer_tag` for payee. ; payee_tag: payee ; beancount: 2018-03-28 * "Martin "Test" 2018-03-28 * Test ; Payee: Martin Assets:A 10.00 EUR Assets:B ; payer_tag: payer ; beancount: 2018-03-28 * "Martin "Test" 2018-03-28 * Test ; Payer: Martin Assets:A 10.00 EUR Assets:B ; ------------------------------------------------------------------------ ; Metadata ; ------------------------------------------------------------------------ ; Beancount doesn't use comments for tags or metadata ; For metadata, you write ; key: "value" 2018-03-28 * Metadata ; key: value Assets:A 10.00 EUR Assets:B ; Metadata keys can be converted to different keys with `metadata_map` ; metadata_map: ; foo: bar ; beancount: ; bar: "test" 2018-03-28 * Metadata keys can be converted: foo -> bar ; foo: test Assets:A 10.00 EUR Assets:B ; In beancount, metadata values generally have to be quoted. ; ledger allows typed metadata (`key::`) and this is not quoted ; in beancount. This makes sense in certain cases (e.g. dates), ; but might not be the right thing for you. ; beancount: ; year: 2017 2018-03-28 * Typed metadata is not quoted ; Year:: 2017 Assets:A 10.00 EUR Assets:B ; ------------------------------------------------------------------------ ; Tags ; ------------------------------------------------------------------------ ; Tags: you put them after the narration in beancount (but on the same ; line) ; beancount: 2018-03-28 * "Tag" #test 2018-03-28 * Tag ; :test: Assets:A 10.00 EUR Assets:B ; In ledger, you can declare tags: tag foo ; This is not required in beancount and there's no way to do it, so ; ledger2beancount skips all tag declarations. (It handles ledger's ; "apply tag" correctly, though) ; ------------------------------------------------------------------------ ; Links ; ------------------------------------------------------------------------ ; Links in beancount allow you to link different transactions together ; (put `^foo` on the narration line to add a link `foo`) ; `link_match` allows you to change tags to links. If it matches, it ; will become a ^link instead of a #tag. ; link_match: ; - ^\d\d\d\d-\d\d-\d\d- ; beancount: 2018-03-28 * "Tag" #test ^2018-03-28-test 2018-03-28 * Tag and link ; :test:2018-03-28-test: Assets:A 10.00 EUR Assets:B ; ------------------------------------------------------------------------ ; Comments ; ------------------------------------------------------------------------ ; Comments are the same in beancount as in ledger (except that you don't ; use comments for tags and metadata). ; comment 2018-03-28 * Show comments Assets:A 10.00 EUR ; comment Assets:B ; comment ; ------------------------------------------------------------------------ ; Virtual costs ; ------------------------------------------------------------------------ ; beancount doesn't have the concept of virtual costs at the moment. ; Maybe this feature will come in the future. ; For now, they are converted to "normal" costs ; (@) -> @ 2018-03-28 * beancount lacks support for virtual costs Assets:A 10.00 EUR (@) 0.88 GBP Assets:B ; ------------------------------------------------------------------------ ; Lots ; ------------------------------------------------------------------------ 2018-03-28 * Lots are supported Assets:A 1 "DE0002635307" {36.11 EUR} Assets:B ; The syntax for lot dates and lot notes are different ; beancount: 1 DE0002635307 {36.11 EUR, 2018-03-27} 2018-03-28 * Lots dates are different Assets:A 1 "DE0002635307" {36.11 EUR} [2018-03-27] Assets:B ; beancount: 1 DE0002635307 {36.11 EUR, "Note!"} 2018-03-28 * Lots notes are different Assets:A 1 "DE0002635307" {36.11 EUR} (Note!) Assets:B ; beancount: 1 DE0002635307 {36.11 EUR, 2018-03-27, "Note!"} 2018-03-28 * Lots date and lot note Assets:A 1 "DE0002635307" {36.11 EUR} [2018-03-27] (Note!) Assets:B ; Lots, costs and prices 2018-03-28 * Conversions are handled Assets:Test 10.00 EUR @ 0.90 GBP Assets:B ; But the semantics are different! ; In ledger, the transaction above actually creates a lot (check with ; `--lots`), i.e. we now have 10.00 EUR at a cost of 0.90 GBP (on ; 2018-03-28) ; ledger --flat --lots bal assets:test ; 10.00 EUR {0.90 GBP} [2018-03-28] Assets:Test ; You think you can do this: 2018-03-28 * Remove this lot (wrong!) Expenses:Purchase 5.00 EUR Assets:Test -5.00 EUR ; but this does not remove the lot! ; ledger --flat --lots bal assets:test ; -5.00 EUR ; 10.00 EUR {0.90 GBP} [2018-03-28] Assets:Test ; Right, we removed 5.00 EUR but we still have the 10.00 EUR held at ; a unit cost of 0.90 GBP with date 2018-03-28 ; Many ledger users are not aware because they never look at the ; lot info with `--lots`. ; You'd have to do: 2018-03-28 * Remove this lot (correct) Expenses:Purchase 4.50 GBP Assets:Test -5.00 EUR {0.90 GBP} [2018-03-28] ; Beancount handles this differently ; And this is why the last transaction will generate an error ; in beancount (convert this file with ledger2beancount and ; check with `bean-check`). (In fact, the other reason it ; A simple conversion `A @ B` does not associate a cost. In fact, we ; shouldn't say "simple conversion" here. `A @ B` means `A` at price ; `B`. It's a *price*. ; In ledger, as we've seen, a price creates a lot (associates a cost ; in beancount lingo). ; If you want to associate a cost in beancount, you have to use ; `A {B}` ; So in the last transaction, we remove something held at a cost ; but it doesn't exist (not in beancount because `@` doesn't ; create a cost). And so beancount gives an error. (Ledger ; generates a lot. But even more so, you can remove lots which ; don't exist. Ledger allows this silently.) ; This creates a cost in beancount: 2018-03-28 * A cost Assets:A 10.00 EUR {0.90 GBP} Assets:B ; But do we really want to do that with currencies? Let's say ; your operating currency is GBP. You travel to Spain, exchange ; some GBP to EUR, spend some and some are left in your wallet ; after your return. Next year you go again and you exchange ; some more; ; So now you have 10 EUR at 0.90 GBP from last time and 120 EUR ; at 0.88 GBP from this time. ; You can track this using a cost: ; 10.00 EUR {0.90 GBP} ; 120.00 EUR {0.88 GBP} ; But do you want to? ; In most cases, the answer is no. So don't use a cost in beancount. ; Use a price. ; Hmm, but now it gets tricky. ; What if we have `A @ B` in ledger. Should it be a price or a cost ; in beancount? As we saw in the example of our holiday in Spain, ; we want a price. But if I'm buying shares/stocks in a company, ; I definitely want to retain the cost. I own a certain number of ; shares bought at a certain price. 2018-03-28 * Shares with cost Assets:A 1 "DE0002635307" {36.11 EUR} Assets:B ; But in ledger, many people write this as: 2018-03-28 * Shares with cost Assets:A 1 "DE0002635307" @ 36.11 EUR Assets:B ; because, as we've seen, it creates a lot with the right ; information. ; Ok, so we have: 2018-03-28 * Currency -> currency Assets:A 10.00 EUR @ 0.90 GBP Assets:B ; and 2018-03-28 * Shares with cost Assets:A 1 "DE0002635307" @ 36.11 EUR Assets:B ; It's the same syntax but a different meaning! ; Fortunately, it's fairly straightforward to differentiate. ; ledger2beancount differentiates between "currencies" (which could ; not have a cost) and "commodities" (which should have a cost). ; Note that beancount itself uses these terms interchangeably, but ; in terms of ledger2beancount there is a difference. ; ; If we find `A @ B`, we'll keep `A @ B` (`A` at price `B`, no ; cost is retained) if it's a currency. But if it's a commodity, ; we'll convert `A @ B` to `A {B}`. ; If a commodity has 3 characters (like EUR, USD, GBP), we assume ; it's a currency. The variable `currency_is_commodity` can override ; this. This is useful for ETH or BTC which have 3 characters. (You ; may want to use XETH and XBTC btw.) ; ; And we have `commodity_is_currency` to say that a commodity is a ; currency. For example, if you track hotel points or airline miles ; in ledger/beancount, you probably don't want to keep a cost ; around. ; Some examples: ; beancount: 10.00 EUR @ 0.88 GBP 2018-03-28 * Two currencies: don't keep cost Assets:A 10.00 EUR @ 0.88 GBP Assets:B ; beancount: 1 DE0002635307 {36.11 EUR} 2018-03-28 * Commodity: keep cost Assets:A 1 "DE0002635307" @ 36.11 EUR Assets:B ; currency_is_commodity: ; - BTC ; beancount: 1 BTC {6482 EUR} 2018-03-28 * What looks like a currency but isn't Assets:A 1 BTC @ 6482 EUR Assets:B ; commodity_is_currency: ; - MILESMORE ; beancount: 10.00 EUR @ 3000 MILESMORE 2018-03-28 * What looks like a commodity but isn't - get a 10 EUR voucher for 3000 Miles&More points Assets:A 10.00 EUR @@ 3000 "M&M" Assets:B ; We hope that covers all cases! ; ------------------------------------------------------------------------ ; Balance assertions ; ------------------------------------------------------------------------ ; beancount has a "balance" directive ; There is a subtle difference though: ; ledger evaluates them at the end of the transaction ; beancount evaluates balance assertions at the *beginning* of the day ; ledger2beancount therefore schedules the balance assertion for the ; day *after* the original transaction. But this assumes that there ; are no other transactions on the same day that change the balance ; again for this account. 2018-03-28 * Balance asserts are evaluated immediately in ledger, not so in beancount Assets:Bal 10.00 EUR = 10.00 EUR Equity:Opening-Balance -10.00 EUR ; ------------------------------------------------------------------------ ; Automated transactions ; ------------------------------------------------------------------------ ; Automated transactions are not supported in beancount, so ledger2beancount ; comments them out. You may have to write a beancount plugin. = expr true Assets:A 50.00 USD Assets:B -50.00 USD ; ------------------------------------------------------------------------ ; Periodic transactions ; ------------------------------------------------------------------------ ; Periodic transactions are not supported in beancount, so ledger2beancount ; comments them out. You may have to write a beancount plugin. ~ Yearly Expenses:Auto:Repair $500.00 Assets ; ------------------------------------------------------------------------ ; Inline math ; ------------------------------------------------------------------------ ; Ledger and beancount both allow inline math. ledger2beancount handles ; simple cases only! Basically, divisions and multiplications. And ; In beancount, the brackets are different: ; 1 GBP @ (1/1.14 EUR) -> 1 GBP @ (1/1.14) EUR 2018-03-26 * Simple inline math Assets:Test1 1 GBP @ (1/1.14 EUR) Assets:Test2 -0.88 EUR 2018-03-26 * Simple inline math Assets:Test1 (1 * 3 GBP) Assets:Test2 -3 GBP ; Ledger allows *a lot*, e.g. (1 EUR + 2 EUR). I don't know what beancount ; allows, but ledger2beancount doesn't handle any complex expressions. ; ------------------------------------------------------------------------ ledger2beancount-2.0/examples/illustrated.yml000066400000000000000000000045671362415351400215130ustar00rootroot00000000000000 date_format: "%Y-%m-%d" # Date without year (if ledger's Y/year directive is used) date_format_no_year: "%m/%d" # Date used to open accounts account_open_date: "2010-03-01" # Unix epoch, just because # Date used to create commodities commodities_date: "2010-03-01" # Unix epoch, just because beancount_indent: 2 ledger_indent: 4 # list of frequently used currencies (not *all* used currencies) operating_currencies: - EUR # Set to `true` if you use option --decimal-comma in ledger decimal_comma: false # mapping of ledger metadata key to corresponding beancount key metadata_map: x-payee: payee x-payer: payer foo: bar # metadata tags (*after* above mapping) used for specific purposes payee_tag: payee payer_tag: payer # payee_split: a list of regular expressions which allows you # to split ledger's payee field into payee and narration. # Use named capture groups "payee" and "narration". payee_split: - (?.*?)\s+\((?.*)\) # payee_match: a list of regular expressions and corresponding # payees. The whole ledger payee becomes the narration and # the matched payee from the regular expression becomes the # payee. payee_match: - ^Oyster top-up: TfL account_map: "Equity:Opening-balance": Equity:Opening-Balance Assets:MyLedger: Assets:MyBeancount # mapping of ledger commodities to valid beancount commodities commodity_map: "$": USD "£": GBP "€": EUR "¥": JPY M&M: MILESMORE # You can set the following metadata tags to an empty string if you # don't want the metadata to be added to beancount. auxdate_tag: aux-date code_tag: code # A list of regular expressions that will cause a tag to be # rendered as a link. link_match: - ^\d\d\d\d-\d\d-\d\d- # A list of metadata tags whose values should be converted to # beancount links instead of metadata. # Tags are case insensitive. Values must not contain whitespace. link_tags: [] # A list of commodities that should be treated as commodities # rather than currencies even though they consist of 3 characters # (which is usually a characteristic of a currency). Expects # beancount commodities (i.e. after transformation and mapping). currency_is_commodity: - BTC - ETH - IBM # A list of commodities that should be treated as currencies # (in the sense that cost is not retained). Expects beancount # commodities (i.e. after transformation and mapping). commodity_is_currency: - MILESMORE ledger2beancount-2.0/examples/simple.ledger000066400000000000000000000010271362415351400210750ustar00rootroot00000000000000 2018-03-28 Simple transaction Expenses:Purchase 10.00 EUR Assets:Wallet 2018-03-28 Currency code, posting flag Expenses:Purchase £20.00 * Assets:Wallet 2018-03-28=2018-03-27 * (100) Transaction flag, aux date, code, conversion Expenses:Purchase 10.00 EUR @ 0.86 GBP Assets:Wallet -8.60 GBP 2018-03-28 * Meta data ; :tag: ; Key: value ; Typed:: [2018-03-20] Expenses:Purchase 10.00 EUR Assets:Wallet ledger2beancount-2.0/ledger2beancount.yml000066400000000000000000000073251362415351400205570ustar00rootroot00000000000000 date_format: "%Y-%m-%d" # Date without year (if ledger's Y/year directive is used) date_format_no_year: "%m-%d" # Date used to open accounts account_open_date: "1970-01-01" # Unix epoch, just because # Date used to create commodities commodities_date: "1970-01-01" # Unix epoch, just because beancount_indent: 2 ledger_indent: 4 # list of frequently used currencies (not *all* used currencies) operating_currencies: - EUR # Attempt to parse hledger specific features hledger: false # You can specify a file which serves as a beancount "header", i.e. # it's put at the beginning of the converted beancount file. You can # specify options for beancount, such as `option "title"`, define # `plugin` directives or beancount `query` information. #beancount_header: # emit account and commodity declares # (Note: the declarations done in ledger via `account` and # `commodity` are always converted. If this option is true, # declarations are created for those which have not been # explicitly declared in ledger but used.) automatic_declarations: true # Set to `true` if you use option --decimal-comma in ledger decimal_comma: false # Should virtual postings be converted. If set to true, virtual # postings in brackets will be made into real accounts. (Virtual # postings in parentheses are always ignored, regardless of this option) convert_virtual: false # mapping of ledger metadata key to corresponding beancount key metadata_map: x-payee: payee x-payer: payer # metadata tags (*after* above mapping) used to set payee payee_tag: payee payer_tag: payer # payee_split: a list of regular expressions which allows you # to split ledger's payee field into payee and narration. # Use named capture groups "payee" and "narration". payee_split: - (?.*?)\s+\((?Tesco)\) # payee_match: a list of regular expressions and corresponding # payees. The whole ledger payee becomes the narration and # the matched payee from the regular expression becomes the # payee. payee_match: - (?i)^Oyster card top-up: TfL # A hash of account names to be mapped to other account # names. account_map: "Equity:Opening-balance": Equity:Opening-Balance # A hash of regular expressions to replace account names. account_regex: ^Accrued:Accounts Payable:(.*): Liabilities:Accounts-Payable:$1 ^Accrued:Accounts Receivable:(.*): Assets:Accounts-Receivable:$1 # mapping of ledger commodities to valid beancount commodities commodity_map: "$": USD "£": GBP "€": EUR "¥": JPY # You can set the following metadata tags to an empty string if you # don't want the metadata to be added to beancount. postdate_tag: date auxdate_tag: aux-date code_tag: code # A list of regular expressions that will cause a tag to be # rendered as a link. link_match: - ^\d\d\d\d-\d\d-\d\d- # A list of metadata tags whose values should be converted to # beancount links instead of metadata. # Tags are case insensitive. Values must not contain whitespace. link_tags: [] # A list of commodities that should be treated as commodities # rather than currencies even though they consist of 3 characters # (which is usually a characteristic of a currency). Expects # beancount commodities (i.e. after transformation and mapping). currency_is_commodity: - BTC - ETH - IBM # A list of commodities that should be treated as currencies # (in the sense that cost is not retained). Expects beancount # commodities (i.e. after transformation and mapping). commodity_is_currency: - MARRIOTT - MILESMORE - NECTAR # A marker that tells ledger2beancount to ignore a line if the # marker is found. #ignore_marker: NoL2B # A marker that tells ledger2beancount to take a line from # the input that is commented out, uncomment it and display # it in the output. keep_marker: L2Bonly ledger2beancount-2.0/misc/000077500000000000000000000000001362415351400155355ustar00rootroot00000000000000ledger2beancount-2.0/misc/initial-git-import.sh000077500000000000000000000017551362415351400216260ustar00rootroot00000000000000#!/bin/sh # ledger2beancount started as an ad hoc personal script. As such it was # maintained in zack's private Ledger Git repository. It was later spun off # as an independent project, when tbm started to heavily contribute to it. The # script below was used to migrate the git history of ledger2beancount from # zack's private repo to a new, independent one. It is ad hoc, uninteresting, # and archived here just for historical reasons. flags="--force --prune-empty" revs="-- --all" git_url="git@*censored*:ledger" git clone "$git_url" ledger2beancount cd ledger2beancount git filter-branch $flags --subdirectory-filter bin $revs git filter-branch $flags --tree-filter "ls | grep -v beancount | xargs rm" $revs git filter-branch $flags --env-filter ' export GIT_AUTHOR_NAME="Martin Michlmayr" export GIT_AUTHOR_EMAIL="tbm@cyrius.com" export GIT_COMMITTER_NAME="Stefano Zacchiroli" export GIT_COMMITTER_EMAIL="zack@upsilon.cc" ' -- $(git rev-list HEAD --since=2018-03-10 | tail -n 1)^..HEAD ledger2beancount-2.0/tests/000077500000000000000000000000001362415351400157445ustar00rootroot00000000000000ledger2beancount-2.0/tests/accounts.beancount000066400000000000000000000315111362415351400214640ustar00rootroot00000000000000;---------------------------------------------------------------------- ; ledger2beancount conversion notes: ; ; - Skipped second account declaration for Expenses:Travel (old Expenses:Bar:Travel) ; - Virtual posting in parentheses ignored ; - Account Revenue not allowed; it needs a subaccount, e.g. Revenue:Subaccount ; - Non-standard root name Revenue used; please set beancount options name_* ; - Account Accrued:Accounts Payable:Baz renamed to Liabilities:Accounts-Payable:Baz ; - Account Assets:Bank Debian)bar renamed to Assets:Bank-Debian-bar ; - Account Assets:Bank [Debian] renamed to Assets:Bank--Debian- ; - Account Assets:test renamed to Assets:Test ; - Account Assets:♚_DASD!;?@#$!%^& *"(*(0-;♚ds renamed to Assets:X-DASD----------------0---ds ; - Account Assets:♚foo:♚bar renamed to Assets:Xfoo:Xbar ; - Account Expenses:Baz: renamed to Expenses:Baz ; - Account Expenses:École républicaine renamed to Expenses:École-républicaine ; - Account Expenses:école renamed to Expenses:École ; - Account Liabilities:Credit Card:Test renamed to Liabilities:Credit-Card:Test ; - Account Liabilities:credit Card:test renamed to Liabilities:Credit-Card:Test ; - Account Revenue renamed to Revenue:Subaccount ; - Account assets:test renamed to Assets:Test ; - Account expenses:purchase renamed to Expenses:Purchase ; - Collision for account Assets:Collision: Assets:Coll1, Assets:Coll2 ; - Collision for account Assets:Test: Assets:Test, Assets:test, assets:test ; - Collision for account Equity:Opening-Balance: Equity:Opening balance, Equity:Opening-Balance ; - Collision for account Expenses:Travel: Expenses:Bar:Travel, Expenses:Foo:Travel ; - Collision for account Liabilities:Credit-Card:Test: Liabilities:Credit Card:Test, Liabilities:credit Card:test ;---------------------------------------------------------------------- option "title" "Test account names" option "name_income" "Revenue" 1970-01-01 open Assets:A 1970-01-01 open Assets:Aaa 1970-01-01 open Assets:Accounts-Receivable:Bar 1970-01-01 open Assets:Accounts-Receivable:Foo 1970-01-01 open Assets:Bank 1970-01-01 open Assets:Bash 1970-01-01 open Assets:Bbb 1970-01-01 open Assets:Collision 1970-01-01 open Assets:MuchLonger 1970-01-01 open Assets:Short 1970-01-01 open Equity:Trading:Currency 1970-01-01 open Expenses:Baz 1970-01-01 open Expenses:Foo 1970-01-01 open Liabilities:Accounts-Payable:Baz 1970-01-01 open Liabilities:MasterCard 1970-01-01 open Revenue:Foo 1970-01-01 open Revenue:Interest 1970-01-01 open Revenue:Salary 1970-01-01 open Revenue:Subaccount 1970-01-01 commodity USD ; Beancount: 2.1.0 1970-01-01 open Assets:Test description: "Test account" ; alias food ; default 1970-01-01 open Equity:Opening-Balance description: "opening balance..." 1970-01-01 open Assets:Vouchers:99Ranch 1970-01-01 open Assets:Vouchers:99Ranch:99Test 1970-01-01 open Liabilities:Credit-Card:Test 1970-01-01 open Assets:Vouchers:99test 1970-01-01 open Assets:X-DASD----------------0---ds 1970-01-01 open Assets:Xfoo:Xbar 1970-01-01 open Expenses:École-républicaine 1970-01-01 open Expenses:École 1970-01-01 open Assets:Crowns 1970-01-01 open Assets:Test:I-Love-Crowns 1970-01-01 open Assets:Commodity-Test123 1970-01-01 open Expenses:Purchase ; These accounts lead to name collision 1970-01-01 open Expenses:Travel 1970-01-01 commodity EUR 2018-03-17 * "Test 1" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 * "Test 2" Assets:Test Equity:Opening-Balance -10.00 EUR 2018-03-17 * "Test 3" Assets:Test 10.00 EUR Equity:Opening-Balance 2018-03-17 * "Test 4" Assets:Test 10 EUR Equity:Opening-Balance ; Account with space 2018-03-17 * "Test" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 * "Test 1" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 * "Test 1" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 txn "Test: account with space and flag" * Assets:Test 10.00 EUR ! Equity:Opening-Balance -10.00 EUR 2018-03-18 * "Test" Assets:Test 10.00 EUR Equity:Opening-Balance ; comment 2018-03-18 * "Account name with space" Liabilities:Credit-Card:Test -10.00 EUR Equity:Opening-Balance 2018-03-18 * "Account name starting with lower case" Assets:Test 10.00 EUR Equity:Opening-Balance 2018-03-18 * "Account name with space and ucfirst" Liabilities:Credit-Card:Test -10.00 EUR Equity:Opening-Balance 2018-03-18 * "Account name starting with digits" Assets:Vouchers:99Ranch 10.00 EUR Equity:Opening-Balance 2018-03-18 * "2 account name starting with digits" Assets:Vouchers:99Ranch:99Test 10.00 EUR Equity:Opening-Balance 2018-03-18 * "Lower case after digit" Assets:Vouchers:99test 10.00 EUR Equity:Opening-Balance 2018-03-26 * "Interesting account name" Assets:X-DASD----------------0---ds 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-26 * "Interesting account name, mapped before conversion" Assets:Crowns 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-26 * "Interesting account name, mapped after conversion" Assets:Test:I-Love-Crowns 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-26 * "Ensure first letter is upper case letter" Assets:Xfoo:Xbar 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-26 * "Drop accents" Expenses:École-républicaine 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-26 * "Ensure first letter is upper case letter" Expenses:École 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-27 * "Account name could be mistaken for commodity" Assets:Test 10.00 EUR Assets:Commodity-Test123 2018-03-28 * "all lower case account names" Expenses:Purchase 10.00 EUR Assets:Test 2018-03-29 * "Mapping creating collision" Assets:Collision 1 EUR Equity:Opening-Balance 2018-03-29 * "Mapping creating collision" Assets:Collision 1 EUR Equity:Opening-Balance 2018-04-18 * "Preserve whitespace: shorter" Assets:Short 10.00 EUR Assets:Test -10.00 EUR 2018-04-18 * "Preserve whitespace: shorter" Assets:Short 10.00 EUR Assets:Test -10.00 EUR 2018-04-18 * "Preserve whitespace: shorter" Assets:Short 10.00 EUR Assets:Test -10.00 EUR 2018-04-18 * "Preserve whitespace: shorter" Assets:Short Assets:Test -10.00 EUR 2018-04-18 * "Preserve whitespace: longer" Assets:MuchLonger 10.00 EUR Assets:Test -10.00 EUR ; Impossible to preserve 2018-04-18 * "Preserve whitespace: longer" Assets:MuchLonger 10.00 EUR Assets:Test -10.00 EUR 2018-04-18 * "Preserve whitespace: longer" Assets:MuchLonger 10.00 EUR Assets:Test -10.00 EUR 2018-04-18 * "Preserve whitespace: longer" Assets:MuchLonger Assets:Test -10.00 EUR 2018-04-18 * "Preserve whitespace: same" Assets:Bash 10.00 EUR Assets:Test -10.00 EUR 2018-04-18 * "Preserve whitespace: same" Assets:Bash 10.00 EUR Assets:A -10.00 EUR 2018-04-18 * "Preserve whitespace: same" Assets:Bash 10.00 EUR Assets:Test -10.00 EUR 2018-04-18 * "Preserve whitespace: same" Assets:Bash Assets:Test -10.00 EUR 2018-10-22 txn "Whitespace is not part of account name" Assets:Test 10.00 EUR Assets:Bank -10.00 EUR 2018-10-22 txn "Whitespace is not part of account name" Assets:Test 10.00 EUR Assets:Bank -10.00 EUR 2018-10-22 txn "Trailing whitespace is not part of account name" Assets:Test 10.00 EUR Assets:Bank 2018-10-22 txn "Trailing whitespace is not part of account name" Assets:Test 10.00 EUR Assets:Bank 2018-10-22 txn "Trailing whitespace is not part of account name" Assets:Test 10.00 EUR Assets:Bank 2018-10-22 txn "Trailing whitespace is not part of account name" Assets:Test 10.00 EUR Assets:Bank 2018-10-22 txn "Trailing whitespace is not part of account name" Assets:Test 10.00 EUR Assets:Bank 2018-10-22 txn "Trailing whitespace is not part of account name" Assets:Test 10.00 EUR Assets:Bank 2019-02-28 txn "Tab after account name" Assets:Test 10.00 EUR Assets:Bank -10.00 EUR 2019-02-28 txn "Tab after account name" Assets:Test 10.00 EUR Assets:Bank -10.00 EUR 1970-01-01 open Assets:Bank:Debian 1970-01-01 open Assets:Bank--Debian- 1970-01-01 open Assets:Bank-Debian-bar 1970-01-01 open Assets:Bank:Debian:Bar 2018-01-02 * "Account name with brackets" Expenses:Foo 10.00 USD Assets:Bank:Debian -10.00 USD 2018-01-02 * "Account name with brackets" Expenses:Foo 10.00 USD Assets:Bank--Debian- -10.00 USD 2018-01-02 * "Account name with brackets" Expenses:Foo 10.00 USD Assets:Bank-Debian-bar -10.00 USD 2018-01-02 * "Account name with brackets" Expenses:Foo 10.00 USD Assets:Bank:Debian:Bar -10.00 USD 2018-01-02 * "Account name with brackets, as virtual posting" Expenses:Foo 10.00 USD Assets:Bank -10.00 USD 2018-01-02 * "Account name with brackets, as virtual posting" Expenses:Foo 10.00 USD Assets:Bank -10.00 USD 2018-01-02 * "Account name with brackets, as virtual posting" Expenses:Foo 10.00 USD Assets:Bank -10.00 USD 2018-01-02 * "Account name with brackets, as virtual posting" Expenses:Foo 10.00 USD Assets:Bank -10.00 USD 2018-01-02 * "Account name with brackets, as virtual posting" Expenses:Foo 10.00 USD Assets:Bank -8.00 USD Assets:Bank:Debian -2.00 USD 2018-01-02 * "Account name with brackets, as virtual posting" Expenses:Foo 10.00 USD Assets:Bank -8.00 USD Assets:Bank--Debian- -2.00 USD 2018-01-02 * "Account name with brackets, as virtual posting" Expenses:Foo 10.00 USD Assets:Bank -8.00 USD Assets:Bank-Debian-bar -2.00 USD 2018-01-02 * "Account name with brackets, as virtual posting" Expenses:Foo 10.00 USD Assets:Bank -8.00 USD Assets:Bank:Debian:Bar -2.00 USD 2019-03-27 txn "Don't confuse account and amount due to tabs" Assets:Bank -35.00 EUR Expenses:Foo 35.00 EUR 2019-03-27 txn "Invalid account: root is not valid, needs subaccount" Assets:Bank 42.00 EUR Revenue:Subaccount 2019-03-27 txn "Non-standard root name" Assets:Bank 100.00 EUR Revenue:Salary -100.00 EUR 2019-03-27 txn "Non-standard root name (after mapping)" Assets:Bank 1.00 EUR Revenue:Interest -1.00 EUR 2019-04-06 * "Name collision and account declarations" Expenses:Travel 11.00 EUR Assets:Bank -11.00 EUR 2019-04-06 * "Name collision and account declarations" Expenses:Travel 22.00 EUR Assets:Bank -22.00 EUR 2019-04-17 * "Mass rename of accounts using account_regex" Assets:Accounts-Receivable:Foo 10.00 EUR Revenue:Foo -10.00 EUR 2019-04-17 * "Mass rename of accounts using account_regex" Assets:Accounts-Receivable:Bar 10.00 EUR Revenue:Foo -10.00 EUR 2019-04-17 * "Mass rename of accounts using account_regex - leads to a name that requires further changes" Liabilities:Accounts-Payable:Baz 10.00 EUR Expenses:Foo -10.00 EUR 2019-04-27 * "Rename account to something which contains original account name" Assets:Bank 10.00 EUR Equity:Trading:Currency -10.00 EUR 2019-04-28 * "Account name with only one letter" Assets:Aaa 10.00 EUR Assets:Bbb 2019-04-28 txn "Deferred account" Liabilities:MasterCard 150.00 EUR Assets:Bank -150.00 EUR 2019-04-29 * "Strange but legal name in ledger - illegal in beancount" Expenses:Baz 100.00 EUR Assets:Bank -100.00 EUR ledger2beancount-2.0/tests/accounts.header000066400000000000000000000001051362415351400207310ustar00rootroot00000000000000 option "title" "Test account names" option "name_income" "Revenue" ledger2beancount-2.0/tests/accounts.ledger000066400000000000000000000246261362415351400207610ustar00rootroot00000000000000; Beancount: 2.1.0 account Assets:Test note Test account alias food default account Equity:Opening balance note opening balance... account Assets:Vouchers:99Ranch !account Assets:Vouchers:99Ranch:99Test @account Liabilities:Credit Card:Test account Assets:Vouchers:99test account Assets:♚_DASD!;?@#$!%^& *"(*(0-;♚ds account Assets:♚foo:♚bar account Expenses:École républicaine account Expenses:école account Assets:♚♛♕♔ account Assets:Test:I love ♚♛♕♔ account Assets:Commodity-Test123 account expenses:purchase ; These accounts lead to name collision account Expenses:Foo:Travel account Expenses:Bar:Travel commodity EUR 2018-03-17 * Test 1 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 * Test 2 Assets:Test Equity:Opening-Balance -10.00 EUR 2018-03-17 * Test 3 Assets:Test 10.00 EUR Equity:Opening-Balance 2018-03-17 * Test 4 Assets:Test 10 EUR Equity:Opening-Balance ; Account with space 2018-03-17 * Test Assets:Test 10.00 EUR Equity:Opening balance -10.00 EUR 2018-03-17 * Test 1 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 * Test 1 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 Test: account with space and flag * Assets:Test 10.00 EUR ! Equity:Opening balance -10.00 EUR 2018-03-18 * Test Assets:Test 10.00 EUR Equity:Opening balance ; comment 2018-03-18 * Account name with space Liabilities:Credit Card:Test -10.00 EUR Equity:Opening balance 2018-03-18 * Account name starting with lower case Assets:test 10.00 EUR Equity:Opening balance 2018-03-18 * Account name with space and ucfirst Liabilities:credit Card:test -10.00 EUR Equity:Opening balance 2018-03-18 * Account name starting with digits Assets:Vouchers:99Ranch 10.00 EUR Equity:Opening-Balance 2018-03-18 * 2 account name starting with digits Assets:Vouchers:99Ranch:99Test 10.00 EUR Equity:Opening-Balance 2018-03-18 * Lower case after digit Assets:Vouchers:99test 10.00 EUR Equity:Opening-Balance 2018-03-26 * Interesting account name Assets:♚_DASD!;?@#$!%^& *"(*(0-;♚ds 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-26 * Interesting account name, mapped before conversion Assets:♚♛♕♔ 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-26 * Interesting account name, mapped after conversion Assets:Test:I love ♚♛♕♔ 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-26 * Ensure first letter is upper case letter Assets:♚foo:♚bar 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-26 * Drop accents Expenses:École républicaine 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-26 * Ensure first letter is upper case letter Expenses:école 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-27 * Account name could be mistaken for commodity Assets:Test 10.00 EUR Assets:Commodity-Test123 2018-03-28 * all lower case account names expenses:purchase 10.00 EUR assets:test 2018-03-29 * Mapping creating collision Assets:Coll1 1 EUR Equity:Opening-Balance 2018-03-29 * Mapping creating collision Assets:Coll2 1 EUR Equity:Opening-Balance 2018-04-18 * Preserve whitespace: shorter Assets:Shorter 10.00 EUR Assets:Test -10.00 EUR 2018-04-18 * Preserve whitespace: shorter Assets:Shorter 10.00 EUR Assets:Test -10.00 EUR 2018-04-18 * Preserve whitespace: shorter Assets:Shorter 10.00 EUR Assets:Test -10.00 EUR 2018-04-18 * Preserve whitespace: shorter Assets:Shorter Assets:Test -10.00 EUR 2018-04-18 * Preserve whitespace: longer Assets:Longer 10.00 EUR Assets:Test -10.00 EUR ; Impossible to preserve 2018-04-18 * Preserve whitespace: longer Assets:Longer 10.00 EUR Assets:Test -10.00 EUR 2018-04-18 * Preserve whitespace: longer Assets:Longer 10.00 EUR Assets:Test -10.00 EUR 2018-04-18 * Preserve whitespace: longer Assets:Longer Assets:Test -10.00 EUR 2018-04-18 * Preserve whitespace: same Assets:Cash 10.00 EUR Assets:Test -10.00 EUR 2018-04-18 * Preserve whitespace: same Assets:Cash 10.00 EUR Assets:A -10.00 EUR 2018-04-18 * Preserve whitespace: same Assets:Cash 10.00 EUR Assets:Test -10.00 EUR 2018-04-18 * Preserve whitespace: same Assets:Cash Assets:Test -10.00 EUR 2018-10-22 Whitespace is not part of account name Assets:Test 10.00 EUR Assets:Bank -10.00 EUR 2018-10-22 Whitespace is not part of account name Assets:Test 10.00 EUR [Assets:Bank] -10.00 EUR 2018-10-22 Trailing whitespace is not part of account name Assets:Test 10.00 EUR Assets:Bank 2018-10-22 Trailing whitespace is not part of account name Assets:Test 10.00 EUR Assets:Bank 2018-10-22 Trailing whitespace is not part of account name Assets:Test 10.00 EUR Assets:Bank 2018-10-22 Trailing whitespace is not part of account name Assets:Test 10.00 EUR [Assets:Bank] 2018-10-22 Trailing whitespace is not part of account name Assets:Test 10.00 EUR [Assets:Bank] 2018-10-22 Trailing whitespace is not part of account name Assets:Test 10.00 EUR [Assets:Bank] 2019-02-28 Tab after account name Assets:Test 10.00 EUR Assets:Bank -10.00 EUR 2019-02-28 Tab after account name Assets:Test 10.00 EUR Assets:Bank -10.00 EUR (Assets:Bank) 2.00 EUR account Assets:Bank (Debian) account Assets:Bank [Debian] account Assets:Bank Debian)bar account Assets:Bank Debian]bar 2018-01-02 * Account name with brackets Expenses:Foo 10.00 USD Assets:Bank (Debian) -10.00 USD 2018-01-02 * Account name with brackets Expenses:Foo 10.00 USD Assets:Bank [Debian] -10.00 USD 2018-01-02 * Account name with brackets Expenses:Foo 10.00 USD Assets:Bank Debian)bar -10.00 USD 2018-01-02 * Account name with brackets Expenses:Foo 10.00 USD Assets:Bank Debian]bar -10.00 USD 2018-01-02 * Account name with brackets, as virtual posting Expenses:Foo 10.00 USD Assets:Bank -10.00 USD (Assets:Bank (Debian)) -2.00 USD 2018-01-02 * Account name with brackets, as virtual posting Expenses:Foo 10.00 USD Assets:Bank -10.00 USD (Assets:Bank [Debian]) -2.00 USD 2018-01-02 * Account name with brackets, as virtual posting Expenses:Foo 10.00 USD Assets:Bank -10.00 USD (Assets:Bank Debian)bar) -2.00 USD 2018-01-02 * Account name with brackets, as virtual posting Expenses:Foo 10.00 USD Assets:Bank -10.00 USD (Assets:Bank Debian]bar) -2.00 USD 2018-01-02 * Account name with brackets, as virtual posting Expenses:Foo 10.00 USD Assets:Bank -8.00 USD [Assets:Bank (Debian)] -2.00 USD 2018-01-02 * Account name with brackets, as virtual posting Expenses:Foo 10.00 USD Assets:Bank -8.00 USD [Assets:Bank [Debian]] -2.00 USD 2018-01-02 * Account name with brackets, as virtual posting Expenses:Foo 10.00 USD Assets:Bank -8.00 USD [Assets:Bank Debian)bar] -2.00 USD 2018-01-02 * Account name with brackets, as virtual posting Expenses:Foo 10.00 USD Assets:Bank -8.00 USD [Assets:Bank Debian]bar] -2.00 USD 2019-03-27 Don't confuse account and amount due to tabs Assets:Bank -35.00 EUR Expenses:Foo 35.00 EUR 2019-03-27 Invalid account: root is not valid, needs subaccount Assets:Bank 42.00 EUR Revenue 2019-03-27 Non-standard root name Assets:Bank 100.00 EUR Revenue:Salary -100.00 EUR 2019-03-27 Non-standard root name (after mapping) Assets:Bank 1.00 EUR Income:Interest -1.00 EUR 2019-04-06 * Name collision and account declarations Expenses:Foo:Travel 11.00 EUR Assets:Bank -11.00 EUR 2019-04-06 * Name collision and account declarations Expenses:Foo:Travel 22.00 EUR Assets:Bank -22.00 EUR 2019-04-17 * Mass rename of accounts using account_regex Accrued:Accounts Receivable:Foo 10.00 EUR Revenue:Foo -10.00 EUR 2019-04-17 * Mass rename of accounts using account_regex Accrued:Accounts Receivable:Bar 10.00 EUR Revenue:Foo -10.00 EUR 2019-04-17 * Mass rename of accounts using account_regex - leads to a name that requires further changes Accrued:Accounts Payable:Baz 10.00 EUR Expenses:Foo -10.00 EUR 2019-04-27 * Rename account to something which contains original account name Assets:Bank 10.00 EUR Trading:Currency -10.00 EUR 2019-04-28 * Account name with only one letter A 10.00 EUR B 2019-04-28 Deferred account Liabilities:MasterCard 150.00 EUR -150.00 EUR 2019-04-29 * Strange but legal name in ledger - illegal in beancount Expenses:Baz: 100.00 EUR Assets:Bank -100.00 EUR ledger2beancount-2.0/tests/accounts.yml000066400000000000000000000014521362415351400203100ustar00rootroot00000000000000 beancount_header: accounts.header convert_virtual: true account_map: Assets:♚♛♕♔: Assets:Crowns Assets:Test:I love ♚♛♕♔: Assets:Test:I-Love-Crowns Assets:Coll1: Assets:Collision Assets:Coll2: Assets:Collision Equity:Opening-balance: Equity:Opening-Balance Assets:Shorter: Assets:Short Assets:Longer: Assets:MuchLonger Assets:Cash: Assets:Bash Assets:Bank (Debian): Assets:Bank:Debian Assets:Bank Debian]bar: Assets:Bank:Debian:Bar Income:Interest: Revenue:Interest Expenses:Foo:Travel: Expenses:Travel Expenses:Bar:Travel: Expenses:Travel Trading:Currency: Equity:Trading:Currency A: Assets:Aaa B: Assets:Bbb account_regex: ^Accrued:Accounts Payable:(.*): Liabilities:Accounts Payable:$1 ^Accrued:Accounts Receivable:(.*): Assets:Accounts-Receivable:$1 ledger2beancount-2.0/tests/amounts-decimal-comma.beancount000066400000000000000000000022151362415351400240200ustar00rootroot00000000000000;---------------------------------------------------------------------- ; ledger2beancount conversion notes: ; ; - Collision for commodity EUR: EUR, € ;---------------------------------------------------------------------- 1970-01-01 open Assets:Test 1970-01-01 commodity FRF 1970-01-01 commodity GBP 1970-01-01 commodity USD 1970-01-01 open Assets:99Test:Test99 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity EUR 2002-01-01 price EUR 6.55957 FRF 2018-03-26 * "Decimal comma" Assets:99Test:Test99 10.12 EUR Equity:Opening-Balance 2018-03-26 * "Decimal comma, with thousand separator" Assets:99Test:Test99 1000.00 EUR Equity:Opening-Balance 2018-03-26 * "Decimal comma, with thousand separator" Assets:99Test:Test99 1000.00 EUR Equity:Opening-Balance 2018-09-27 * "Test amounts without digits before comma separator" Assets:Test 0.10 EUR Assets:Test -0.10 EUR Assets:Test 0.10 GBP Assets:Test -0.10 GBP Assets:Test 0.10 USD Assets:Test -0.10 USD ledger2beancount-2.0/tests/amounts-decimal-comma.ledger000066400000000000000000000014641362415351400233110ustar00rootroot00000000000000--decimal-comma account Assets:99Test:Test99 account Equity:Opening-Balance commodity EUR P 2002-01-01 € 6,55957 FRF 2018-03-26 * Decimal comma Assets:99Test:Test99 10,12 EUR Equity:Opening-Balance 2018-03-26 * Decimal comma, with thousand separator Assets:99Test:Test99 EUR 1.000,00 Equity:Opening-Balance 2018-03-26 * Decimal comma, with thousand separator Assets:99Test:Test99 EUR 1.000,00 Equity:Opening-Balance 2018-09-27 * Test amounts without digits before comma separator Assets:Test €,10 Assets:Test €-,10 Assets:Test £,10 Assets:Test £-,10 Assets:Test $,10 Assets:Test $-0,10 ledger2beancount-2.0/tests/amounts-decimal-comma.yml000066400000000000000000000000261362415351400226410ustar00rootroot00000000000000 decimal_comma: true ledger2beancount-2.0/tests/amounts.beancount000066400000000000000000000115471362415351400213420ustar00rootroot00000000000000;---------------------------------------------------------------------- ; ledger2beancount conversion notes: ; ; - Commodity Avios renamed to AVIOS ; - Collision for commodity EUR: EUR, € ; - Collision for commodity GBP: GBP, £ ; - Collision for commodity USD: $, USD ;---------------------------------------------------------------------- 1970-01-01 open Assets:Current 1970-01-01 open Assets:Receivable 1970-01-01 open Assets:Rewards 1970-01-01 open Assets:Test 1970-01-01 open Expenses:Housing:Rent 1970-01-01 open Expenses:Travel:Airfare 1970-01-01 open Liabilities:BA 1970-01-01 commodity AVIOS 1970-01-01 commodity CZK 1970-01-01 open Assets:99Test:Test99 1970-01-01 open Assets:Test1 1970-01-01 open Assets:Test2 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity EUR 1970-01-01 commodity GBP 1970-01-01 commodity USD 2018-03-26 * "Commodity after amount" Assets:99Test:Test99 1 EUR Equity:Opening-Balance 2018-03-26 * "Commodity after amount, no space" Assets:99Test:Test99 1 EUR Equity:Opening-Balance 2018-03-26 * "Commodity before amount" Assets:99Test:Test99 1 EUR Equity:Opening-Balance 2018-03-26 * "Commodity before amount, no space" Assets:99Test:Test99 1000.00 EUR Equity:Opening-Balance 2018-03-26 * "Commodity after amount, negative" Assets:99Test:Test99 -1 EUR Equity:Opening-Balance 2018-03-26 * "Commodity after amount, negative, no space" Assets:99Test:Test99 -1 EUR Equity:Opening-Balance 2018-03-26 * "Commodity before amount, negative" Assets:99Test:Test99 -3 EUR Equity:Opening-Balance 2018-03-26 * "Commodity before amount, negative" Assets:99Test:Test99 -2 EUR Equity:Opening-Balance 2018-03-26 * "Commodity symbol after amount" Assets:99Test:Test99 100 USD Equity:Opening-Balance 2018-03-26 * "Commodity symbol after amount, negative" Assets:99Test:Test99 -1 USD Equity:Opening-Balance 2018-03-26 * "Commodity symbol before amount" Assets:99Test:Test99 1 USD Equity:Opening-Balance 2018-03-26 * "Commodity symbol before amount, negative" Assets:99Test:Test99 -1 USD Equity:Opening-Balance 2018-03-26 * "Commodity symbol after amount, with space" Assets:99Test:Test99 1 USD Equity:Opening-Balance 2018-03-26 * "Commodity symbol before amount, with space" Assets:99Test:Test99 1 USD Equity:Opening-Balance 2018-03-26 * "Commodity symbol after amount, negative, with space" Assets:99Test:Test99 -1 USD Equity:Opening-Balance 2018-03-26 * "Commodity symbol before amount, negative" Assets:99Test:Test99 -1 USD Equity:Opening-Balance 2018-03-26 * "Commodity after amount, comma" Assets:99Test:Test99 1,000 EUR Equity:Opening-Balance 2018-03-26 * "Commodity before amount, comma" Assets:99Test:Test99 1,000.00 EUR Equity:Opening-Balance 2018-03-26 * "Commodity before amount, comma, no space" Assets:99Test:Test99 1,000.00 EUR Equity:Opening-Balance 2018-03-26 * "Commodity before amount, comma, one million" Assets:99Test:Test99 1,000,000.00 EUR Equity:Opening-Balance 2018-03-26 * "Simple inline math" Assets:Test1 (1*3) GBP Assets:Test2 -3 GBP 2018-03-26 * "Simple inline math" Assets:Test1 1 GBP @ (1/1.14) EUR Assets:Test2 -0.88 EUR 2018-03-26 * "Simple inline math" Assets:Test1 44.06 USD @ (1/1.362) GBP Assets:Test2 -32.35 GBP 2018-03-26 * "Simple inline math" Assets:Test1 (1 * 3) GBP Assets:Test2 -3 GBP 2018-03-26 * "Simple inline math" Assets:Test1 1 GBP @ (1 / 1.14) EUR Assets:Test2 -0.88 EUR 2018-03-26 * "Simple inline math" Assets:Test1 44.06 USD @ (1 / 1.362) GBP Assets:Test2 -32.35 GBP 2018-04-10 * "Inline math: negative amounts" Expenses:Travel:Airfare (2 * 15.00) GBP Expenses:Travel:Airfare (2*4500) AVIOS Assets:Rewards (2*-4500) AVIOS Liabilities:BA (2 * -15.00) GBP 2018-04-10 * "Inline math" Expenses:Housing:Rent (550.00/2) GBP Assets:Receivable (550.00/2) GBP Assets:Current -550.00 GBP 2018-09-27 * "Test amounts without digits before point separator" Assets:Test 0.10 EUR Assets:Test -0.10 EUR Assets:Test 0.10 GBP Assets:Test -0.10 GBP Assets:Test 0.10 USD Assets:Test -0.10 USD Assets:Test 19,200 CZK @ 0.04585052 USD Assets:Test -880.33 USD ledger2beancount-2.0/tests/amounts.ledger000066400000000000000000000103031362415351400206130ustar00rootroot00000000000000 account Assets:99Test:Test99 account Assets:Test1 account Assets:Test2 account Equity:Opening-Balance commodity EUR commodity GBP commodity $ 2018-03-26 * Commodity after amount Assets:99Test:Test99 1 EUR Equity:Opening-Balance 2018-03-26 * Commodity after amount, no space Assets:99Test:Test99 1EUR Equity:Opening-Balance 2018-03-26 * Commodity before amount Assets:99Test:Test99 EUR 1 Equity:Opening-Balance 2018-03-26 * Commodity before amount, no space Assets:99Test:Test99 EUR1000.00 Equity:Opening-Balance 2018-03-26 * Commodity after amount, negative Assets:99Test:Test99 -1 EUR Equity:Opening-Balance 2018-03-26 * Commodity after amount, negative, no space Assets:99Test:Test99 -1EUR Equity:Opening-Balance 2018-03-26 * Commodity before amount, negative Assets:99Test:Test99 EUR -3 Equity:Opening-Balance 2018-03-26 * Commodity before amount, negative Assets:99Test:Test99 -EUR 2 Equity:Opening-Balance 2018-03-26 * Commodity symbol after amount Assets:99Test:Test99 100$ Equity:Opening-Balance 2018-03-26 * Commodity symbol after amount, negative Assets:99Test:Test99 -1$ Equity:Opening-Balance 2018-03-26 * Commodity symbol before amount Assets:99Test:Test99 $1 Equity:Opening-Balance 2018-03-26 * Commodity symbol before amount, negative Assets:99Test:Test99 -$1 Equity:Opening-Balance 2018-03-26 * Commodity symbol after amount, with space Assets:99Test:Test99 1 $ Equity:Opening-Balance 2018-03-26 * Commodity symbol before amount, with space Assets:99Test:Test99 $ 1 Equity:Opening-Balance 2018-03-26 * Commodity symbol after amount, negative, with space Assets:99Test:Test99 -1 $ Equity:Opening-Balance 2018-03-26 * Commodity symbol before amount, negative Assets:99Test:Test99 -$ 1 Equity:Opening-Balance 2018-03-26 * Commodity after amount, comma Assets:99Test:Test99 1,000 EUR Equity:Opening-Balance 2018-03-26 * Commodity before amount, comma Assets:99Test:Test99 EUR 1,000.00 Equity:Opening-Balance 2018-03-26 * Commodity before amount, comma, no space Assets:99Test:Test99 EUR1,000.00 Equity:Opening-Balance 2018-03-26 * Commodity before amount, comma, one million Assets:99Test:Test99 EUR 1,000,000.00 Equity:Opening-Balance 2018-03-26 * Simple inline math Assets:Test1 (1*3 GBP) Assets:Test2 -3 GBP 2018-03-26 * Simple inline math Assets:Test1 1 GBP @ (1/1.14 EUR) Assets:Test2 -0.88 EUR 2018-03-26 * Simple inline math Assets:Test1 44.06 USD @ (1/1.362 GBP) Assets:Test2 -32.35 GBP 2018-03-26 * Simple inline math Assets:Test1 (1 * 3 GBP) Assets:Test2 -3 GBP 2018-03-26 * Simple inline math Assets:Test1 1 GBP @ (1 / 1.14 EUR) Assets:Test2 -0.88 EUR 2018-03-26 * Simple inline math Assets:Test1 44.06 USD @ (1 / 1.362 GBP) Assets:Test2 -32.35 GBP 2018-04-10 * Inline math: negative amounts Expenses:Travel:Airfare (2 * 15.00 GBP) Expenses:Travel:Airfare (2*4500 Avios) Assets:Rewards (2*-4500 Avios) Liabilities:BA (2 * -15.00 GBP) 2018-04-10 * Inline math Expenses:Housing:Rent (550.00/2 GBP) Assets:Receivable (550.00/2 GBP) Assets:Current -550.00 GBP 2018-09-27 * Test amounts without digits before point separator Assets:Test €.10 Assets:Test €-.10 Assets:Test £.10 Assets:Test -£.10 Assets:Test $.10 Assets:Test $-0.10 Assets:Test 19,200 CZK @ $.04585052 Assets:Test -$880.33 ledger2beancount-2.0/tests/aux-date.beancount000066400000000000000000000027531362415351400213630ustar00rootroot00000000000000 1970-01-01 open Assets:Commodity-Test123 1970-01-01 open Assets:Test 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity EUR 2018-03-17 * "Test with transaction aux date" aux-date: 2018-03-16 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-18 * "Test with posting aux date" Assets:Test 10.00 EUR aux-date: 2018-03-13 Equity:Opening-Balance 2018-03-18 * "Test with transaction and posting aux date" aux-date: 2018-03-17 Assets:Test 10.00 EUR aux-date: 2018-03-13 Equity:Opening-Balance 2018-03-18 * "Test with posting aux date plus comment" Assets:Test 10.00 EUR ; foo aux-date: 2018-03-13 Equity:Opening-Balance 2018-03-18 * "Test with posting aux date after no amount" Assets:Test 10.00 EUR Equity:Opening-Balance aux-date: 2018-03-13 2018-03-27 * "Account name could be mistaken for commodity" Assets:Test 10.00 EUR Assets:Commodity-Test123 aux-date: 2018-03-13 2019-01-16 * "Posting date using comment" Assets:Test 10.00 EUR date: 2017-03-04 Equity:Opening-Balance -10.00 EUR date: 2017-07-08 2019-01-16 * "Posting date and aux date using comment" Assets:Test 10.00 EUR date: 2017-03-04 aux-date: 2017-03-05 Equity:Opening-Balance -10.00 EUR date: 2017-07-08 aux-date: 2017-07-09 ledger2beancount-2.0/tests/aux-date.ledger000066400000000000000000000026111362415351400206400ustar00rootroot00000000000000 account Assets:Commodity-Test123 account Assets:Test account Equity:Opening-Balance commodity EUR 2018-03-17=2018-03-16 * Test with transaction aux date Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-18 * Test with posting aux date Assets:Test 10.00 EUR ; [=2018-03-13] Equity:Opening-Balance 2018-03-18=2018-03-17 * Test with transaction and posting aux date Assets:Test 10.00 EUR ; [=2018-03-13] Equity:Opening-Balance 2018-03-18 * Test with posting aux date plus comment Assets:Test 10.00 EUR ; [=2018-03-13] ; foo Equity:Opening-Balance 2018-03-18 * Test with posting aux date after no amount Assets:Test 10.00 EUR Equity:Opening-Balance ; [=2018-03-13] 2018-03-27 * Account name could be mistaken for commodity Assets:Test 10.00 EUR Assets:Commodity-Test123 ; [=2018-03-13] 2019-01-16 * Posting date using comment Assets:Test 10.00 EUR ; [2017-03-04] Equity:Opening-Balance -10.00 EUR ; [2017-07-08] 2019-01-16 * Posting date and aux date using comment Assets:Test 10.00 EUR ; [2017-03-04=2017-03-05] Equity:Opening-Balance -10.00 EUR ; [2017-07-08=2017-07-09] ledger2beancount-2.0/tests/balance-assertion.beancount000066400000000000000000000074421362415351400232450ustar00rootroot00000000000000;---------------------------------------------------------------------- ; ledger2beancount conversion notes: ; ; - Account Assets:wallet cash renamed to Assets:Wallet-cash ; - Account Expenses:Food and drink renamed to Expenses:Food-and-drink ;---------------------------------------------------------------------- 1970-01-01 open Assets:Cash 1970-01-01 open Assets:Wallet 1970-01-01 open Assets:Wallet-cash 1970-01-01 open Equity:Adjustments 1970-01-01 open Expenses:Drinks 1970-01-01 open Expenses:Food 1970-01-01 open Expenses:Food-and-drink 1970-01-01 open Expenses:Tips 1970-01-01 commodity THB 1970-01-01 open Assets:Test 1970-01-01 open Assets:Test2 1970-01-01 open Assets:Test3 1970-01-01 open Assets:Test4 1970-01-01 open Assets:Test5 1970-01-01 open Assets:Test6 1970-01-01 open Assets:Test7 1970-01-01 open Assets:Test8 1970-01-01 open Assets:Test9 1970-01-01 open Income:Test 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity EUR 1970-01-01 commodity USD 2018-03-23 * "Test 1" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-24 balance Assets:Test 10.00 EUR 2018-03-24 * "Test 2" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-25 balance Assets:Test 20.00 EUR 2018-03-25 balance Equity:Opening-Balance -20.00 EUR 2019-01-18 * "Assertion with commodity mapping" Assets:Test2 10.00 USD Equity:Opening-Balance -10.00 USD 2019-01-19 balance Assets:Test2 10.00 USD 2019-01-18 txn "KFC" Expenses:Food 20.00 USD Assets:Cash -20.00 USD 2019-01-19 balance Assets:Cash -20.00 USD 2019-01-19 txn "KFC" Expenses:Food 20.00 USD Expenses:Drinks 3.00 USD Assets:Cash 2019-01-20 balance Assets:Cash -43.00 USD ; account name needs mapping 2019-01-20 txn "KFC" Expenses:Food-and-drink 20.00 USD Expenses:Tips 3.00 USD Assets:Wallet-cash 2019-01-21 balance Assets:Wallet-cash -23.00 USD 2019-01-21 pad Assets:Cash Equity:Adjustments 2019-01-22 balance Assets:Cash 500.00 USD 2019-01-25 * "Balance assertion with comment" Assets:Test3 10.00 EUR ; comment Equity:Opening-Balance -10.00 EUR 2019-01-26 balance Assets:Test3 10.00 EUR 2019-01-25 * "Balance assertion with tag" Assets:Test4 10.00 EUR tags: "foo" Equity:Opening-Balance -10.00 EUR 2019-01-26 balance Assets:Test4 10.00 EUR 2019-01-29 * "Balance assertion with metadata" Assets:Test5 10.00 EUR foo: "bar" Equity:Opening-Balance -10.00 EUR 2019-01-30 balance Assets:Test5 10.00 EUR 2019-01-29 pad Assets:Test6 Equity:Adjustments 2019-01-30 balance Assets:Test6 500.00 USD 2019-04-20 txn "Wallet" Assets:Wallet 500.00 THB Equity:Opening-Balance 2019-04-28 txn "Food" Expenses:Food 10.00 THB Assets:Wallet 2019-04-29 balance Assets:Wallet 490.00 THB 2020-02-15 txn "Specify amount" Assets:Test7 20.00 EUR Equity:Opening-Balance -20.00 EUR 2020-02-16 balance Assets:Test7 20.00 EUR 2020-02-15 txn "Specify amount" Assets:Test8 30.00 EUR Equity:Opening-Balance -30.00 EUR 2020-02-16 balance Assets:Test8 30.00 EUR 2020-02-15 txn "Specify amount" Assets:Test9 40.00 EUR Equity:Opening-Balance -40.00 EUR 2020-02-15 * "Balance assertion with a single posting - use bucket to balance" Assets:Test9 5.00 EUR Income:Test 2020-02-16 balance Assets:Test9 45.00 EUR ledger2beancount-2.0/tests/balance-assertion.ledger000066400000000000000000000055021362415351400225240ustar00rootroot00000000000000 account Assets:Test account Assets:Test2 account Assets:Test3 account Assets:Test4 account Assets:Test5 account Assets:Test6 account Assets:Test7 account Assets:Test8 account Assets:Test9 account Income:Test account Equity:Opening-Balance commodity EUR commodity $ 2018-03-23 * Test 1 Assets:Test 10.00 EUR = 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-24 * Test 2 Assets:Test 10.00 EUR = 20.00 EUR Equity:Opening-Balance -10.00 EUR = -20.00 EUR 2019-01-18 * Assertion with commodity mapping Assets:Test2 $10.00 = $10.00 Equity:Opening-Balance -$10.00 2019-01-18 KFC Expenses:Food $20.00 Assets:Cash $-20.00 = $-20.00 2019-01-19 KFC Expenses:Food $20.00 Expenses:Drinks $3.00 Assets:Cash = $-43.00 ; account name needs mapping 2019-01-20 KFC Expenses:Food and drink $20.00 Expenses:Tips $3.00 Assets:wallet cash = $-23.00 2019-01-21 Adjustment Assets:Cash = $500.00 Equity:Adjustments 2019-01-25 * Balance assertion with comment Assets:Test3 10.00 EUR = 10.00 EUR ; comment Equity:Opening-Balance -10.00 EUR 2019-01-25 * Balance assertion with tag Assets:Test4 10.00 EUR = 10.00 EUR ; :foo: Equity:Opening-Balance -10.00 EUR 2019-01-29 * Balance assertion with metadata Assets:Test5 10.00 EUR = 10.00 EUR ; foo: bar Equity:Opening-Balance -10.00 EUR 2019-01-29 Adjustment ; :foo: Assets:Test6 = $500.00 Equity:Adjustments 2019-04-20 Wallet Assets:Wallet 500.00 THB Equity:Opening-Balance 2019-04-28 Food Expenses:Food 10.00 THB Assets:Wallet = 490.00 THB 2020-02-15 Specify amount Assets:Test7 20.00 EUR Equity:Opening-Balance -20.00 EUR 2020-02-15 * Balance assertion with 0 value Assets:Test7 0.00 EUR = 20.00 EUR 2020-02-15 Specify amount Assets:Test8 30.00 EUR Equity:Opening-Balance -30.00 EUR 2020-02-15 * Balance assigment with a single posting Assets:Test8 = 30.00 EUR 2020-02-15 Specify amount Assets:Test9 40.00 EUR Equity:Opening-Balance -40.00 EUR bucket Income:Test 2020-02-15 * Balance assertion with a single posting - use bucket to balance Assets:Test9 5.00 EUR = 45.00 EUR ledger2beancount-2.0/tests/code.beancount000066400000000000000000000021431362415351400205560ustar00rootroot00000000000000 1970-01-01 open Assets:Test 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity EUR ; Integer 2018-03-17 * "Test" code: "1201" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; String 2018-03-17 * "Test" code: "AT20" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; Code but no flag 2018-03-17 txn "Test" code: "AT20" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-05-16 * "Code without space" code: "1201" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-05-16 * "Code without space" code: "AT20" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-05-16 txn "Code without space, no flag" code: "1201" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-05-16 txn "Code without space, no flag" code: "AT20" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ledger2beancount-2.0/tests/code.ledger000066400000000000000000000020141362415351400200370ustar00rootroot00000000000000 account Assets:Test account Equity:Opening-Balance commodity EUR ; Integer 2018-03-17 * (1201) Test Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; String 2018-03-17 * (AT20) Test Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; Code but no flag 2018-03-17 (AT20) Test Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-05-16 *(1201)Code without space Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-05-16 *(AT20)Code without space Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-05-16 (1201)Code without space, no flag Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-05-16 (AT20)Code without space, no flag Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ledger2beancount-2.0/tests/comments.beancount000066400000000000000000000040301362415351400214660ustar00rootroot00000000000000; Beancount: 2.1.0 ; -*- mode: beancount -*- ;; -*- mode: beancount -*- * -*- mode: beancount -*- 1970-01-01 open Assets:Test 1970-01-01 open Equity:Opening-Balance 1970-01-01 open Assets:Commodity-Test123 1970-01-01 commodity EUR ; This is a block comment ; Second line ; Comment without indentation ; Second line ; Another comment ; test can be ended with end comment ; comment can be ended with end test ; This is another block comment ; No indentation, followed by ; indentation. ; Indentation, followed by ; no indentation. ; This is a single line comment, # and this, % and this, ; and this, * and this. ; This is a comment ; Test: not a tag ; :not:a:tag: ; Another comment 2018-03-17 * "Test" ; Another comment Assets:Test 10.00 EUR ; What an "interesting" accout name ; full line posting comment Equity:Opening-Balance -10.00 EUR ; Opening balance? ; posting-level comment 2018-03-17 * "Tag and comment on same line" #tag ; comment Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 * "Multi-line comment" ; comment1 ; comment2 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-27 * "Account name could be mistaken for commodity" Assets:Test 10.00 EUR Assets:Commodity-Test123 ; comment 2018-03-27 * "Account name could be mistaken for commodity" Assets:Test 10.00 EUR Assets:Commodity-Test123 ; comment 2019-01-25 * "A payee can contain ; without problems" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2019-01-25 * "You can put a comment on the same line as the payee" ; comment Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2019-01-25 * "You can put a comment on the same line as the payee" ; this is a comment Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ledger2beancount-2.0/tests/comments.ledger000066400000000000000000000042221362415351400207550ustar00rootroot00000000000000; Beancount: 2.1.0 ; -*- ledger -*- ;; -*- ledger -*- * -*- ledger -*- account Assets:Test account Equity:Opening-Balance account Assets:Commodity-Test123 commodity EUR comment This is a block comment Second line end comment comment Comment without indentation Second line end comment test Another comment end test test test can be ended with end comment end comment comment comment can be ended with end test end test !comment This is another block comment end comment @comment No indentation, followed by indentation. end comment @comment Indentation, followed by no indentation. end comment ; This is a single line comment, # and this, % and this, | and this, * and this. ; This is a comment ; Test: not a tag ; :not:a:tag: ; Another comment 2018-03-17 * Test ; Another comment Assets:Test 10.00 EUR ; What an "interesting" accout name ; full line posting comment Equity:Opening-Balance -10.00 EUR ; Opening balance? ; posting-level comment 2018-03-17 * Tag and comment on same line ; :tag: comment Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 * Multi-line comment ; comment1 ; comment2 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-27 * Account name could be mistaken for commodity Assets:Test 10.00 EUR Assets:Commodity-Test123 ; comment 2018-03-27 * Account name could be mistaken for commodity Assets:Test 10.00 EUR Assets:Commodity-Test123 ; comment 2019-01-25 * A payee can contain ; without problems Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2019-01-25 * You can put a comment on the same line as the payee ; comment Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2019-01-25 * You can put a comment on the same line as the payee ; this is a comment Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ledger2beancount-2.0/tests/commodities.beancount000066400000000000000000000113621362415351400221630ustar00rootroot00000000000000;---------------------------------------------------------------------- ; ledger2beancount conversion notes: ; ; - Skipped second commodity declaration for USD (old USD) ; - Commodity "A commodity" renamed to A-COMMODITY ; - Commodity "M&M3" renamed to M-M3 ; - Commodity AnotherAnotherAnotherAnother renamed to ANOTHERANOTHERANOTHERANO ; - Commodity Aud renamed to AUD ; - Commodity Bär renamed to BAR ; - Commodity C renamed to CX ; - Commodity Crown♛ renamed to CROWNX ; - Commodity Föö renamed to FOO ; - Commodity Gandi renamed to GANDI ; - Commodity KrisFlyer renamed to KRISFLYER ; - Commodity krw renamed to KRW ; - Collision for commodity COLLISION: COLLA, COLLB ; - Collision for commodity USD: $, USD ;---------------------------------------------------------------------- 1970-01-01 commodity AA 1970-01-01 commodity COLLISION 1970-01-01 commodity CX 1970-01-01 open Assets:Test 1970-01-01 open Assets:Test123 1970-01-01 open Expenses:Gandi ; test comment 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity A-COMMODITY 1970-01-01 commodity ANOTHER ; just a comment 1970-01-01 commodity ANOTHERANOTHERANOTHERANO 1970-01-01 commodity UR 1970-01-01 commodity DE0002635307 1970-01-01 commodity USD ; value 0.90 EUR 1970-01-01 commodity EUR name: "Euro" ; nomarket ; default 1970-01-01 commodity GANDI name: "Gandi points" 1970-01-01 commodity KRISFLYER 1970-01-01 commodity MILESMORE 1970-01-01 commodity MILESMORE2 1970-01-01 commodity M-M3 1970-01-01 commodity MILESMORE4 1970-01-01 commodity MR name: "AMEX Membership Rewards" 1970-01-01 commodity KRW 1970-01-01 commodity AUD 1970-01-01 commodity CROWNX 1970-01-01 commodity BAR 1970-01-01 commodity FOO 1970-01-01 commodity MOETZ 1970-01-01 commodity MOO 2018-03-17 * "Test quoted commodity" Assets:Test 1 DE0002635307 Equity:Opening-Balance -1 DE0002635307 2018-03-17 * "Test commodity mapping" Assets:Test 1 UR Equity:Opening-Balance -1 UR 2018-03-18 * "Test quoted commodity with defined mapping" Assets:Test 1 MILESMORE Equity:Opening-Balance -1 MILESMORE 2018-03-18 * "Test quoted commodity with defined mapping missing quotes" Assets:Test 1 MILESMORE2 Equity:Opening-Balance -1 MILESMORE2 2018-03-18 * "Test upper case" Assets:Test 1 GANDI Equity:Opening-Balance -1 GANDI 2017-03-31 * "Test with account name containing same string as commodity" Expenses:Gandi 140616 GANDI Assets:Test -140616 GANDI 2018-03-20 * "Account name ending in digits - digits not part of amount" Assets:Test123 10.00 EUR Equity:Opening-Balance 2018-03-21 * "Test upper caser for lot price" Assets:Test 1 MR @ 1 KRISFLYER Equity:Opening-Balance 2018-03-21 * "Invalid character for beancount commodity names" Assets:Test 1 M-M3 Equity:Opening-Balance 2018-03-21 * "Invalid character for beancount commodity names, with mapping" Assets:Test 1 MILESMORE4 Equity:Opening-Balance 2018-03-21 * "Commodity with space" Assets:Test 1 A-COMMODITY Equity:Opening-Balance 2018-03-21 * "Commodity with space, with mapping" Assets:Test 1 ANOTHER Equity:Opening-Balance 2018-03-21 * "Commodity is too long for beancount" Assets:Test 1 ANOTHERANOTHERANOTHERANO Equity:Opening-Balance 2018-03-26 * "Lower case" Assets:Test 1 KRW Equity:Opening-Balance 2018-03-26 * "Lower case at end" Assets:Test 1 AUD Equity:Opening-Balance 2018-03-26 * "Non-letter at end" Assets:Test 1 CROWNX Equity:Opening-Balance 2018-03-26 * "Umlaut in middle" Assets:Test 1 BAR Equity:Opening-Balance 2018-03-26 * "Umlaut at end" Assets:Test 1 FOO Equity:Opening-Balance 2018-03-26 * "Mapped before transformation" Assets:Test 1 MOETZ Equity:Opening-Balance 2018-03-26 * "Mapped after transformation" Assets:Test 1 MOO Equity:Opening-Balance 2018-03-29 * "Mapping creating collision" Assets:Test 1 COLLISION Equity:Opening-Balance 2018-03-29 * "Mapping creating collision" Assets:Test 1 COLLISION Equity:Opening-Balance 2018-04-28 * "Commodity with only 1 letter" Assets:Test 1 CX Equity:Opening-Balance 2018-04-28 * "Commodity with only 1 letter" Assets:Test 1 AA Equity:Opening-Balance ledger2beancount-2.0/tests/commodities.ledger000066400000000000000000000073471362415351400214570ustar00rootroot00000000000000 account Assets:Test account Assets:Test123 account Expenses:Gandi ; test comment account Equity:Opening-Balance commodity "A commodity" commodity "Another commodity" ; just a comment commodity AnotherAnotherAnotherAnother @commodity Chase !commodity "DE0002635307" commodity $ value 0.90 EUR commodity USD alias FOO commodity EUR note Euro format 1000.00EUR nomarket default commodity Gandi note Gandi points commodity KrisFlyer commodity "M&M" commodity "M&M2" commodity "M&M3" commodity "M&M4" commodity MR note AMEX Membership Rewards commodity krw commodity Aud commodity Crown♛ commodity Bär commodity Föö commodity Mötz commodity M♛O 2018-03-17 * Test quoted commodity Assets:Test 1 "DE0002635307" Equity:Opening-Balance -1 "DE0002635307" 2018-03-17 * Test commodity mapping Assets:Test 1 Chase Equity:Opening-Balance -1 Chase 2018-03-18 * Test quoted commodity with defined mapping Assets:Test 1 "M&M" Equity:Opening-Balance -1 "M&M" 2018-03-18 * Test quoted commodity with defined mapping missing quotes Assets:Test 1 "M&M2" Equity:Opening-Balance -1 "M&M2" 2018-03-18 * Test upper case Assets:Test 1 Gandi Equity:Opening-Balance -1 Gandi 2017-03-31 * Test with account name containing same string as commodity Expenses:Gandi 140616 Gandi Assets:Test -140616 Gandi 2018-03-20 * Account name ending in digits - digits not part of amount Assets:Test123 10.00 EUR Equity:Opening-Balance 2018-03-21 * Test upper caser for lot price Assets:Test 1 MR @ 1 KrisFlyer Equity:Opening-Balance 2018-03-21 * Invalid character for beancount commodity names Assets:Test 1 "M&M3" Equity:Opening-Balance 2018-03-21 * Invalid character for beancount commodity names, with mapping Assets:Test 1 "M&M4" Equity:Opening-Balance 2018-03-21 * Commodity with space Assets:Test 1 "A commodity" Equity:Opening-Balance 2018-03-21 * Commodity with space, with mapping Assets:Test 1 "Another commodity" Equity:Opening-Balance 2018-03-21 * Commodity is too long for beancount Assets:Test 1 AnotherAnotherAnotherAnother Equity:Opening-Balance 2018-03-26 * Lower case Assets:Test 1 krw Equity:Opening-Balance 2018-03-26 * Lower case at end Assets:Test 1 Aud Equity:Opening-Balance 2018-03-26 * Non-letter at end Assets:Test 1 Crown♛ Equity:Opening-Balance 2018-03-26 * Umlaut in middle Assets:Test 1 Bär Equity:Opening-Balance 2018-03-26 * Umlaut at end Assets:Test 1 Föö Equity:Opening-Balance 2018-03-26 * Mapped before transformation Assets:Test 1 Mötz Equity:Opening-Balance 2018-03-26 * Mapped after transformation Assets:Test 1 M♛O Equity:Opening-Balance 2018-03-29 * Mapping creating collision Assets:Test 1 COLLA Equity:Opening-Balance 2018-03-29 * Mapping creating collision Assets:Test 1 COLLB Equity:Opening-Balance 2018-04-28 * Commodity with only 1 letter Assets:Test 1 C Equity:Opening-Balance 2018-04-28 * Commodity with only 1 letter Assets:Test 1 ♛ Equity:Opening-Balance ledger2beancount-2.0/tests/dates-month.beancount000066400000000000000000000003701362415351400220670ustar00rootroot00000000000000 1970-01-01 open Assets:Test 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity EUR 1970-01-01 commodity USD 2018-03-29 * "Non-ISO 8601 date" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ledger2beancount-2.0/tests/dates-month.ledger000066400000000000000000000003621362415351400213540ustar00rootroot00000000000000--input-date-format %Y-%b-%d account Assets:Test account Equity:Opening-Balance commodity EUR commodity USD 2018-Mar-29 * Non-ISO 8601 date Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ledger2beancount-2.0/tests/dates-month.yml000066400000000000000000000000321362415351400207050ustar00rootroot00000000000000 date_format: "%Y-%b-%d" ledger2beancount-2.0/tests/dates.beancount000066400000000000000000000014231362415351400207440ustar00rootroot00000000000000;---------------------------------------------------------------------- ; ledger2beancount conversion notes: ; ; - Metadata key Date renamed to date ;---------------------------------------------------------------------- 1970-01-01 open Assets:Test 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity EUR 1970-01-01 commodity USD 2018-03-19 * "Non-ISO 8601 date" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-20 * "Typed meta data with non-ISO 8601 date" date: 2017-12-31 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-20 * "Lot date with non-ISO 8601 date" Assets:Test 10.00 EUR {1.23 USD, 2018-03-16} Equity:Opening-Balance -12.30 USD ledger2beancount-2.0/tests/dates.ledger000066400000000000000000000010461362415351400202310ustar00rootroot00000000000000 account Assets:Test account Equity:Opening-Balance commodity EUR commodity USD 2018/03/19 * Non-ISO 8601 date Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018/03/20 * Typed meta data with non-ISO 8601 date ; Date:: [2017/12/31] Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018/03/20 * Lot date with non-ISO 8601 date Assets:Test 10.00 EUR {1.23 USD} [2018/03/16] @ 1.23 USD Equity:Opening-Balance -12.30 USD ledger2beancount-2.0/tests/dates.yml000066400000000000000000000000321362415351400175620ustar00rootroot00000000000000 date_format: "%Y/%m/%d" ledger2beancount-2.0/tests/directives.beancount000066400000000000000000000136341362415351400220140ustar00rootroot00000000000000;---------------------------------------------------------------------- ; ledger2beancount conversion notes: ; ; - Automated or periodic transaction skipped ; - Unsupported directive `i` skipped ; - Unsupported directive `o` skipped ; - Unsupported directive `I` skipped ; - Unsupported directive `O` skipped ; - Unsupported directive `b` skipped ; - Unsupported directive `h` skipped ; - Unsupported directive `C` skipped ; - Unsupported directive `D` skipped ; - Unsupported directive `N` skipped ; - Unsupported directive `eval` skipped ; - The `define` directive is not supported ; - Unsupported directive `value` skipped ; - The `def` directive is not supported ;---------------------------------------------------------------------- 1970-01-01 open Assets:Another:Alias 1970-01-01 open Assets:Checking 1970-01-01 open Assets:GG 1970-01-01 open Assets:Savings 1970-01-01 open Assets:Test 1970-01-01 open Assets:Test1:Test2:AA 1970-01-01 open Assets:Test1:Test2:Another:Alias 1970-01-01 open Assets:Test1:Test2:BB 1970-01-01 open Assets:Test1:Test2:CC:DD 1970-01-01 open Assets:Test1:Test2:EE:FF 1970-01-01 open Assets:Test1:Test2:XXX:AA 1970-01-01 open Assets:What:A:Long:Name 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity EUR ; Beancount: 2.1.0 1970-01-01 txn "open Assets:Test" 1970-01-01 txn "open Equity:Opening-Balance" 1970-01-01 txn "commodity EUR" ; = expr true ; Assets:Foo 50.00 USD ; Assets:Bar -50.00 USD ; = /^(?:Income:|Expenses:(?:Business|Rent$|Furnishings|Taxes|Insurance))/ ; (Liabilities:Huququ'llah) 0.19 ; ~ Yearly ; Expenses:Auto:Repair $500.00 ; Assets ; payee KFC ; alias KENTUCKY FRIED CHICKEN ; uuid 2a2e21d434356f886c84371eebac6e44f1337fda ; payee McD ; payee Burger King ; setting year 2014 ; (no space) 2014-10-02 * "Transaction without year" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2014-10-02 * "Transaction without year, with aux date" aux-date: 2014-10-01 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; setting year 2015 2015-10-02 * "Transaction without year" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2015-10-02 * "Transaction without year, with aux date" aux-date: 2015-10-01 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; setting year 2016 2016-10-02 * "Transaction without year" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2016-10-02 * "Transaction without year, with aux date" aux-date: 2016-10-01 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-25 * "Transaction with year" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; setting year 2018 2018-10-02 * "Transaction without year" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-10-02 * "Transaction without year, with aux date" aux-date: 2018-10-01 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2015-03-25 * "Transaction with year" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; apply year can be nested 2013-04-13 txn "Test apply year - 2013" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2015-04-13 txn "Test apply year - 2015" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2014-04-13 txn "Test apply year - 2014" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2013-04-13 txn "Test apply year - 2013" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR include "include1.beancount" include "include2.beancount" include "include3.beancount" ; Test apply account and apply tag pushtag #foo pushtag #bar 2018-03-29 * "Test apply" ^2018-02-02-brussels-fosdem test: "martin" Assets:Test1:Test2:AA 10.00 EUR Assets:Test1:Test2:BB 2018-03-29 * "Test apply" ^2018-02-02-brussels-fosdem test: "martin" Assets:Test1:Test2:CC:DD 10.00 EUR Assets:Test1:Test2:EE:FF poptag #bar poptag #foo ; Test apply account and alias 2018-03-29 * "Test apply" Assets:Test1:Test2:AA 10.00 EUR Assets:What:A:Long:Name 2018-03-29 * "Test apply" Assets:Test1:Test2:XXX:AA 10.00 EUR Assets:Test1:Test2:Another:Alias 2018-03-29 * "Test apply" Assets:GG 10.00 EUR Assets:Test1:Test2:Another:Alias 2018-03-29 * "Test apply" Assets:GG 10.00 EUR Assets:Another:Alias 2018-03-29 * "Bucket" Assets:Test 10.00 EUR Assets:Checking 2018-03-29 * "Bucket" Assets:Test 10.00 EUR Assets:Savings ; timeclock ; i 2018-03-29 14:10:20 B ; o 2018-03-29 14:50:00 ; I 2018-03-29 14:55:40 B ; O 2018-03-29 15:10:10 ; b 2018-03-29 14:10:20 ; h 2018-03-29 14:10:20 ; commodity conversion ; C 1.00 Mb = 1024 Kb ; Default Commodity ; D 1000.00 EUR ; Ignore pricing information ; N EUR ; python ; def print_type(val): ; print type(val), val ; ; eval print_type(true) ; python ; def option_pyfirst(context): ; print "In --pyfirst (from %s)" % context ; ; def option_pysecond(context, val): ; print "In --pysecond=%s (from %s)" % (val, context) 2019-04-28 * "Transactions can follow python without empty line" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; define myfunc_seven(s, d, t) = 7 EUR ;; The 'value' directive sets the valuation used for all commodities used in ;; the rest of the daat stream. This is the fallback, if nothing more ;; specific is found. ; value myfunc_seven ; def foo=200 USD ledger2beancount-2.0/tests/directives.ledger000066400000000000000000000115421362415351400212740ustar00rootroot00000000000000; Beancount: 2.1.0 --input-date-format %Y-%m-%d --input-date-format %m-%d 1970-01-01 open Assets:Test 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity EUR = expr true Assets:Foo 50.00 USD Assets:Bar -50.00 USD = /^(?:Income:|Expenses:(?:Business|Rent$|Furnishings|Taxes|Insurance))/ (Liabilities:Huququ'llah) 0.19 ~ Yearly Expenses:Auto:Repair $500.00 Assets payee KFC alias KENTUCKY FRIED CHICKEN uuid 2a2e21d434356f886c84371eebac6e44f1337fda !payee McD @payee Burger King ; setting year 2014 ; (no space) Y2014 10-02 * Transaction without year Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 10-02=10-01 * Transaction without year, with aux date Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; setting year 2015 Y 2015 10-02 * Transaction without year Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 10-02=10-01 * Transaction without year, with aux date Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; setting year 2016 year 2016 10-02 * Transaction without year Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 10-02=10-01 * Transaction without year, with aux date Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-25 * Transaction with year Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; setting year 2018 apply year 2018 10-02 * Transaction without year Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 10-02=10-01 * Transaction without year, with aux date Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2015-03-25 * Transaction with year Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR end apply ; apply year can be nested apply year 2013 04-13 Test apply year - 2013 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR apply year 2014 apply year 2015 04-13 Test apply year - 2015 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR end apply 04-13 Test apply year - 2014 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR end apply 04-13 Test apply year - 2013 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR end apply !include include1.ledger @include include2.ledger include include3.ledger ; Test apply account and apply tag !apply account Assets: apply tag foo apply tag bar apply tag 2018-02-02-brussels-fosdem apply tag test: martin @apply account Test1::::::::::: @apply account Test2 2018-03-29 * Test apply AA 10.00 EUR BB 2018-03-29 * Test apply CC:DD 10.00 EUR EE:FF end apply end apply end apply end apply end apply end apply end apply ; Test apply account and alias alias BB=Assets:What:A:Long:Name !apply account Assets: @apply account Test1::::::::::: @apply account Test2 2018-03-29 * Test apply AA 10.00 EUR BB alias BB=Another:Alias apply account XXX 2018-03-29 * Test apply AA 10.00 EUR BB end apply end apply end apply end apply 2018-03-29 * Test apply Assets:GG 10.00 EUR BB alias BB=Assets:Another:Alias 2018-03-29 * Test apply Assets:GG 10.00 EUR BB bucket Assets:Checking 2018-03-29 * Bucket Assets:Test 10.00 EUR A Assets:Savings 2018-03-29 * Bucket Assets:Test 10.00 EUR !tag foo @tag bar tag baz tag Project check value =~ /^(0ad|ankur|aptosid|archlinux|chakra|debian)$/ ; timeclock i 2018-03-29 14:10:20 B o 2018-03-29 14:50:00 I 2018-03-29 14:55:40 B O 2018-03-29 15:10:10 b 2018-03-29 14:10:20 h 2018-03-29 14:10:20 ; commodity conversion C 1.00 Mb = 1024 Kb ; Default Commodity D 1000.00 EUR ; Ignore pricing information N EUR python def print_type(val): print type(val), val eval print_type(true) python def option_pyfirst(context): print "In --pyfirst (from %s)" % context def option_pysecond(context, val): print "In --pysecond=%s (from %s)" % (val, context) 2019-04-28 * Transactions can follow python without empty line Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR define myfunc_seven(s, d, t) = 7 EUR ;; The 'value' directive sets the valuation used for all commodities used in ;; the rest of the daat stream. This is the fallback, if nothing more ;; specific is found. value myfunc_seven def foo=200 USD ledger2beancount-2.0/tests/fixated.beancount000066400000000000000000000035171362415351400212760ustar00rootroot000000000000001970-01-01 open Assets:Brokerage 1970-01-01 open Assets:Brokerage:Cash 1970-01-01 open Assets:Wallet 1970-01-01 open Expenses:Food 1970-01-01 commodity AAPL 1970-01-01 commodity CAD 1970-01-01 commodity EUR 1970-01-01 commodity USD 2012-04-10 txn "My Broker" Assets:Brokerage 10 AAPL {50.00 USD} Assets:Brokerage:Cash -500.00 USD 2012-04-11 txn "My Broker" Assets:Brokerage 10 AAPL {50.00 USD} Assets:Brokerage:Cash -500.00 USD ; Only apply fixated to CAD, not to EUR 2012-04-10 txn "Lunch in Canada" Assets:Wallet -15.50 CAD {0.20 USD} Expenses:Food 15.50 CAD {0.20 USD} 2012-04-10 txn "Lunch in Canada" Assets:Wallet -15.50 CAD {0.90 USD} Expenses:Food 15.50 CAD {0.90 USD} 2012-04-11 txn "Second day Dinner in Canada" Assets:Wallet -25.75 CAD {0.90 USD} Expenses:Food 25.75 CAD {0.90 USD} 2012-04-11 txn "Paid in EUR" Assets:Wallet -25.75 EUR Expenses:Food 25.75 EUR 2012-04-11 txn "Paid in EUR" Assets:Wallet -25.75 EUR Expenses:Food ; Apply fixated to CAD and EUR 2012-04-10 txn "Lunch in Canada" Assets:Wallet -15.50 CAD {0.20 USD} Expenses:Food 15.50 CAD {0.20 USD} 2012-04-10 txn "Lunch in Canada" Assets:Wallet -15.50 CAD {0.90 USD} Expenses:Food 15.50 CAD {0.90 USD} 2012-04-11 txn "Second day Dinner in Canada" Assets:Wallet -25.75 CAD {0.90 USD} Expenses:Food 25.75 CAD {0.90 USD} 2012-04-11 txn "Second day Dinner in Canada" Assets:Wallet -25.75 CAD {0.90 USD} Expenses:Food 2012-04-11 txn "Paid in EUR" Assets:Wallet -25.75 EUR {0.40 CAD} Expenses:Food 25.75 EUR {0.40 CAD} 2012-04-11 txn "Paid in EUR" Assets:Wallet -25.75 EUR {0.40 CAD} Expenses:Food ledger2beancount-2.0/tests/fixated.ledger000066400000000000000000000030501362415351400205520ustar00rootroot00000000000000 2012-04-10 My Broker Assets:Brokerage 10 AAPL @ =$50.00 Assets:Brokerage:Cash $-500.00 2012-04-11 My Broker Assets:Brokerage 10 AAPL {=$50.00} Assets:Brokerage:Cash $-500.00 ; Only apply fixated to CAD, not to EUR apply fixed CAD $0.90 2012-04-10 Lunch in Canada Assets:Wallet -15.50 CAD {$0.20} Expenses:Food 15.50 CAD {$0.20} 2012-04-10 Lunch in Canada Assets:Wallet -15.50 CAD Expenses:Food 15.50 CAD 2012-04-11 Second day Dinner in Canada Assets:Wallet -25.75 CAD Expenses:Food 25.75 CAD 2012-04-11 Paid in EUR Assets:Wallet -25.75 EUR Expenses:Food 25.75 EUR 2012-04-11 Paid in EUR Assets:Wallet -25.75 EUR Expenses:Food end apply fixed ; Apply fixated to CAD and EUR apply fixed CAD $0.90 apply fixed EUR 0.40 CAD 2012-04-10 Lunch in Canada Assets:Wallet -15.50 CAD {$0.20} Expenses:Food 15.50 CAD {$0.20} 2012-04-10 Lunch in Canada Assets:Wallet -15.50 CAD Expenses:Food 15.50 CAD 2012-04-11 Second day Dinner in Canada Assets:Wallet -25.75 CAD Expenses:Food 25.75 CAD 2012-04-11 Second day Dinner in Canada Assets:Wallet -25.75 CAD Expenses:Food 2012-04-11 Paid in EUR Assets:Wallet -25.75 EUR Expenses:Food 25.75 EUR 2012-04-11 Paid in EUR Assets:Wallet -25.75 EUR Expenses:Food end apply fixed end apply fixed ledger2beancount-2.0/tests/flags.beancount000066400000000000000000000006721362415351400207450ustar00rootroot00000000000000 1970-01-01 open Assets:Test 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity EUR 2018-03-17 txn "Test" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 * "Test" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 ! "Test" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ledger2beancount-2.0/tests/flags.ledger000066400000000000000000000006411362415351400202250ustar00rootroot00000000000000 account Assets:Test account Equity:Opening-Balance commodity EUR 2018-03-17 Test Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 * Test Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 ! Test Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ledger2beancount-2.0/tests/hledger.beancount000066400000000000000000000071071362415351400212630ustar00rootroot00000000000000;---------------------------------------------------------------------- ; ledger2beancount conversion notes: ; ; - Account assets:checking renamed to Assets:Checking ; - Account expenses:food renamed to Expenses:Food ; - Metadata key 2012 renamed to x2012 ; - Metadata key 2012foo renamed to x2012foo ; - Metadata key TEST1234TEST renamed to tEST1234TEST ; - Metadata key test♚ renamed to test- ;---------------------------------------------------------------------- 1970-01-01 open Assets:B 1970-01-01 open Assets:Checking 1970-01-01 open Expenses:Food 1970-01-01 commodity EUR 1970-01-01 commodity USD 1970-01-01 open Assets:A ; foo ; Payee and narration 2015-05-30 txn "foo" "bar" Assets:A 10.00 EUR Assets:B -10.00 EUR 2015-05-30 txn "foo" "bar" Assets:A 10.00 EUR Assets:B -10.00 EUR 2015-05-30 txn "foo" "bar" Assets:A 10.00 EUR Assets:B -10.00 EUR 2015-05-30 txn "foo" "bar | baz" Assets:A 10.00 EUR Assets:B -10.00 EUR ; Posting level dates as comments 2015-05-30 txn "date as comment" Expenses:Food 10 USD ; food purchased on saturday 05/30 Assets:Checking ; bank cleared it on monday, date: 2005-06-01 2015-05-30 txn "date as comment without year" Expenses:Food 10 USD ; food purchased on saturday 05/30 Assets:Checking ; bank cleared it on monday, date: 2015-06-01 2015-05-30 txn "date2 as comment" Expenses:Food 10 USD ; food purchased on saturday 05/30 Assets:Checking ; bank cleared it on monday, aux-date: 2005-06-02 2015-05-30 txn "date and date2 as comment" Expenses:Food 10 USD ; food purchased on saturday 05/30 Assets:Checking ; bank cleared it on monday, date: 2005-06-01 aux-date: 2005-06-02 2015-05-30 txn "date and date2 as comment, in reverse order" Expenses:Food 10 USD ; food purchased on saturday 05/30 Assets:Checking ; bank cleared it on monday, aux-date: 2005-06-02 date: 2005-06-01 2015-05-30 txn "date and date2 on next line" aux-date: 2005-06-02 date: 2005-06-01 ; bank cleared it on monday. Expenses:Food 10 USD Assets:Checking 2015-05-30 txn "date and date2 on next line" Expenses:Food 10 USD aux-date: 2005-06-02 date: 2005-06-01 ; bank cleared it on monday. Assets:Checking 2015-05-30 txn "date and date2 on next line" Expenses:Food 10 USD Assets:Checking aux-date: 2005-06-02 date: 2005-06-01 ; bank cleared it on monday. ; Tags 2019-01-28 txn "Tag test" #sometag #foo #bar Assets:A 10.00 EUR Assets:B 2019-01-28 txn "Tag test" #sometag #foo #bar Assets:A 10.00 EUR Assets:B 2019-01-28 txn "ledger tag" tag1: "tag2:" Assets:A 10.00 EUR Assets:B 2019-01-28 txn "Tag test" #foo #bar sometag: "foo" Assets:A 10.00 EUR Assets:B 2019-01-28 txn "Tag test" #bar sometag: "this is a value" foo: "another value" Assets:A 10.00 EUR Assets:B 2019-01-28 txn "Tag test" ; a comment containing #tag1 tag2: "some value ..." Assets:A 10.00 EUR Assets:B 2019-01-28 txn "Tag test" #bar sometag: "this is a value" foo: "another value" test-: "foo" Assets:A 10.00 EUR tEST1234TEST: "foo" test-: "foo" x2012: "foo" x2012foo: "foo" Assets:B 2019-01-28 txn "Tag test" Assets:A 10.00 EUR tags: "sometag, foo, bar" Assets:B 2019-01-28 txn "Tag test" Assets:A 10.00 EUR sometag: "foo" tags: "foo, bar" Assets:B ledger2beancount-2.0/tests/hledger.ledger000066400000000000000000000054111362415351400205430ustar00rootroot00000000000000 account Assets:A ; foo ; Payee and narration 2015/5/30 foo | bar Assets:A 10.00 EUR Assets:B -10.00 EUR 2015/5/30 foo|bar Assets:A 10.00 EUR Assets:B -10.00 EUR 2015/5/30 foo| bar Assets:A 10.00 EUR Assets:B -10.00 EUR 2015/5/30 foo | bar | baz Assets:A 10.00 EUR Assets:B -10.00 EUR ; Posting level dates as comments 2015/5/30 date as comment expenses:food $10 ; food purchased on saturday 05/30 assets:checking ; bank cleared it on monday, date:2005/6/01 2015/5/30 date as comment without year expenses:food $10 ; food purchased on saturday 05/30 assets:checking ; bank cleared it on monday, date:6/1 2015/5/30 date2 as comment expenses:food $10 ; food purchased on saturday 05/30 assets:checking ; bank cleared it on monday, date2:2005/6/2 2015/5/30 date and date2 as comment expenses:food $10 ; food purchased on saturday 05/30 assets:checking ; bank cleared it on monday, date:2005/6/01, date2:2005/6/2 2015/5/30 date and date2 as comment, in reverse order expenses:food $10 ; food purchased on saturday 05/30 assets:checking ; bank cleared it on monday, date2:2005/6/02, date:2005/6/1 2015/5/30 date and date2 on next line ; bank cleared it on monday. date2:2005/6/02, date:2005/6/1 expenses:food $10 assets:checking 2015/5/30 date and date2 on next line expenses:food $10 ; bank cleared it on monday. date2:2005/6/02, date:2005/6/1 assets:checking 2015/5/30 date and date2 on next line expenses:food $10 assets:checking ; bank cleared it on monday. date2:2005/6/02, date:2005/6/1 ; Tags 2019/01/28 Tag test ; sometag:, foo:, bar: Assets:A 10.00 EUR Assets:B 2019/01/28 Tag test ; sometag: , foo:, bar: Assets:A 10.00 EUR Assets:B 2019/01/28 ledger tag ; :tag1:tag2: Assets:A 10.00 EUR Assets:B 2019/01/28 Tag test ;sometag: foo , foo:, bar: Assets:A 10.00 EUR Assets:B 2019/01/28 Tag test ; sometag: this is a value, foo:another value, bar: Assets:A 10.00 EUR Assets:B 2019/01/28 Tag test ; a comment containing tag1:, tag2: some value ... Assets:A 10.00 EUR Assets:B 2019/01/28 Tag test ; sometag: this is a value, foo:another value, bar:, test♚: foo Assets:A 10.00 EUR ; TEST1234TEST: foo ; test♚: foo ; 2012: foo ; 2012foo: foo Assets:B 2019/01/28 Tag test Assets:A 10.00 EUR ; sometag: , foo:, bar: Assets:B 2019/01/28 Tag test Assets:A 10.00 EUR ;sometag: foo , foo:, bar: Assets:B ledger2beancount-2.0/tests/hledger.yml000066400000000000000000000001601362415351400200760ustar00rootroot00000000000000 date_format: "%Y/%m/%d" date_format_no_year: "%m/%d" hledger: true postdate_tag: date auxdate_tag: aux-date ledger2beancount-2.0/tests/ignore.beancount000066400000000000000000000013021362415351400211230ustar00rootroot000000000000001970-01-01 open Assets:Test3 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity EUR 1970-01-01 open Assets:Test1 description: "Test account" ; alias food ; default 1970-01-01 open Liabilities:CreditCard 2018-03-17 * "Test 1" Assets:Test1 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 * "Test 3" Assets:Test3 10.00 EUR Equity:Opening-Balance 2014-07-09 event "location" "Paris, France" 2018-09-01 event "location" "Bologna, Italy" 2013-11-03 note Liabilities:CreditCard "Called about fraud" 2013-11-03 note Liabilities:CreditCard "Called about fraud" 2013-11-03 note Liabilities:CreditCard "Called about fraud" ledger2beancount-2.0/tests/ignore.ledger000066400000000000000000000017301362415351400204140ustar00rootroot00000000000000; NoL2B begin ~ Yearly Expenses:Auto:Repair $500.00 Assets ; NoL2B end account Assets:Test1 note Test account alias food default account Liabilities:CreditCard C 1.00 Mb = 1024 Kb ; NoL2B ; NoL2B begin account Assets:Test2 note Test account alias food default ; NoL2B end 2018-03-17 * Test 1 Assets:Test1 10.00 EUR Equity:Opening-Balance -10.00 EUR ; NoL2B begin 2018-03-17 * Test 2 Assets:Test2 Equity:Opening-Balance -10.00 EUR ; NoL2B end 2018-03-17 * Test 3 Assets:Test3 10.00 EUR Equity:Opening-Balance ; L2Bonly begin ;2014-07-09 event "location" "Paris, France" ; 2018-09-01 event "location" "Bologna, Italy" ; L2Bonly end ; 2013-11-03 note Liabilities:CreditCard "Called about fraud" ; L2Bonly # 2013-11-03 note Liabilities:CreditCard "Called about fraud" ; L2Bonly *2013-11-03 note Liabilities:CreditCard "Called about fraud" ; L2Bonly ledger2beancount-2.0/tests/ignore.yml000066400000000000000000000004111362415351400177460ustar00rootroot00000000000000 # A marker that tells ledger2beancount to ignore a line if the # marker is found. ignore_marker: NoL2B # A marker that tells ledger2beancount to take a line from # the input that is commented out, uncomment it and display # it in the output. keep_marker: L2Bonly ledger2beancount-2.0/tests/include1.beancount000066400000000000000000000002721362415351400213510ustar00rootroot000000000000001970-01-01 open Assets:Include1a 1970-01-01 open Assets:Include1b 1970-01-01 commodity INC1 2018-03-28 * "Include1" Assets:Include1a 10.00 INC1 Assets:Include1b ledger2beancount-2.0/tests/include1.ledger000066400000000000000000000001421362415351400206310ustar00rootroot00000000000000 2018-03-28 * Include1 Assets:Include1a 10.00 "INC1" Assets:Include1b ledger2beancount-2.0/tests/include2.beancount000066400000000000000000000002721362415351400213520ustar00rootroot000000000000001970-01-01 open Assets:Include2a 1970-01-01 open Assets:Include2b 1970-01-01 commodity INC2 2018-03-28 * "Include2" Assets:Include2a 10.00 INC2 Assets:Include2b ledger2beancount-2.0/tests/include2.ledger000066400000000000000000000001421362415351400206320ustar00rootroot00000000000000 2018-03-28 * Include2 Assets:Include2a 10.00 "INC2" Assets:Include2b ledger2beancount-2.0/tests/include3.beancount000066400000000000000000000002721362415351400213530ustar00rootroot000000000000001970-01-01 open Assets:Include3a 1970-01-01 open Assets:Include3b 1970-01-01 commodity INC3 2018-03-28 * "Include3" Assets:Include3a 10.00 INC3 Assets:Include3b ledger2beancount-2.0/tests/include3.ledger000066400000000000000000000001421362415351400206330ustar00rootroot00000000000000 2018-03-28 * Include3 Assets:Include3a 10.00 "INC3" Assets:Include3b ledger2beancount-2.0/tests/ledger2beancount.yml000066400000000000000000000025541362415351400217200ustar00rootroot00000000000000 date_format: "%Y-%m-%d" # Date without year (if ledger's Y/year directive is used) date_format_no_year: "%m-%d" # mapping of ledger metadata key to corresponding beancount key metadata_map: label: bank-label x-payee: payee x-payer: payer # metadata tags (*after* above mapping) used for specific purposes payee_tag: payee payer_tag: payer payee_split: - (?.*?)\s+\((?Tesco)\) payee_match: - (?i)^Oyster card top-up: TfL - ^Marriott reward1.*\(£\d+\.\d+\): Creation - ^Marriott reward2.*\(.\d+\.\d+\): Creation - test: test account_map: "Equity:Opening-balance": Equity:Opening-Balance # mapping of ledger commodities to valid beancount commodities commodity_map: Chase: UR '"M&M"': MILESMORE M&M2: MILESMORE2 M-M4: MILESMORE4 Another commodity: ANOTHER Mötz: MOETZ M-O: MOO XX: AA COLLA: COLLISION COLLB: COLLISION # You can set the following metadata tags to an empty string if you # don't want the metadata to be added to beancount. postdate_tag: date auxdate_tag: aux-date code_tag: code link_match: - ^\d\d\d\d-\d\d-\d\d- link_tags: - Trip - Invoice # A list of commodities that should be treated as commodities # rather than currencies even though they consist of 3 characters # (which is usually a characteristic of a currency) currency_is_commodity: - ETH commodity_is_currency: - AA - MR - XXXX ledger2beancount-2.0/tests/lots.beancount000066400000000000000000000230561362415351400206330ustar00rootroot00000000000000;---------------------------------------------------------------------- ; ledger2beancount conversion notes: ; ; - Commodity XXXx renamed to XXXX ; - Metadata key VALUE renamed to vALUE ; - Collision for commodity EUR: EUR, € ; - Collision for commodity USD: $, USD ;---------------------------------------------------------------------- 1970-01-01 open Assets:A 1970-01-01 open Assets:B 1970-01-01 open Assets:Bank 1970-01-01 open Assets:Cash 1970-01-01 open Expenses:Currency 1970-01-01 open Expenses:Food 1970-01-01 open Expenses:Test 1970-01-01 open Assets:Test 1970-01-01 open Equity:Opening-Balance 1970-01-01 open Income:Capital-Gain 1970-01-01 commodity ETH 1970-01-01 commodity EUR 1970-01-01 commodity GBP 1970-01-01 commodity LU0274208692 1970-01-01 commodity MR 1970-01-01 commodity USD 1970-01-01 commodity AA 1970-01-01 commodity XXXX 2018-03-17 * "Opening balance" Assets:Test 100.00 EUR {{90.00 GBP}} Equity:Opening-Balance 2018-03-17 * "Opening balance" Assets:Test 100.00 EUR {0.90 GBP} Equity:Opening-Balance 2018-03-17 * "Test" Assets:Test 10.00 EUR {0.90 GBP} Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test 10.00 EUR {0.90 GBP} Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test 10.00 EUR {0.90 GBP} Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test 10.00 EUR {0.90 GBP} Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test 10.00 EUR {0.90 GBP} Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test 10.00 EUR {0.90 GBP} Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test 10.00 EUR {{9 GBP}} Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test 10.00 EUR {0.90 GBP} Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test 10.00 EUR {0.90 GBP} Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test 10.00 EUR {1.23 USD, 2018-03-16} Equity:Opening-Balance -12.30 USD 2018-03-17 * "Test" Assets:Test 10.00 EUR {1.23 USD, 2018-03-16} Equity:Opening-Balance -12.30 USD 2018-03-20 * "Lot cost, no lot price" Assets:Test 1.00 EUR {0.90 GBP, 2018-03-18} Equity:Opening-Balance 2018-03-17 * "Test" Assets:Test 10.00 EUR {0.90 GBP} Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test -10.00 EUR {0.90 GBP} @ 0.95 GBP Assets:Test 9.50 GBP Income:Capital-Gain -0.50 GBP 2018-03-17 * "Test" Assets:Test -10.00 EUR {0.90 GBP} @ 0.95 GBP Assets:Test 9.50 GBP Income:Capital-Gain -0.50 GBP 2018-03-17 * "Test" Assets:Test 10.00 EUR {{9 GBP}} Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test 10.00 EUR {{9.00 GBP}} Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test 10.00 EUR {{9.00 GBP}} Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test 10.00 EUR {{9.00 GBP}} Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test 10.00 EUR {{9.00 GBP}} Equity:Opening-Balance -9.00 GBP 2018-03-20 * "Lot cost, no lot price" Assets:Test 1.00 EUR {{0.90 GBP, 2018-03-18}} Equity:Opening-Balance 2018-03-17 * "Test" Assets:Test 10.00 EUR {{12.30 USD, 2018-03-16}} Equity:Opening-Balance -12.30 USD 2018-03-17 * "Test" Assets:Test 10.00 EUR {{12.30 USD, 2018-03-16}} Equity:Opening-Balance -12.30 USD 2018-03-17 * "Test" Assets:Test 10.00 EUR {{9 GBP}} Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test 10.00 EUR {{9 GBP}} Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test -10.00 EUR {{9.00 GBP}} @@ 9.50 GBP Assets:Test 9.50 GBP Income:Capital-Gain -0.50 GBP 2018-03-17 * "Test" Assets:Test -10.00 EUR {{9.00 GBP}} @ 0.95 GBP Assets:Test 9.50 GBP Income:Capital-Gain -0.50 GBP 2018-03-17 * "Test" Assets:Test -10.00 EUR {0.90 GBP} @@ 9.50 GBP Assets:Test 9.50 GBP Income:Capital-Gain -0.50 GBP 2018-03-17 * "Test" Assets:Test 10.00 EUR @ 0.90 GBP Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test 10.00 EUR @@ 9.00 GBP Equity:Opening-Balance -9.00 GBP 2018-03-17 * "Test" Assets:Test 1 LU0274208692 {48.67 EUR} Equity:Opening-Balance -48.67 EUR 2018-03-17 * "Test" Assets:Test 1 LU0274208692 {{48.67 EUR}} Equity:Opening-Balance -48.67 EUR 2018-03-17 * "Test" Assets:Test 1.00 ETH {6500.00 EUR} Equity:Opening-Balance -6500.00 EUR 2018-03-17 * "Test" Assets:Test 1.00 ETH {{6500.00 EUR}} Equity:Opening-Balance -6500.00 EUR 2018-03-21 * "Lot note" Assets:Test 10.00 EUR {1.23 USD, "this is a note"} Equity:Opening-Balance -12.30 USD 2018-03-21 * "Lot note with lot date" Assets:Test 10.00 EUR {1.23 USD, 2018-03-16, "note! oh my @ what"} Equity:Opening-Balance -12.30 USD 2018-03-21 * "Lot note" Assets:Test 10.00 EUR {{12.30 USD, "a note"}} Equity:Opening-Balance -12.30 USD 2018-03-21 * "Lot note with date" Assets:Test 10.00 EUR {{12.30 USD, 2018-03-16, "whatever"}} Equity:Opening-Balance -12.30 USD 2018-03-21 * "Lot note with date and no space" Assets:Test 10.00 EUR {{12.30 USD, 2018-03-16, "whatever"}} Equity:Opening-Balance -12.30 USD 2018-03-20 * "Commodity treated as currency" Assets:Test 42.30 USD @@ 5641 MR Assets:Test -5641 MR 2018-03-27 * "Commodity treated as currency, transformed" Assets:Test 42.30 USD @@ 5641 XXXX Assets:Test -5641 XXXX 2018-03-27 * "Commodity treated as currency, mapped" Assets:Test 42.30 USD @@ 5641 AA Assets:Test -5641 AA 2018-04-22 * "Lot with comment" Assets:Test 10.00 EUR {0.90 GBP} ; comment Equity:Opening-Balance -9.00 GBP 2018-04-22 * "Lot with comment" Assets:Test 10.00 EUR {0.90 GBP} ; comment Equity:Opening-Balance -9.00 GBP 2018-04-22 * "Lot with comment" Assets:Test 10.00 EUR {1.23 USD, 2018-03-16} ; comment Equity:Opening-Balance -12.30 USD 2018-04-22 * "Lot with comment" Assets:Test -10.00 EUR {0.90 GBP, 2018-03-17} @ 0.95 GBP ; comment Assets:Test 9.50 GBP Income:Capital-Gain -0.50 GBP 2018-04-22 * "Lot with comment" Assets:Test 10.00 EUR {{12.30 USD, 2018-03-16}} ; comment Equity:Opening-Balance -12.30 USD 2018-04-22 * "Lot with comment" Assets:Test 10.00 EUR {1.23 USD, "this is a note"} ; comment Equity:Opening-Balance -12.30 USD 2018-04-22 * "Lot with comment, no space" Assets:Test 10.00 EUR {1.23 USD, "this is a note"} @ 1.30 USD ; comment Assets:Bank 2018-10-22 * "Commodity conversion of lot cost" Expenses:Test 2361.00 EUR {1.3831 USD} @ 1.4056 USD Expenses:Currency 53.12 USD Assets:Bank -3318.62 USD 2018-10-23 * "Lot information" Expenses:Test 416.00 EUR {1.2937 USD, 2012-05-12} @ 1.30 USD Assets:Bank 2018-10-23 * "Lot information, no space" Expenses:Test 416.00 EUR {1.2937 USD, 2012-05-12} @ 1.30 USD Assets:Bank 2018-10-23 * "Lot information" Expenses:Test 416.00 EUR {1.2937 USD, 2012-05-12} @ 1.30 USD Assets:Bank 2018-10-23 * "Lot information, no space" Expenses:Test 416.00 EUR {1.2937 USD, 2012-05-12} @ 1.30 USD Assets:Bank 2018-10-23 * "Lot information" Expenses:Test 416.00 EUR {1.2937 USD, 2012-05-12} Assets:Bank 2018-10-23 * "Lot information" Expenses:Test 416.00 EUR {1.2937 USD, 2012-05-12} Assets:Bank 2019-01-25 * "Lot information - with tag" Expenses:Test 416.00 EUR {1.2937 USD, 2012-05-12} tags: "foo, bar" Assets:Bank 2019-01-25 * "Cost - with tag" Assets:Test 10.00 EUR {{9 GBP}} tags: "foo, bar" Equity:Opening-Balance -9.00 GBP 2019-01-25 * "Conversion - with tag" Assets:Test 1 LU0274208692 {{48.67 EUR}} tags: "foo, bar" Equity:Opening-Balance -48.67 EUR 2019-01-28 * "Lot information - with metadata" Expenses:Test 416.00 EUR {1.2937 USD, 2012-05-12} foo: "bar" Assets:Bank 2019-01-28 * "Cost - with metadata" Assets:Test 10.00 EUR {{9 GBP}} foo: "bar" Equity:Opening-Balance -9.00 GBP 2019-01-28 * "Conversion - with metadata" Assets:Test 1 LU0274208692 {{48.67 EUR}} foo: "bar" Equity:Opening-Balance -48.67 EUR 2019-01-29 * "Implicit conversion" Assets:A 10.00 EUR Assets:B -11.42 USD @@ 10.00 EUR 2019-01-29 * "Implicit conversion" #foo Assets:A 10.00 EUR Assets:B -11.42 USD @@ 10.00 EUR 2019-01-29 * "Implicit conversion" Assets:A 10.00 EUR tags: "foo" Assets:B -11.42 USD @@ 10.00 EUR 2019-01-29 * "Implicit conversion" #foo Assets:A 10 EUR Assets:B -11.42 USD @@ 10 EUR foo: "bar" 2019-04-28 * "Don't parse the value: 30 DM as implicit conversion" Expenses:Food 20.00 USD vALUE: 30 DM Assets:Cash -20.00 USD ledger2beancount-2.0/tests/lots.ledger000066400000000000000000000222661362415351400201210ustar00rootroot00000000000000 account Assets:Test account Equity:Opening-Balance account Income:Capital-Gain commodity ETH commodity EUR commodity GBP commodity "LU0274208692" commodity MR commodity USD commodity XX commodity XXXx 2018-03-17 * Opening balance Assets:Test 100.00 EUR {{90.00 GBP}} Equity:Opening-Balance 2018-03-17 * Opening balance Assets:Test 100.00 EUR {0.90 GBP} Equity:Opening-Balance 2018-03-17 * Test Assets:Test 10.00 EUR {0.90 GBP} Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test 10.00 EUR { 0.90 GBP} Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test 10.00 EUR { 0.90 GBP } Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test 10.00 EUR { 0.90 GBP } Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test 10.00 EUR{ 0.90 GBP } Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test 10.00 EUR{0.90 GBP} Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test 10.00 EUR {{ 9 GBP}} Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test 10.00 EUR {0.90 GBP} @ 0.90 GBP Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test 10.00 EUR{0.90 GBP}@0.90 GBP Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test 10.00 EUR {1.23 USD} [2018-03-16] @ 1.23 USD Equity:Opening-Balance -12.30 USD 2018-03-17 * Test Assets:Test 10.00 EUR {1.23 USD} [2018-03-16] @ 1.23 USD Equity:Opening-Balance -12.30 USD 2018-03-20 * Lot cost, no lot price Assets:Test 1.00 EUR {0.90 GBP} [2018-03-18] Equity:Opening-Balance 2018-03-17 * Test Assets:Test 10.00 EUR {0.90 GBP} @ 0.90 GBP Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test -10.00 EUR {0.90 GBP} @ 0.95 GBP Assets:Test 9.50 GBP Income:Capital-Gain -0.50 GBP 2018-03-17 * Test Assets:Test -10.00 EUR {0.90 GBP} @ 0.95 GBP Assets:Test 9.50 GBP Income:Capital-Gain -0.50 GBP 2018-03-17 * Test Assets:Test 10.00 EUR {{9 GBP}} Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test 10.00 EUR {{9.00 GBP}} Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test 10.00 EUR {{ 9.00 GBP }} Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test 10.00 EUR {{9.00 GBP}} @@ 9.00 GBP Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test 10.00 EUR {{9.00 GBP}} @@ 9.00 GBP Equity:Opening-Balance -9.00 GBP 2018-03-20 * Lot cost, no lot price Assets:Test 1.00 EUR {{0.90 GBP}} [2018-03-18] Equity:Opening-Balance 2018-03-17 * Test Assets:Test 10.00 EUR {{12.30 USD}} [2018-03-16] @@ 12.30 USD Equity:Opening-Balance -12.30 USD 2018-03-17 * Test Assets:Test 10.00 EUR {{12.30 USD}} [2018-03-16] @@ 12.30 USD Equity:Opening-Balance -12.30 USD 2018-03-17 * Test Assets:Test 10.00 EUR {{9 GBP}} @@ 9 GBP Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test 10.00 EUR {{ 9 GBP }} @@ 9 GBP Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test -10.00 EUR {{9.00 GBP}} @@ 9.50 GBP Assets:Test 9.50 GBP Income:Capital-Gain -0.50 GBP 2018-03-17 * Test Assets:Test -10.00 EUR {{9.00 GBP}} @ 0.95 GBP Assets:Test 9.50 GBP Income:Capital-Gain -0.50 GBP 2018-03-17 * Test Assets:Test -10.00 EUR {0.90 GBP} @@ 9.50 GBP Assets:Test 9.50 GBP Income:Capital-Gain -0.50 GBP 2018-03-17 * Test Assets:Test 10.00 EUR @ 0.90 GBP Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test 10.00 EUR @@ 9.00 GBP Equity:Opening-Balance -9.00 GBP 2018-03-17 * Test Assets:Test 1 "LU0274208692" @ 48.67 EUR Equity:Opening-Balance -48.67 EUR 2018-03-17 * Test Assets:Test 1 "LU0274208692" @@ 48.67 EUR Equity:Opening-Balance -48.67 EUR 2018-03-17 * Test Assets:Test 1.00 ETH @ 6500.00 EUR Equity:Opening-Balance -6500.00 EUR 2018-03-17 * Test Assets:Test 1.00 ETH @@ 6500.00 EUR Equity:Opening-Balance -6500.00 EUR 2018-03-21 * Lot note Assets:Test 10.00 EUR {1.23 USD} (this is a note) @ 1.23 USD Equity:Opening-Balance -12.30 USD 2018-03-21 * Lot note with lot date Assets:Test 10.00 EUR {1.23 USD} [2018-03-16] (note! oh my @ what) @ 1.23 USD Equity:Opening-Balance -12.30 USD 2018-03-21 * Lot note Assets:Test 10.00 EUR {{12.30 USD}} (a note) @@ 12.30 USD Equity:Opening-Balance -12.30 USD 2018-03-21 * Lot note with date Assets:Test 10.00 EUR {{12.30 USD}} [2018-03-16] (whatever) @@ 12.30 USD Equity:Opening-Balance -12.30 USD 2018-03-21 * Lot note with date and no space Assets:Test 10.00 EUR {{12.30 USD}}[2018-03-16](whatever)@@12.30 USD Equity:Opening-Balance -12.30 USD 2018-03-20 * Commodity treated as currency Assets:Test 42.30 USD @@ 5641 MR Assets:Test -5641 MR 2018-03-27 * Commodity treated as currency, transformed Assets:Test 42.30 USD @@ 5641 XXXx Assets:Test -5641 XXXx 2018-03-27 * Commodity treated as currency, mapped Assets:Test 42.30 USD @@ 5641 XX Assets:Test -5641 XX 2018-04-22 * Lot with comment Assets:Test 10.00 EUR {0.90 GBP} ; comment Equity:Opening-Balance -9.00 GBP 2018-04-22 * Lot with comment Assets:Test 10.00 EUR {0.90 GBP} @ 0.90 GBP ; comment Equity:Opening-Balance -9.00 GBP 2018-04-22 * Lot with comment Assets:Test 10.00 EUR {1.23 USD} [2018-03-16] @ 1.23 USD ;comment Equity:Opening-Balance -12.30 USD 2018-04-22 * Lot with comment Assets:Test -10.00 EUR {0.90 GBP} [2018-03-17] @ 0.95 GBP ; comment Assets:Test 9.50 GBP Income:Capital-Gain -0.50 GBP 2018-04-22 * Lot with comment Assets:Test 10.00 EUR {{12.30 USD}} [2018-03-16] @@ 12.30 USD ; comment Equity:Opening-Balance -12.30 USD 2018-04-22 * Lot with comment Assets:Test 10.00 EUR {1.23 USD} (this is a note) @ 1.23 USD ; comment Equity:Opening-Balance -12.30 USD 2018-04-22 * Lot with comment, no space Assets:Test 10.00 EUR{1.23 USD}(this is a note)@1.30 USD; comment Assets:Bank 2018-10-22 * Commodity conversion of lot cost Expenses:Test €2361.00 {$1.3831} @ $1.4056 Expenses:Currency $53.12 Assets:Bank $-3318.62 2018-10-23 * Lot information Expenses:Test €416.00 {$1.2937} [2012-05-12] @ $1.30 Assets:Bank 2018-10-23 * Lot information, no space Expenses:Test €416.00{$1.2937}[2012-05-12]@$1.30 Assets:Bank 2018-10-23 * Lot information Expenses:Test 416.00 EUR {1.2937 USD} [2012-05-12] @ 1.30 USD Assets:Bank 2018-10-23 * Lot information, no space Expenses:Test 416.00 EUR{1.2937 USD}[2012-05-12]@1.30 USD Assets:Bank 2018-10-23 * Lot information Expenses:Test €416.00 {$1.2937} [2012-05-12] Assets:Bank 2018-10-23 * Lot information Expenses:Test 416.00 EUR {1.2937 USD} [2012-05-12] Assets:Bank 2019-01-25 * Lot information - with tag Expenses:Test €416.00 {$1.2937} [2012-05-12] ; :foo:bar: Assets:Bank 2019-01-25 * Cost - with tag Assets:Test 10.00 EUR {{ 9 GBP}} ; :foo:bar: Equity:Opening-Balance -9.00 GBP 2019-01-25 * Conversion - with tag Assets:Test 1 "LU0274208692" @@ 48.67 EUR ; :foo:bar: Equity:Opening-Balance -48.67 EUR 2019-01-28 * Lot information - with metadata Expenses:Test €416.00 {$1.2937} [2012-05-12] ; foo: bar Assets:Bank 2019-01-28 * Cost - with metadata Assets:Test 10.00 EUR {{ 9 GBP}} ; foo: bar Equity:Opening-Balance -9.00 GBP 2019-01-28 * Conversion - with metadata Assets:Test 1 "LU0274208692" @@ 48.67 EUR ; foo: bar Equity:Opening-Balance -48.67 EUR 2019-01-29 * Implicit conversion Assets:A 10.00 EUR Assets:B -11.42 USD 2019-01-29 * Implicit conversion ; :foo: Assets:A 10.00 EUR Assets:B -11.42 USD 2019-01-29 * Implicit conversion Assets:A 10.00 EUR ; :foo: Assets:B -11.42 USD 2019-01-29 * Implicit conversion ; :foo: Assets:A 10 EUR Assets:B -11.42 USD ; foo: bar 2019-04-28 * Don't parse the value: 30 DM as implicit conversion Expenses:Food 20.00 USD ; VALUE:: 30 DM Assets:Cash -20.00 USD ledger2beancount-2.0/tests/metadata.beancount000066400000000000000000000106561362415351400214340ustar00rootroot00000000000000;---------------------------------------------------------------------- ; ledger2beancount conversion notes: ; ; - Metadata key 2012 renamed to x2012 ; - Metadata key 2012foo renamed to x2012foo ; - Metadata key Date renamed to date ; - Metadata key Invoice renamed to invoice ; - Metadata key TEST1234TEST renamed to tEST1234TEST ; - Metadata key Trip renamed to trip ; - Metadata key a renamed to ax ; - Metadata key test:test renamed to test-test ; - Metadata key test♔ renamed to test- ; - Metadata key test♚ renamed to test- ; - Collision for metadata test-: test♔, test♚ ;---------------------------------------------------------------------- ; Beancount: 2.1.0 1970-01-01 open Assets:Test 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity EUR 2018-03-19 * "Metadata after posting, with amount" test: "foo bar baz" Assets:Test 10.00 EUR test: "foo" Equity:Opening-Balance -10.00 EUR 2018-03-19 * "Metadata after posting, no amount" test: "foo bar baz" Assets:Test test: "foo" Equity:Opening-Balance -10.00 EUR 2018-03-19 * "Metadata on next line of posting, no space" test: "foo bar baz" Assets:Test 10.00 EUR test: "bar" Equity:Opening-Balance -10.00 EUR 2018-03-19 * "Metadata on next line of posting, with space" test: "\"foo bar baz\"" Assets:Test 10.00 EUR test: "baz" Equity:Opening-Balance -10.00 EUR 2018-03-19 * "Metadata and comments" test: "foo bar baz" ; one comment Assets:Test 10.00 EUR ; another comment test: "baz" Equity:Opening-Balance -10.00 EUR ; and another comment 2018-03-19 * "Metadata, one of which should be converted to a link" #tag1 #tag2 ^brussels-fosdem #tag3 test: "foo bar baz" Assets:Test 10.00 EUR test: "baz" Equity:Opening-Balance -10.00 EUR 2018-03-19 * "Metadata, two of which should be converted to a link" #tag1 #tag2 ^brussels-fosdem #tag3 ^1234 test: "foo bar baz" Assets:Test 10.00 EUR test: "baz" Equity:Opening-Balance -10.00 EUR trip: "brussels-fosdem" 2018-03-19 * "Metadata, some posting-level links" #tag1 #tag2 ^brussels-fosdem #tag3 ^4 test: "foo bar baz" Assets:Test 10.00 EUR test: "baz" invoice: 5 Equity:Opening-Balance -10.00 EUR invoice: 6 2018-03-20 * "Typed meta data with date" date: 2017-12-31 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; label will be mapped to bank-label 2018-03-17 * "Map metadata" bank-label: "foo" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-04-12 * "Metadata starting with digit" x2012: "foo" Assets:Test 10.00 EUR Assets:Test 2018-04-12 * "Metadata starting with digit" x2012foo: "foo" Assets:Test 10.00 EUR Assets:Test 2018-04-12 * "Metadata starting with uppercase letter" tEST1234TEST: "foo" Assets:Test 10.00 EUR Assets:Test 2018-04-12 * "Metadata with invalid character, leading to collision" test-: "foo" Assets:Test 10.00 EUR Assets:Test 2018-04-12 * "Metadata with invalid character, leading to collision" test-: "foo" Assets:Test 10.00 EUR Assets:Test ; ledger reg -l "tag('test:test') =~ /foo/" 2018-04-12 * "Ledger metadata may contain a colon" test-test: "foo" Assets:Test 10.00 EUR Assets:Test 2019-01-28 * "Metadata on null posting" Assets:Test 10.00 EUR Assets:Test foo: "bar" 2019-04-29 * "Metadata key with one letter" Assets:Test 10.00 EUR ax: "books" Assets:Test -10.00 EUR 2020-02-18 * "Empty (but defined tag)" check_memo: "" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2020-02-18 * "Empty (but defined tag) with trailing whitespace" check_memo: "" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2020-02-18 * "No space -> not recognized by ledger as metadata" ; check_memo:bar Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ledger2beancount-2.0/tests/metadata.ledger000066400000000000000000000076411362415351400207200ustar00rootroot00000000000000; Beancount: 2.1.0 account Assets:Test account Equity:Opening-Balance commodity EUR 2018-03-19 * Metadata after posting, with amount ; test: foo bar baz Assets:Test 10.00 EUR ; test: foo Equity:Opening-Balance -10.00 EUR 2018-03-19 * Metadata after posting, no amount ; test: foo bar baz Assets:Test ; test: foo Equity:Opening-Balance -10.00 EUR 2018-03-19 * Metadata on next line of posting, no space ; test: foo bar baz Assets:Test 10.00 EUR ; test: bar Equity:Opening-Balance -10.00 EUR 2018-03-19 * Metadata on next line of posting, with space ; test: "foo bar baz" Assets:Test 10.00 EUR ; test: baz Equity:Opening-Balance -10.00 EUR 2018-03-19 * Metadata and comments ; test: foo bar baz ; one comment Assets:Test 10.00 EUR ; another comment ; test: baz Equity:Opening-Balance -10.00 EUR ; and another comment 2018-03-19 * Metadata, one of which should be converted to a link ; :tag1: ; test: foo bar baz ; :tag2: ; Trip: brussels-fosdem ; :tag3: Assets:Test 10.00 EUR ; test: baz Equity:Opening-Balance -10.00 EUR 2018-03-19 * Metadata, two of which should be converted to a link ; :tag1: ; test: foo bar baz ; :tag2: ; Trip: brussels-fosdem ; :tag3: ; Invoice:: 1234 Assets:Test 10.00 EUR ; test: baz Equity:Opening-Balance -10.00 EUR ; Trip: brussels-fosdem 2018-03-19 * Metadata, some posting-level links ; :tag1: ; test: foo bar baz ; :tag2: ; Trip: brussels-fosdem ; :tag3: ; Invoice:: 4 Assets:Test 10.00 EUR ; test: baz ; Invoice:: 5 Equity:Opening-Balance -10.00 EUR ; Invoice:: 6 2018-03-20 * Typed meta data with date ; Date:: [2017-12-31] Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; label will be mapped to bank-label 2018-03-17 * Map metadata ; label: foo Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-04-12 * Metadata starting with digit ; 2012: foo Assets:Test 10.00 EUR Assets:Test 2018-04-12 * Metadata starting with digit ; 2012foo: foo Assets:Test 10.00 EUR Assets:Test 2018-04-12 * Metadata starting with uppercase letter ; TEST1234TEST: foo Assets:Test 10.00 EUR Assets:Test 2018-04-12 * Metadata with invalid character, leading to collision ; test♚: foo Assets:Test 10.00 EUR Assets:Test 2018-04-12 * Metadata with invalid character, leading to collision ; test♔: foo Assets:Test 10.00 EUR Assets:Test ; ledger reg -l "tag('test:test') =~ /foo/" 2018-04-12 * Ledger metadata may contain a colon ; test:test: foo Assets:Test 10.00 EUR Assets:Test 2019-01-28 * Metadata on null posting Assets:Test 10.00 EUR Assets:Test ; foo: bar 2019-04-29 * Metadata key with one letter Assets:Test 10.00 EUR ; a: books Assets:Test -10.00 EUR 2020-02-18 * Empty (but defined tag) ; check_memo: Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2020-02-18 * Empty (but defined tag) with trailing whitespace ; check_memo: Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2020-02-18 * No space -> not recognized by ledger as metadata ; check_memo:bar Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ledger2beancount-2.0/tests/narration.beancount000066400000000000000000000017571362415351400216530ustar00rootroot00000000000000 1970-01-01 open Assets:Test 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity EUR 2018-03-17 * "Test \"quote me\" please" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; empty narration 2018-05-16 txn "" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; empty narration with flag 2018-05-16 * "" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-05-16 * "No space between flag and narration" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2019-03-05 txn "Foo\\" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2019-03-05 txn "Foo\\ bar" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2019-03-05 txn "Foo\\ \"" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ledger2beancount-2.0/tests/narration.ledger000066400000000000000000000017111362415351400211250ustar00rootroot00000000000000 account Assets:Test account Equity:Opening-Balance commodity EUR 2018-03-17 * Test "quote me" please Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; empty narration 2018-05-16 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; empty narration with flag 2018-05-16 * Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-05-16 *No space between flag and narration Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2019-03-05 Foo\ Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2019-03-05 Foo\ bar Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2019-03-05 Foo\ " Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ledger2beancount-2.0/tests/no-config.beancount000066400000000000000000000006761362415351400215340ustar00rootroot000000000000001970-01-01 open Assets:Test 1970-01-01 commodity EUR 1970-01-01 commodity GBP 1970-01-01 commodity USD 2018-09-27 * "Test conversion of built-in commodity codes" Assets:Test 10.00 EUR Assets:Test -10.00 EUR Assets:Test 10.00 GBP Assets:Test -10.00 GBP Assets:Test 10.00 USD Assets:Test -10.00 USD ledger2beancount-2.0/tests/no-config.ledger000066400000000000000000000005251362415351400210110ustar00rootroot00000000000000 2018-09-27 * Test conversion of built-in commodity codes Assets:Test €10.00 Assets:Test €-10.00 Assets:Test £10.00 Assets:Test £-10.00 Assets:Test $10.00 Assets:Test $-10.00 ledger2beancount-2.0/tests/no-config.yml000066400000000000000000000000261362415351400203440ustar00rootroot00000000000000 # empty config file ledger2beancount-2.0/tests/payee.beancount000066400000000000000000000033171362415351400207530ustar00rootroot00000000000000 1970-01-01 open Assets:Test 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity EUR 1970-01-01 commodity GBP 2018-03-18 * "Foo" "Payee Foo" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-18 * "Bar" "Payer Bar" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-18 * "TfL" "Oyster card top-up" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; case insensitive match 2018-03-18 * "TfL" "oyster card top-up" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-18 * "Tesco" "Supermarket" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-22 * "Creation" "Marriott reward1: test (£10.00)" Assets:Test 10.00 GBP Equity:Opening-Balance -10.00 GBP 2018-03-22 * "Creation" "Marriott reward2: test (£10.00)" Assets:Test 10.00 GBP Equity:Opening-Balance -10.00 GBP 2018-03-26 * "MK2" "Payee from metadata" Assets:Test 10.00 GBP Equity:Opening-Balance -10.00 GBP 2018-03-26 * "Martin" "Payer from metadata" Assets:Test 10.00 GBP Equity:Opening-Balance -10.00 GBP ; Interaction of payee_split and payee_tag 2018-03-31 * "MyEmployer" "Supermarket" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; Interaction of payee_match and payee_tag 2018-03-31 * "MyEmployer" "Oyster card top-up" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ledger2beancount-2.0/tests/payee.ledger000066400000000000000000000033571362415351400202430ustar00rootroot00000000000000 account Assets:Test account Equity:Opening-Balance commodity EUR commodity GBP 2018-03-18 * Payee Foo ; payee: Foo Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-18 * Payer Bar ; payer: Bar Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-18 * Oyster card top-up Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; case insensitive match 2018-03-18 * oyster card top-up Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-18 * Supermarket (Tesco) Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-22 * Marriott reward1: test (£10.00) Assets:Test 10.00 GBP Equity:Opening-Balance -10.00 GBP 2018-03-22 * Marriott reward2: test (£10.00) Assets:Test 10.00 GBP Equity:Opening-Balance -10.00 GBP 2018-03-26 * Payee from metadata ; X-Payee: MK2 Assets:Test 10.00 GBP Equity:Opening-Balance -10.00 GBP 2018-03-26 * Payer from metadata ; X-Payer: Martin Assets:Test 10.00 GBP Equity:Opening-Balance -10.00 GBP ; Interaction of payee_split and payee_tag 2018-03-31 * Supermarket (Tesco) ; X-Payee: MyEmployer Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; Interaction of payee_match and payee_tag 2018-03-31 * Oyster card top-up ; X-Payee: MyEmployer Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ledger2beancount-2.0/tests/prices.beancount000066400000000000000000000016171362415351400211360ustar00rootroot000000000000001970-01-01 commodity JPY 1970-01-01 commodity MILESMORE4 1970-01-01 commodity UR 1970-01-01 commodity USD 1970-01-01 open Assets:Test 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity ETH 1970-01-01 commodity EUR 1970-01-01 commodity GBP 2018-03-21 price EUR 0.87 GBP 2018-03-21 price UR 0.015 USD 2018-03-21 price MILESMORE4 0.01 USD 2019-04-28 price EUR 124.56 JPY 2018-03-21 * "Virtual cost (@)" Assets:Test 10.00 EUR @ 0.90 GBP Equity:Opening-Balance -9.00 GBP 2018-03-21 * "Virtual cost (@@)" Assets:Test 10.00 EUR @@ 9.00 GBP Equity:Opening-Balance -9.00 GBP 2018-03-21 * "Virtual cost (@) becoming a cost" Assets:Test 1.00 ETH {6500.00 EUR} Equity:Opening-Balance -6500.00 EUR 2018-03-21 * "Virtual cost (@) becoming a cost" Assets:Test 1.00 ETH {{6500.00 EUR}} Equity:Opening-Balance -6500.00 EUR ledger2beancount-2.0/tests/prices.ledger000066400000000000000000000013711362415351400204170ustar00rootroot00000000000000 account Assets:Test account Equity:Opening-Balance commodity ETH commodity EUR commodity GBP P 2018-03-21 EUR 0.87 GBP P 2018-03-21 Chase 0.015 USD P 2018-03-21 "M&M4" 0.01 USD P 2019-04-28 17:12:15 EUR ¥124.56 2018-03-21 * Virtual cost (@) Assets:Test 10.00 EUR (@) 0.90 GBP Equity:Opening-Balance -9.00 GBP 2018-03-21 * Virtual cost (@@) Assets:Test 10.00 EUR (@@) 9.00 GBP Equity:Opening-Balance -9.00 GBP 2018-03-21 * Virtual cost (@) becoming a cost Assets:Test 1.00 ETH (@) 6500.00 EUR Equity:Opening-Balance -6500.00 EUR 2018-03-21 * Virtual cost (@) becoming a cost Assets:Test 1.00 ETH (@@) 6500.00 EUR Equity:Opening-Balance -6500.00 EUR ledger2beancount-2.0/tests/runtests000077500000000000000000000035201362415351400175610ustar00rootroot00000000000000#!/bin/sh status=0 # We need sort from coreutils for -V case `uname -s` in Linux*) SORT=sort ;; Darwin*) SORT=gsort ;; *) SORT=sort ;; esac test_conversion () { test=$1 expected=$(echo $test | sed -e 's/.ledger$/.beancount/') actual=$(mktemp) printf "Converting $test... " config=ledger2beancount.yml t=$(echo $test | sed 's/.ledger$//') if [ -e $t.yml ]; then config=$t.yml fi ../bin/ledger2beancount --config $config $test > $actual if $(cmp -s $expected $actual); then echo "ok" else status=1 echo "FAIL" diff -urN $expected $actual | tail -n +3 fi rm -f $actual } test_validity_ledger () { test=$1 printf "Validating $test... " if ledger --init-file /dev/null -f $test bal > /dev/null; then echo "ok" else echo "FAIL" status=1 fi } test_validity_beancount () { test=$1 printf "Validating $test... " # Ensure beancount is new enough needed=$(grep "^; Beancount:" $test | head -n 1 | sed 's/^; Beancount:\s*//') if [ -n "$needed" ]; then latest=$(printf "$needed\n$beancount_version" | $SORT -V | tail -n 1) if [ "$beancount_version" != "$latest" ]; then echo "skipping since beancount is too old" return fi fi if bean-check $test; then echo "ok" else echo "FAIL" status=1 fi } export LC_ALL=C.UTF-8 ledger_version=$(ledger --version 2>/dev/null | grep "^Ledger [0-9]" | cut -d " " -f 2 | cut -d . -f 1) if [ -z $ledger_version ]; then echo "Skipping ledger validation checks since ledger is not installed" elif [ $ledger_version -eq 2 ]; then echo "Skipping ledger validation checks since ledger 2 is too old" else for test in *.ledger; do test_validity_ledger "$test" done fi for test in *.ledger; do test_conversion "$test" done beancount_version=$(bean-check --version 2>/dev/null | cut -d' ' -f2) for test in *.beancount; do test_validity_beancount "$test" done exit $status ledger2beancount-2.0/tests/runtests.bat000066400000000000000000000013261362415351400203250ustar00rootroot00000000000000 setlocal enableDelayedExpansion :: Set UTF-8 locale chcp 65001 :: Convert ledger files set error=0 for /r %%i in (*.ledger) do ( echo Converting %%i... set ledger=%%i set beancount=!ledger:.ledger=.beancount! set yml=!ledger:.ledger=.yml! if exist !yml! ( set config=!yml! ) else ( set config=ledger2beancount.yml ) perl ..\bin\ledger2beancount --config !config! %%i > temp diff --strip-trailing-cr -urN !beancount! temp if errorlevel 1 set error=1 del temp ) if "%error%"=="1" ( echo One or more conversions had unexpected results exit /b 1 ) :: Validate beancount files for /r %%i in (*.beancount) do ( echo Validating %%i... bean-check %%i ) ledger2beancount-2.0/tests/spacing.beancount000066400000000000000000000010241362415351400212650ustar00rootroot000000000000001970-01-01 open Assets:Test 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity EUR 2018-03-24 * "Test 1" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; comment 2018-03-24 * "Test 2" Assets:Test Equity:Opening-Balance -10.00 EUR 2018-03-24 * "Indented whitespace" Assets:Test 10.00 EUR Equity:Opening-Balance 2018-03-24 * "No empty line after the transaction" Assets:Test 10.00 EUR Equity:Opening-Balance ledger2beancount-2.0/tests/spacing.ledger000066400000000000000000000010071362415351400205520ustar00rootroot00000000000000account Assets:Test account Equity:Opening-Balance commodity EUR 2018-03-24 * Test 1 Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ; comment 2018-03-24 * Test 2 Assets:Test Equity:Opening-Balance -10.00 EUR 2018-03-24 * Indented whitespace Assets:Test 10.00 EUR Equity:Opening-Balance 2018-03-24 * No empty line after the transaction Assets:Test 10.00 EUR Equity:Opening-Balance ledger2beancount-2.0/tests/tags.beancount000066400000000000000000000046461362415351400206140ustar00rootroot00000000000000; Beancount: 2.1.0 1970-01-01 open Assets:Test 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity EUR 2018-03-17 * "Tag on transaction" #foo #bar #baz Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 * "Tag on transaction, split over two lines" #foo #bar #baz #second Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 * "Tag on transaction, one converted to a link" #foo #bar ^2018-02-02-brussels-fosdem #baz Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 * "Tag on transaction, one link on posting level" #foo #bar ^2018-02-02-brussels-fosdem #baz Assets:Test 10.00 EUR tags: "qux, quux, quuz" links: "2018-03-08-london" Equity:Opening-Balance -10.00 EUR 2018-03-17 * "Tag on postings" #foo #bar #baz Assets:Test 10.00 EUR tags: "foo" Equity:Opening-Balance -10.00 EUR tags: "bar" 2018-03-31 * "Tag on postings, without indentation" #foo #bar #baz Assets:Test 10.00 EUR tags: "qux" links: "2018-03-08-london" Equity:Opening-Balance -10.00 EUR tags: "quux, quuz" 2018-05-23 * "Tag on postings, same line" #foo #bar #baz Assets:Test 10.00 EUR tags: "qux" links: "2018-03-08-london" Equity:Opening-Balance -10.00 EUR tags: "quux, quuz" 2018-05-23 * "Tag on postings, same and next line" #foo #bar #baz Assets:Test 10.00 EUR tags: "qux, foo" links: "2018-03-08-london" Equity:Opening-Balance -10.00 EUR tags: "quux, quuz" ; This is not a tag; you need two spaces before the comment 2019-01-25 * "Just a payee description ; :foo:" #bar #baz Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2019-01-25 * "Tag on same line as payee" #foo #bar #baz Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2019-01-25 * "Tag on same line as payee" #foo #bar #baz Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2019-01-25 * "Comment and tag on same line as payee" ; comment #foo #bar #baz Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ledger2beancount-2.0/tests/tags.ledger000066400000000000000000000045731362415351400200770ustar00rootroot00000000000000; Beancount: 2.1.0 account Assets:Test account Equity:Opening-Balance commodity EUR 2018-03-17 * Tag on transaction ; :foo:bar:baz: Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 * Tag on transaction, split over two lines ; :foo:bar:baz: ; :second: Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 * Tag on transaction, one converted to a link ; :foo:bar:2018-02-02-brussels-fosdem:baz: Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 * Tag on transaction, one link on posting level ; :foo:bar:2018-02-02-brussels-fosdem:baz: Assets:Test 10.00 EUR ; :qux:quux:2018-03-08-london:quuz: Equity:Opening-Balance -10.00 EUR 2018-03-17 * Tag on postings ; :foo:bar:baz: Assets:Test 10.00 EUR ; :foo: Equity:Opening-Balance -10.00 EUR ; :bar: 2018-03-31 * Tag on postings, without indentation ; :foo:bar:baz: Assets:Test 10.00 EUR ; :qux:2018-03-08-london: Equity:Opening-Balance -10.00 EUR ; :quux:quuz: 2018-05-23 * Tag on postings, same line ; :foo:bar:baz: Assets:Test 10.00 EUR ; :qux:2018-03-08-london: Equity:Opening-Balance -10.00 EUR ; :quux:quuz: 2018-05-23 * Tag on postings, same and next line ; :foo:bar:baz: Assets:Test 10.00 EUR ; :qux:2018-03-08-london: ; :foo: Equity:Opening-Balance -10.00 EUR ; :quux:quuz: ; This is not a tag; you need two spaces before the comment 2019-01-25 * Just a payee description ; :foo: ; :bar:baz: Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2019-01-25 * Tag on same line as payee ; :foo: ; :bar:baz: Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2019-01-25 * Tag on same line as payee ; :foo: ; :bar:baz: Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2019-01-25 * Comment and tag on same line as payee ; comment :foo: ; :bar:baz: Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR ledger2beancount-2.0/tests/transactions.beancount000066400000000000000000000000671362415351400223570ustar00rootroot000000000000001970-01-01 open Assets:Test 1970-01-01 commodity EUR ledger2beancount-2.0/tests/transactions.ledger000066400000000000000000000002041362415351400216340ustar00rootroot00000000000000 2019-02-15 * A transaction with a single posting - only allowed when amount == 0 Assets:Test 0.00 EUR ledger2beancount-2.0/tests/virtual-postings.beancount000066400000000000000000000013311362415351400231740ustar00rootroot00000000000000;---------------------------------------------------------------------- ; ledger2beancount conversion notes: ; ; - Virtual posting in parentheses ignored ;---------------------------------------------------------------------- 1970-01-01 open Assets:Test 1970-01-01 open Assets:Wallet 1970-01-01 open Equity:Opening-Balance 1970-01-01 commodity EUR 2018-03-17 * "Virtual posting with parentheses" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR 2018-03-17 * "Virtual posting with brackets" Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR Assets:Wallet 7.00 EUR Equity:Opening-Balance -7.00 EUR ledger2beancount-2.0/tests/virtual-postings.ledger000066400000000000000000000006631362415351400224670ustar00rootroot00000000000000 2018-03-17 * Virtual posting with parentheses Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR (Budget:Test) -10.00 EUR 2018-03-17 * Virtual posting with brackets Assets:Test 10.00 EUR Equity:Opening-Balance -10.00 EUR [Assets:Wallet] 7.00 EUR [Equity:Opening-Balance] -7.00 EUR ledger2beancount-2.0/tests/virtual-postings.yml000066400000000000000000000000301362415351400220120ustar00rootroot00000000000000 convert_virtual: true