Git commit 3d40b969b2b5de92e7f8ccec07e26f40c47b327c by Stephane Mankowski. Committed on 16/06/2016 at 20:29. Pushed by smankowski into branch 'master'.
Import of PDF invoice M +1 -0 CHANGELOG M +2 -0 CMakeLists.txt M +42 -5 doc/index.docbook M +1 -1 doc/kde_docbook M +1 -0 plugins/import/CMakeLists.txt C +20 -21 plugins/import/skrooge_import_pdf/CMakeLists.txt [from: plugins/import/CMakeLists.txt - 059% similarity] A +7 -0 plugins/import/skrooge_import_pdf/allopneus.extractor A +7 -0 plugins/import/skrooge_import_pdf/biofan.extractor A +7 -0 plugins/import/skrooge_import_pdf/easycartouche.extractor A +7 -0 plugins/import/skrooge_import_pdf/engie.extractor A +8 -0 plugins/import/skrooge_import_pdf/free.extractor A +24 -0 plugins/import/skrooge_import_pdf/freemobile.extractor A +7 -0 plugins/import/skrooge_import_pdf/ldlc.extractor A +18 -0 plugins/import/skrooge_import_pdf/org.kde.skrooge-import-pdf.desktop A +7 -0 plugins/import/skrooge_import_pdf/oscaro.extractor A +7 -0 plugins/import/skrooge_import_pdf/oxybul.extractor A +7 -0 plugins/import/skrooge_import_pdf/pixmania.extractor A +253 -0 plugins/import/skrooge_import_pdf/skgimportpluginpdf.cpp [License: GPL (v2+)] A +71 -0 plugins/import/skrooge_import_pdf/skgimportpluginpdf.h [License: GPL (v2+)] A +7 -0 plugins/import/skrooge_import_pdf/spartoo.extractor A +7 -0 plugins/import/skrooge_import_pdf/topachat.extractor http://commits.kde.org/skrooge/3d40b969b2b5de92e7f8ccec07e26f40c47b327c diff --git a/CHANGELOG b/CHANGELOG index a56810a..8b020d9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ skrooge (2.5.0) *Correction: The 31 of the month, in budget page, "Previous month" does not work *New feature: Capability to set/change order of budget rules *New feature: Tooltip on modified amount of budget to explain the reasons of modifications + *New feature: Import of PDF invoice -- Stephane MANKOWSKI <steph...@mankowski.fr> xxx diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e4202c..d382923 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,6 +191,8 @@ IF(SKG_BUILD_TEST AND NOT WIN32) ADD_SUBDIRECTORY(tests) ENDIF(SKG_BUILD_TEST AND NOT WIN32) +ADD_SUBDIRECTORY(doc) + #Main application ADD_SUBDIRECTORY(skrooge) ADD_SUBDIRECTORY(skroogeconvert) diff --git a/doc/index.docbook b/doc/index.docbook index cb07435..e603f0b 100644 --- a/doc/index.docbook +++ b/doc/index.docbook @@ -44,15 +44,15 @@ <year>2013</year> <year>2014</year> <year>2015</year> + <year>2016</year> <holder>Stéphane MANKOWSKI</holder> <holder>Guillaume DE BURE</holder> </copyright> <legalnotice>&FDLNotice;</legalnotice> - <date>15/06/2015</date> - <releaseinfo>2.0.0</releaseinfo> - + <date>15/06/2016</date> + <releaseinfo>2.5.0</releaseinfo> <abstract> <para> @@ -693,8 +693,10 @@ <listitem><para>QIF: <trademark>Quicken</trademark> Import File. Maybe the most common financial file format. However, it has some rather annoying limitations, like not giving the unit for operation, or no strict date formatting.</para></listitem> <listitem><para>IIF: <trademark>Intuit</trademark> Interchange Format is used by <trademark>QuickBooks</trademark>.</para></listitem> <listitem><para>SKG: This is useful to merge 2 &appname; documents</para></listitem> + <listitem><para>PDF: This allows to create the operation from a PDF invoice. The invoice is also associated to the operation as a property. Read the <link linkend="howto_extractor">How to</link> if you want ot know how to extract information from an invoice not supported yet.</para></listitem> <listitem><para>Backend: &appname; can also import operations by using a backend. The only one supported is <ulink url="http://weboob.org/">WEBOOB</ulink>. By using this backend you can import all operations from all your banks in only one click. For that, you just have to install <ulink url="http://weboob.org/">WEBOOB</ulink> and activate the corresponding backend from settings.</para> - <tip><para>If you do not want to store your bank passwords in the configuration file of WEBOOB, you can do that: + + <tip><para>If you do not want to store your bank passwords in the configuration file of WEBOOB, you can do that: <itemizedlist> <listitem><para>Add passwords for each bank by doing <quote>kwallet-query -f Weboob kdewallet -w m_bank_name</quote></para></listitem> @@ -2499,7 +2501,42 @@ file is opened. It is also recommended to create a different account (⪚ "ETF" <para>The size of your document can be very important. If you delete some old transactions, the size will increase. This is normal because &appname; keeps the history of all modifications for the undo/redo mechanism. So if you want to reduce the size of your document, you just have to clear the history.</para> - </sect1> + </sect1> + + <sect1 id="howto_extractor"> + <title>How to define a new invoice extractor?</title> + <para>&appname; uses pdftotext to extract all strings of a PDF. After that, it uses an text file describing how to find key values. If you want to define a new invoice extractor, you have to do that:</para> + <itemizedlist> + <listitem><para>Launch <command>pdftotext</command> on your PDF file</para></listitem> + <listitem><para>Open the text file generated and the corresponding PDF file</para></listitem> + <listitem><para>Create a new text with an extension ".extractor". Example: google.extractor</para></listitem> + <listitem><para>Your file must be like this:</para> +<programlisting> +payee=REGEXPCAP:^(Biofan) SPRL$ +date=REGEXPCAP:^Order Date: (.*)$ +dateformat=dd MMM yyyy +number=REGEXPCAP:^N° de facture (.*)$ +mode=SET:Carte +comment=REGEXPCAP:^N° de commande (.*)$|SET:Commande %1 +amount=REGEXP:^Montant global:$|LINEOFFSET:2 +</programlisting> +<para>Each attribute (payee, date, number, mode, comment and amount) use the same syntax: COMMAND:value|COMMAND:value|...</para> +<para>The command can be:</para> + <itemizedlist> + <listitem><para><command>REGEXPCAP</command>: This a regular expression capturing a value</para></listitem> + <listitem><para><command>REGEXP</command>: To find the line in the file maching a regular expression</para></listitem> + <listitem><para><command>LINEOFFSET</command>: To change the line index.</para></listitem> + <listitem><para><command>SET</command>: To force the value. Can be used as first command or after the REGEXPCAP (see example).</para></listitem> + </itemizedlist> +<para>dateformat is the format of the date extracted.</para> +</listitem> + + <listitem><para>Put this file in the same directory than all other .extractor files</para></listitem> + </itemizedlist> + <para> + </para> + </sect1> + </chapter> <chapter id="credits"> diff --git a/doc/kde_docbook b/doc/kde_docbook index 893e05b..59cd3c7 100755 --- a/doc/kde_docbook +++ b/doc/kde_docbook @@ -14,7 +14,7 @@ echo " -> OK !"; # Convert to html echo "Running xsltproc... "; -xsltproc -o $2 /usr/share/kde4/apps/ksgmltools2/customization/kde-nochunk.xsl $1; +xsltproc -o $2 /usr/share/kf5/kdoctools/customization/kde-nochunk.xsl $1; if [ $? -gt 0 ]; then echo " -> xsltproc failed !"; exit 1; diff --git a/plugins/import/CMakeLists.txt b/plugins/import/CMakeLists.txt index 0ff1777..85fa0ed 100644 --- a/plugins/import/CMakeLists.txt +++ b/plugins/import/CMakeLists.txt @@ -33,6 +33,7 @@ ADD_SUBDIRECTORY(skrooge_import_mt940) IF(LIBOFX_FOUND) ADD_SUBDIRECTORY(skrooge_import_ofx) ENDIF(LIBOFX_FOUND) +ADD_SUBDIRECTORY(skrooge_import_pdf) ADD_SUBDIRECTORY(skrooge_import_skg) ADD_SUBDIRECTORY(skrooge_import_xhb) diff --git a/plugins/import/CMakeLists.txt b/plugins/import/skrooge_import_pdf/CMakeLists.txt similarity index 59% copy from plugins/import/CMakeLists.txt copy to plugins/import/skrooge_import_pdf/CMakeLists.txt index 0ff1777..27086ad 100644 --- a/plugins/import/CMakeLists.txt +++ b/plugins/import/skrooge_import_pdf/CMakeLists.txt @@ -14,26 +14,25 @@ #* You should have received a copy of the GNU General Public License * #* along with this program. If not, see <http://www.gnu.org/licenses/> * #*************************************************************************** -#Correction bug 223848 vvvv -#FIND_PACKAGE( LibOfx REQUIRED ) -FIND_PACKAGE( LibOfx ) +MESSAGE( STATUS "..:: CMAKE PLUGIN_IMPORT_PDF ::..") -ADD_SUBDIRECTORY(skrooge_import_afb120) -ADD_SUBDIRECTORY(skrooge_import_backend) -ADD_SUBDIRECTORY(skrooge_import_iif) -ADD_SUBDIRECTORY(skrooge_import_qif) -ADD_SUBDIRECTORY(skrooge_import_csv) -ADD_SUBDIRECTORY(skrooge_import_gnc) -ADD_SUBDIRECTORY(skrooge_import_gsb) -ADD_SUBDIRECTORY(skrooge_import_json) -ADD_SUBDIRECTORY(skrooge_import_kmy) -ADD_SUBDIRECTORY(skrooge_import_mmb) -ADD_SUBDIRECTORY(skrooge_import_mny) -ADD_SUBDIRECTORY(skrooge_import_mt940) -IF(LIBOFX_FOUND) - ADD_SUBDIRECTORY(skrooge_import_ofx) -ENDIF(LIBOFX_FOUND) -ADD_SUBDIRECTORY(skrooge_import_skg) +PROJECT(plugin_import_PDF) -ADD_SUBDIRECTORY(skrooge_import_xhb) -ADD_SUBDIRECTORY(skrooge_import_xml) +LINK_DIRECTORIES (${LIBRARY_OUTPUT_PATH}) + +SET(skrooge_import_pdf_SRCS + skgimportpluginpdf.cpp +) + +ADD_LIBRARY(skrooge_import_pdf MODULE ${skrooge_import_pdf_SRCS}) +TARGET_LINK_LIBRARIES(skrooge_import_pdf KF5::Parts skgbasemodeler skgbasegui skgbankmodeler skgbankgui) + +########### install files ############### +INSTALL(TARGETS skrooge_import_pdf DESTINATION ${KDE_INSTALL_QTPLUGINDIR}) +INSTALL(FILES ${PROJECT_SOURCE_DIR}/org.kde.skrooge-import-pdf.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) +INSTALL(DIRECTORY . DESTINATION ${KDE_INSTALL_DATADIR}/skrooge/extractors FILES_MATCHING PATTERN "*.extractor" +PATTERN ".svn" EXCLUDE +PATTERN "CMakeLists.txt" EXCLUDE +PATTERN "CMakeFiles" EXCLUDE +PATTERN "grantlee_filters" EXCLUDE +PATTERN "Testing" EXCLUDE) \ No newline at end of file diff --git a/plugins/import/skrooge_import_pdf/allopneus.extractor b/plugins/import/skrooge_import_pdf/allopneus.extractor new file mode 100644 index 0000000..11257d1 --- /dev/null +++ b/plugins/import/skrooge_import_pdf/allopneus.extractor @@ -0,0 +1,7 @@ +payee=REGEXP:^Réglé par Carte bancaire date de facture|SET:Allo Pneus +date=REGEXP:^Date$|LINEOFFSET:1 +dateformat=dd/MM/yyyy +number=REGEXP:^Numéro$|LINEOFFSET:1 +mode=SET:Carte +comment=REGEXP:^N°Commande$|LINEOFFSET:1|SET:Commande %1 +amount=REGEXP:^Montant TTC :$|LINEOFFSET:1|REGEXPCAP:^([^ ]*) .*$ diff --git a/plugins/import/skrooge_import_pdf/biofan.extractor b/plugins/import/skrooge_import_pdf/biofan.extractor new file mode 100644 index 0000000..85346c7 --- /dev/null +++ b/plugins/import/skrooge_import_pdf/biofan.extractor @@ -0,0 +1,7 @@ +payee=REGEXPCAP:^(Biofan) SPRL$ +date=REGEXPCAP:^Order Date: (.*)$ +dateformat=dd MMM yyyy +number=REGEXPCAP:^N° de facture (.*)$ +mode=SET:Carte +comment=REGEXPCAP:^N° de commande (.*)$|SET:Commande %1 +amount=REGEXP:^Montant global:$|LINEOFFSET:2 diff --git a/plugins/import/skrooge_import_pdf/easycartouche.extractor b/plugins/import/skrooge_import_pdf/easycartouche.extractor new file mode 100644 index 0000000..ef5a95f --- /dev/null +++ b/plugins/import/skrooge_import_pdf/easycartouche.extractor @@ -0,0 +1,7 @@ +payee=REGEXPCAP:^(EasyCartouche) est une marque et un service +date=REGEXPCAP:^Passée le ([^ ]*) et traitée le +dateformat=dd/MM/yyyy +number=REGEXPCAP:^FACTURE n° (.*)$ +mode=SET:Carte +comment=REGEXPCAP:^Commande n° (.*)$|SET:Commande %1 +amount=REGEXP:^Total TTC$|LINEOFFSET:4 diff --git a/plugins/import/skrooge_import_pdf/engie.extractor b/plugins/import/skrooge_import_pdf/engie.extractor new file mode 100644 index 0000000..2f6d99a --- /dev/null +++ b/plugins/import/skrooge_import_pdf/engie.extractor @@ -0,0 +1,7 @@ +payee=REGEXPCAP:^(ENGIE) - SA au capital de +date=REGEXPCAP:^VOTRE FACTURE DU (.*) +dateformat=dd/MM/yy +number=REGEXPCAP:^N°(.*)$ +mode=SET:Carte +comment=LINEOFFSET:1 +amount=REGEXP:^MONTANT TTC$|LINEOFFSET:2|REGEXPCAP:^([^ ]*) .*$ diff --git a/plugins/import/skrooge_import_pdf/free.extractor b/plugins/import/skrooge_import_pdf/free.extractor new file mode 100644 index 0000000..e68fb2c --- /dev/null +++ b/plugins/import/skrooge_import_pdf/free.extractor @@ -0,0 +1,8 @@ +payee=REGEXPCAP:^(Free) Service Abonné$ +date=REGEXPCAP:Facture no .* du (.*)$ +dateformat=dd MMM yyyy +number=REGEXPCAP:Facture no (.*) du +comment=REGEXPCAP:(^Communications de la ligne .*$) +mode=SET:Prélèvement +amount=REGEXP:^Total facture$|LINEOFFSET:13 + diff --git a/plugins/import/skrooge_import_pdf/freemobile.extractor b/plugins/import/skrooge_import_pdf/freemobile.extractor new file mode 100644 index 0000000..99a5704 --- /dev/null +++ b/plugins/import/skrooge_import_pdf/freemobile.extractor @@ -0,0 +1,24 @@ +#The payee extraction. +#If the payee is not found, then the process is stopped with this extractor +payee=REGEXPCAP:^(Free Mobile) – SAS + +#The date extraction. +date=REGEXPCAP:Facture no .* du (.*)$ + +#The date format +dateformat=dd MMM yyyy + +#The number extraction +number=REGEXPCAP:Facture no (.*) du + +#The comment extraction +comment=REGEXPCAP:(^Consommations du .*$) + +#The mode extraction +mode=SET:Prélèvement + +#The amount extraction +amount=REGEXP:^Somme à payer TTC$|LINEOFFSET:-4|REGEXPCAP:^([^ ]*) .*$ + + +#For the regexp syntax, you can consult this page: http://qt-project.org/doc/qt-4.8/qregexp.html diff --git a/plugins/import/skrooge_import_pdf/ldlc.extractor b/plugins/import/skrooge_import_pdf/ldlc.extractor new file mode 100644 index 0000000..aebb7cf --- /dev/null +++ b/plugins/import/skrooge_import_pdf/ldlc.extractor @@ -0,0 +1,7 @@ +payee=REGEXPCAP:^(LDLC) AURORE EP5-4-S1 SANS SYSTEME$ +date=REGEXPCAP:^Date de la facture : (.*)$ +dateformat=dd/MM/yyyy +number=REGEXP:^N° de facture :$|LINEOFFSET:1 +mode=SET:Carte +comment=REGEXP:^Désignation$|LINEOFFSET:7 +amount=REGEXP:^Les conditions générales de vente|LINEOFFSET:-5 diff --git a/plugins/import/skrooge_import_pdf/org.kde.skrooge-import-pdf.desktop b/plugins/import/skrooge_import_pdf/org.kde.skrooge-import-pdf.desktop new file mode 100644 index 0000000..4a83972 --- /dev/null +++ b/plugins/import/skrooge_import_pdf/org.kde.skrooge-import-pdf.desktop @@ -0,0 +1,18 @@ +[Desktop Entry] +Name=Skrooge import PDF plugin +Comment=A Skrooge plugin to import PDF files +Encoding=UTF-8 +Icon=skrooge +Type=Service +X-KDE-ServiceTypes=SKG IMPORT/Plugin +X-KDE-Library=skrooge_import_pdf +X-Krunner-ID=Skrooge import PDF plugin +X-KDE-PluginInfo-Author=Stephane MANKOWSKI +X-KDE-PluginInfo-Email=steph...@mankowski.fr +X-KDE-PluginInfo-Name=skrooge_import_pdf +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://skrooge.org/ +X-KDE-PluginInfo-Category=Plugins +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plugins/import/skrooge_import_pdf/oscaro.extractor b/plugins/import/skrooge_import_pdf/oscaro.extractor new file mode 100644 index 0000000..ff2154b --- /dev/null +++ b/plugins/import/skrooge_import_pdf/oscaro.extractor @@ -0,0 +1,7 @@ +payee=REGEXPCAP:^(OSCARO).COM$ +date=REGEXPCAP:^Date de facturation : (.*)$ +dateformat=dd/MM/yyyy +number=REGEXPCAP:^Facture : (.*)$ +mode=SET:Carte +comment=REGEXPCAP:^Numéro de commande : (.*)$|SET:Commande %1 +amount=REGEXP:^Montant TTC :$|LINEOFFSET:4 diff --git a/plugins/import/skrooge_import_pdf/oxybul.extractor b/plugins/import/skrooge_import_pdf/oxybul.extractor new file mode 100644 index 0000000..db583e8 --- /dev/null +++ b/plugins/import/skrooge_import_pdf/oxybul.extractor @@ -0,0 +1,7 @@ +payee=REGEXPCAP:^(Oxybul) Eveil et Jeux vous remercie +date=REGEXP:^Date de commande :$|LINEOFFSET:4 +dateformat=dd/MM/yyyy +number=REGEXPCAP:^FACTURE N° : (.*)$ +mode=SET:Carte +comment=REGEXP:^N° commande :$|LINEOFFSET:4|SET:Commande %1 +amount=REGEXP:^TOTAL TTC de votre commande$|LINEOFFSET:-3 diff --git a/plugins/import/skrooge_import_pdf/pixmania.extractor b/plugins/import/skrooge_import_pdf/pixmania.extractor new file mode 100644 index 0000000..49a6ff7 --- /dev/null +++ b/plugins/import/skrooge_import_pdf/pixmania.extractor @@ -0,0 +1,7 @@ +payee=REGEXPCAP:^(PIXMANIA).COM : +date=REGEXP:^Date de facture :$|LINEOFFSET:2 +dateformat=yyyy-MM-dd +number=REGEXPCAP:^BON DE LIVRAISON ET FACTURE (.*)$ +mode=SET:Carte +comment=REGEXP:^N° de commande :$|LINEOFFSET:2|SET:Commande %1 +amount=REGEXP:^Total TTC$|LINEOFFSET:2|REGEXPCAP:^(.*) .*$ diff --git a/plugins/import/skrooge_import_pdf/skgimportpluginpdf.cpp b/plugins/import/skrooge_import_pdf/skgimportpluginpdf.cpp new file mode 100644 index 0000000..5208b3a --- /dev/null +++ b/plugins/import/skrooge_import_pdf/skgimportpluginpdf.cpp @@ -0,0 +1,253 @@ +/*************************************************************************** + * Copyright (C) 2008 by S. MANKOWSKI / G. DE BURE supp...@mankowski.fr * + * * + * 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 2 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 <http://www.gnu.org/licenses/> * + ***************************************************************************/ +/** @file + * This file is Skrooge plugin for for PDF import / export. + * http://jerome.girod.perso.sfr.fr/finance/pdfx.php + * + * @author Stephane MANKOWSKI / Guillaume DE BURE + */ +#include "skgimportpluginpdf.h" + +#include <kpluginfactory.h> + +#include <qfileinfo.h> +#include <qstandardpaths.h> +#include <qdiriterator.h> +#include <qtemporaryfile.h> +#include <qprocess.h> + +#include "skgtraces.h" +#include "skgservices.h" +#include "skgbankincludes.h" +#include "skgimportexportmanager.h" + +/** + * This plugin factory. + */ +K_PLUGIN_FACTORY(SKGImportPluginPDFFactory, registerPlugin<SKGImportPluginPDF>();) + +SKGImportPluginPDF::SKGImportPluginPDF(QObject* iImporter, const QVariantList& iArg) + : SKGImportPlugin(iImporter) +{ + SKGTRACEINFUNC(10); + Q_UNUSED(iArg); +} + +SKGImportPluginPDF::~SKGImportPluginPDF() +{ +} + +bool SKGImportPluginPDF::isImportPossible() +{ + SKGTRACEINFUNC(10); + return (!m_importer ? true : m_importer->getFileNameExtension() == QStringLiteral("PDF")); +} + +QString SKGImportPluginPDF::extract(const QStringList& iLine, const QString& iSyntax) +{ + QString output; + int currentIndex = -1; + bool setpossible = true; + + // Interpret the syntax + auto items = SKGServices::splitCSVLine(iSyntax, '|', false); + for (const auto& item : items) { + if (item.startsWith(QLatin1String("REGEXPCAP:"))) { + QRegExp regexp(item.right(item.length() - 10)); + if (output.isEmpty()) { + for (const auto& line : iLine) { + if (regexp.indexIn(line) > -1) { + output = regexp.cap(1); + break; + } + } + } else { + if (regexp.indexIn(output) > -1) { + output = regexp.cap(1); + } + } + } else if (item.startsWith(QLatin1String("REGEXP:"))) { + setpossible = false; + QRegExp regexp(item.right(item.length() - 7)); + int nb = iLine.count(); + for (int i = 0; i < nb; ++i) { + if (regexp.indexIn(iLine.at(i)) > -1) { + currentIndex = i; + setpossible = true; + break; + } + } + } else if (item.startsWith(QLatin1String("LINEOFFSET:"))) { + currentIndex += SKGServices::stringToInt(item.right(item.length() - 11)); + if (currentIndex >= 0 && currentIndex < iLine.count()) { + output = iLine.at(currentIndex); + } + } else if (item.startsWith(QLatin1String("SET:")) && setpossible) { + QString s = item.right(item.length() - 4); + if (s.contains(QLatin1String("%1"))) { + output = s.arg(output); + } else { + output = s; + } + } + } + + + return output; +} + + +SKGError SKGImportPluginPDF::importFile() +{ + if (!m_importer) { + return SKGError(ERR_ABORT, i18nc("Error message", "Invalid parameters")); + } + SKGError err; + SKGTRACEINFUNCRC(2, err); + + // Begin transaction + err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import %1 file", "PDF"), 2); + IFOK(err) { + // Open file + IFOK(err) { + // Extract text from PDF + QString file = m_importer->getLocalFileName(); + QTemporaryFile txtFile; + txtFile.open(); + QString cmd = "pdftotext \"" % file % "\" \"" % txtFile.fileName() % "\""; + + QProcess p; + p.start(cmd); + if (!p.waitForFinished(1000 * 60 * 2) || p.exitCode() != 0) { + err.setReturnCode(ERR_FAIL).setMessage(i18nc("Error message", "The following command line failed with code %2:\n'%1'", cmd, p.exitCode())); + + } else { + // Step 1 done + IFOKDO(err, m_importer->getDocument()->stepForward(1)) + + // Read the text file + QStringList lines; + QTextStream stream(&txtFile); + while (!stream.atEnd()) { + // Read line + lines.push_back(stream.readLine()); + } + + // Search extractors + bool found = false; + QString a = QStringLiteral("skrooge/extractors"); + const auto dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, a, QStandardPaths::LocateDirectory); + for (const auto& dir : dirs) { + QDirIterator it(dir, QStringList() << QStringLiteral("*.extractor")); + while (it.hasNext()) { + // Read extractor + QString fileName = it.next(); + QString extractor = QFileInfo(fileName).baseName().toUpper(); + QHash< QString, QString > properties; + err = SKGServices::readPropertyFile(fileName, properties); + IFOK(err) { + // Check if this extractor is done for this file + QString payee = extract(lines, properties[QStringLiteral("payee")]); + if (!payee.isEmpty()) { + // Search the date + QString date = extract(lines, properties[QStringLiteral("date")]); + QString dateFormat = properties[QStringLiteral("dateformat")]; + auto d = QDate::fromString(date, dateFormat); + if (!dateFormat.contains(QStringLiteral("yyyy")) && d.year() < 2000) { + d = d.addYears(100); + } + + // Search the amount + double amount = SKGServices::stringToDouble(extract(lines, properties[QStringLiteral("amount")])); + + // Search the comment + QString comment = extract(lines, properties[QStringLiteral("comment")]); + + // Search the number + QString number = extract(lines, properties[QStringLiteral("number")]); + + // Search the mode + QString mode = extract(lines, properties[QStringLiteral("mode")]); + + // Get account + SKGAccountObject account; + SKGOperationObject act; + m_importer->getDocument()->getObject("v_account_display", "t_close='N' AND t_type='C' ORDER BY i_NBOPERATIONS DESC LIMIT 1", act); + if (act.exist()) { + account = act; + IFOKDO(err, m_importer->getDocument()->sendMessage(i18nc("An information message", "Using account '%1' for import", account.getName()))) + } else { + IFOKDO(err, m_importer->getDefaultAccount(account)) + } + + // Get unit + SKGUnitObject unit; + IFOKDO(err, m_importer->getDefaultUnit(unit)) + + // Create operation + SKGOperationObject operation; + IFOKDO(err, account.addOperation(operation, true)); + IFOKDO(err, operation.setDate(d)) + + + IFOKDO(err, operation.setUnit(unit)) + SKGPayeeObject payeeObj; + IFOKDO(err, SKGPayeeObject::createPayee(m_importer->getDocument(), payee, payeeObj)); + IFOKDO(err, operation.setPayee(payeeObj)) + IFOKDO(err, operation.setComment(comment)) + IFOKDO(err, operation.setMode(mode)) + IFOKDO(err, operation.setImportID(QStringLiteral("PDF-") % extractor % QStringLiteral("-") % number)) + // This is normal. PDF inport is for only one operation, so no check if already imported + IFOKDO(err, operation.setAttribute(QStringLiteral("t_imported"), QStringLiteral("Y"))) + IFOKDO(err, operation.save(false)) + + SKGSubOperationObject subop; + IFOKDO(err, operation.addSubOperation(subop)) + IFOKDO(err, subop.setComment(comment)) + IFOKDO(err, subop.setQuantity(-amount)); + IFOKDO(err, subop.save(false, false)) + + // Add file + IFOKDO(err, err = operation.setProperty(i18n("Invoice"), file, file)) + + found = true; + break; + } + } + } + } + + if (!found) { + IFOKDO(err, m_importer->getDocument()->sendMessage(i18nc("An information message", "Invoice %1 has not been imported because no recognized.", file), SKGDocument::Error)) + } + + // Step 2 done + IFOKDO(err, m_importer->getDocument()->stepForward(2)) + } + } + } + SKGENDTRANSACTION(m_importer->getDocument(), err); + + return err; +} + +QString SKGImportPluginPDF::getMimeTypeFilter() const +{ + return "*.pdf|" % i18nc("A file format", "PDF file (invoice)"); +} + +#include <skgimportpluginpdf.moc> diff --git a/plugins/import/skrooge_import_pdf/skgimportpluginpdf.h b/plugins/import/skrooge_import_pdf/skgimportpluginpdf.h new file mode 100644 index 0000000..b75e583 --- /dev/null +++ b/plugins/import/skrooge_import_pdf/skgimportpluginpdf.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2008 by S. MANKOWSKI / G. DE BURE supp...@mankowski.fr * + * * + * 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 2 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 <http://www.gnu.org/licenses/> * + ***************************************************************************/ +#ifndef SKGIMPORTPLUGINPDF_H +#define SKGIMPORTPLUGINPDF_H +/** @file +* This file is Skrooge plugin for PDF import / export. +* +* @author Stephane MANKOWSKI / Guillaume DE BURE +*/ +#include "skgimportplugin.h" + +/** + * This file is Skrooge plugin for PDF import / export. + */ +class SKGImportPluginPDF : public SKGImportPlugin +{ + Q_OBJECT + Q_INTERFACES(SKGImportPlugin) + +public: + /** + * Default constructor + * @param iImporter the parent importer + * @param iArg the arguments + */ + explicit SKGImportPluginPDF(QObject* iImporter, const QVariantList& iArg); + + /** + * Default Destructor + */ + virtual ~SKGImportPluginPDF(); + + /** + * To know if import is possible with this plugin + */ + virtual bool isImportPossible() override; + + /** + * Import a file + * @return an object managing the error. + * @see SKGError + */ + virtual SKGError importFile() override; + + /** + * Return the mime type filter + * @return the mime type filter. Example: "*.csv|CSV file" + */ + virtual QString getMimeTypeFilter() const override; + + +private: + Q_DISABLE_COPY(SKGImportPluginPDF) + QString extract(const QStringList& iLine, const QString& iSyntax); +}; + +#endif // SKGIMPORTPLUGINPDF_H diff --git a/plugins/import/skrooge_import_pdf/spartoo.extractor b/plugins/import/skrooge_import_pdf/spartoo.extractor new file mode 100644 index 0000000..443174a --- /dev/null +++ b/plugins/import/skrooge_import_pdf/spartoo.extractor @@ -0,0 +1,7 @@ +payee=REGEXPCAP:^(Spartoo)$ +date=REGEXPCAP:^Date : (.*)$ +dateformat=dd/MM/yyyy +number=REGEXPCAP:^Facture : (.*)$ +mode=SET:Carte +comment=REGEXP:^Désignation$|LINEOFFSET:4 +amount=REGEXP:^Total TTC$|LINEOFFSET:2|REGEXPCAP:^(.*) .*$ diff --git a/plugins/import/skrooge_import_pdf/topachat.extractor b/plugins/import/skrooge_import_pdf/topachat.extractor new file mode 100644 index 0000000..81bbada --- /dev/null +++ b/plugins/import/skrooge_import_pdf/topachat.extractor @@ -0,0 +1,7 @@ +payee=REGEXPCAP:^(TOPACHAT)-CLUST +date=REGEXP:^Date facture$|LINEOFFSET:7 +dateformat=dd/MM/yyyy +number=REGEXP:^N° Commande$|LINEOFFSET:7 +mode=SET:Carte +comment=REGEXP:^Facture$|LINEOFFSET:1|SET:Commande %1 +amount=REGEXP:^TTC à payer en euros$|LINEOFFSET:3 _______________________________________________ kde-doc-english mailing list kde-doc-english@kde.org https://mail.kde.org/mailman/listinfo/kde-doc-english