GnuCash  5.6-150-g038405b370+
gnc-invoice-sql.cpp
1 /********************************************************************\
2  * gnc-invoice-sql.c - invoice sql backend *
3  * *
4  * This program is free software; you can redistribute it and/or *
5  * modify it under the terms of the GNU General Public License as *
6  * published by the Free Software Foundation; either version 2 of *
7  * the License, or (at your option) any later version. *
8  * *
9  * This program is distributed in the hope that it will be useful, *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12  * GNU General Public License for more details. *
13  * *
14  * You should have received a copy of the GNU General Public License*
15  * along with this program; if not, contact: *
16  * *
17  * Free Software Foundation Voice: +1-617-542-5942 *
18  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
19  * Boston, MA 02110-1301, USA gnu@gnu.org *
20  * *
21 \********************************************************************/
22 
30 #include <guid.hpp>
31 #include <config.h>
32 
33 #include <glib.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 #include "gnc-commodity.h"
38 
39 #include "gncBillTermP.h"
40 #include "gncInvoiceP.h"
41 
42 #include "gnc-sql-connection.hpp"
43 #include "gnc-sql-backend.hpp"
44 #include "gnc-sql-object-backend.hpp"
45 #include "gnc-sql-column-table-entry.hpp"
46 #include "gnc-commodity-sql.h"
47 #include "gnc-slots-sql.h"
48 #include "gnc-invoice-sql.h"
49 #include "gnc-bill-term-sql.h"
50 
51 #define _GNC_MOD_NAME GNC_ID_INVOICE
52 
53 static QofLogModule log_module = G_LOG_DOMAIN;
54 
55 #define TABLE_NAME "invoices"
56 #define TABLE_VERSION 4
57 
58 #define MAX_ID_LEN 2048
59 #define MAX_NOTES_LEN 2048
60 #define MAX_BILLING_ID_LEN 2048
61 
62 static EntryVec col_table
63 ({
64  gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid"),
65  gnc_sql_make_table_entry<CT_STRING>("id", MAX_ID_LEN, COL_NNUL, INVOICE_ID,
66  true),
67  gnc_sql_make_table_entry<CT_TIME>("date_opened", 0, 0, INVOICE_OPENED,
68  true),
69  gnc_sql_make_table_entry<CT_TIME>("date_posted", 0, 0, INVOICE_POSTED,
70  true),
71  gnc_sql_make_table_entry<CT_STRING>("notes", MAX_NOTES_LEN, COL_NNUL,
72  "notes"),
73  gnc_sql_make_table_entry<CT_BOOLEAN>("active", 0, COL_NNUL,
74  QOF_PARAM_ACTIVE, true),
75  gnc_sql_make_table_entry<CT_COMMODITYREF>("currency", 0, COL_NNUL,
76  (QofAccessFunc)gncInvoiceGetCurrency,
77  (QofSetterFunc)gncInvoiceSetCurrency),
78  gnc_sql_make_table_entry<CT_OWNERREF>("owner", 0, 0,
79  (QofAccessFunc)gncInvoiceGetOwner,
80  (QofSetterFunc)gncInvoiceSetOwner),
81  gnc_sql_make_table_entry<CT_BILLTERMREF>("terms", 0, 0, INVOICE_TERMS,
82  true),
83  gnc_sql_make_table_entry<CT_STRING>("billing_id", MAX_BILLING_ID_LEN, 0,
84  INVOICE_BILLINGID, true),
85  gnc_sql_make_table_entry<CT_TXREF>("post_txn", 0, 0, INVOICE_POST_TXN,
86  true),
87  gnc_sql_make_table_entry<CT_LOTREF>("post_lot", 0, 0,
88  (QofAccessFunc)gncInvoiceGetPostedLot,
89  (QofSetterFunc)gncInvoiceSetPostedLot),
90  gnc_sql_make_table_entry<CT_ACCOUNTREF>("post_acc", 0, 0, INVOICE_ACC,
91  true),
92  gnc_sql_make_table_entry<CT_OWNERREF>("billto", 0, 0,
93  (QofAccessFunc)gncInvoiceGetBillTo,
94  (QofSetterFunc)gncInvoiceSetBillTo),
95  gnc_sql_make_table_entry<CT_NUMERIC>("charge_amt", 0, 0,
96  (QofAccessFunc)gncInvoiceGetToChargeAmount,
97  (QofSetterFunc)gncInvoiceSetToChargeAmount),
98 });
99 
100 GncSqlInvoiceBackend::GncSqlInvoiceBackend() :
101  GncSqlObjectBackend(TABLE_VERSION, GNC_ID_INVOICE,
102  TABLE_NAME, col_table) {}
103 
104 static GncInvoice*
105 load_single_invoice (GncSqlBackend* sql_be, GncSqlRow& row)
106 {
107  const GncGUID* guid;
108  GncInvoice* pInvoice;
109 
110  g_return_val_if_fail (sql_be != NULL, NULL);
111 
112  guid = gnc_sql_load_guid (sql_be, row);
113  pInvoice = gncInvoiceLookup (sql_be->book(), guid);
114  if (pInvoice == NULL)
115  {
116  pInvoice = gncInvoiceCreate (sql_be->book());
117  }
118  gnc_sql_load_object (sql_be, row, GNC_ID_INVOICE, pInvoice, col_table);
119  qof_instance_mark_clean (QOF_INSTANCE (pInvoice));
120 
121  return pInvoice;
122 }
123 
124 /* Because gncInvoiceLookup has the arguments backwards: */
125 static inline GncInvoice*
126 gnc_invoice_lookup (const GncGUID *guid, const QofBook *book)
127 {
128  QOF_BOOK_RETURN_ENTITY(book, guid, GNC_ID_INVOICE, GncInvoice);
129 }
130 
131 void
133 {
134  g_return_if_fail (sql_be != NULL);
135 
136  std::string sql("SELECT * FROM " TABLE_NAME);
137  auto stmt = sql_be->create_statement_from_sql(sql);
138  auto result = sql_be->execute_select_statement(stmt);
139 
140  for (auto row : *result)
141  load_single_invoice (sql_be, row);
142 
143  std::string pkey(col_table[0]->name());
144  sql = "SELECT DISTINCT ";
145  sql += pkey + " FROM " TABLE_NAME;
147  (BookLookupFn)gnc_invoice_lookup);
148 }
149 
150 /* ================================================================= */
151 void
153 {
154  gint version;
155 
156  g_return_if_fail (sql_be != NULL);
157 
158  version = sql_be->get_table_version( TABLE_NAME);
159  if (version == 0)
160  {
161  sql_be->create_table(TABLE_NAME, TABLE_VERSION, col_table);
162  }
163  else if (version < TABLE_VERSION)
164  {
165  /* Upgrade:
166  1->2: 64 bit int handling
167  2->3: invoice open date can be NULL
168  3->4: Use DATETIME instead of TIMESTAMP in MySQL
169  */
170  sql_be->upgrade_table(TABLE_NAME, col_table);
171  sql_be->set_table_version (TABLE_NAME, TABLE_VERSION);
172 
173  PINFO ("Invoices table upgraded from version %d to version %d\n", version,
174  TABLE_VERSION);
175  }
176 }
177 
178 /* ================================================================= */
179 bool
181 {
182  const GncGUID* guid;
183  GncInvoice* invoice;
184  E_DB_OPERATION op;
185  gboolean is_infant;
186  gboolean is_ok = TRUE;
187 
188  g_return_val_if_fail (inst != NULL, FALSE);
189  g_return_val_if_fail (GNC_IS_INVOICE (inst), FALSE);
190  g_return_val_if_fail (sql_be != NULL, FALSE);
191 
192  invoice = GNC_INVOICE (inst);
193 
194  is_infant = qof_instance_get_infant (inst);
195  if (qof_instance_get_destroying (inst))
196  {
197  op = OP_DB_DELETE;
198  }
199  else if (sql_be->pristine() || is_infant)
200  {
201  op = OP_DB_INSERT;
202  }
203  else
204  {
205  op = OP_DB_UPDATE;
206  }
207  if (op != OP_DB_DELETE)
208  {
209  // Ensure the commodity is in the db
210  is_ok = sql_be->save_commodity(gncInvoiceGetCurrency(invoice));
211  }
212 
213  if (is_ok)
214  {
215  is_ok = sql_be->do_db_operation(op, TABLE_NAME, GNC_ID_INVOICE, inst,
216  col_table);
217  }
218 
219  if (is_ok)
220  {
221  // Now, commit or delete any slots
222  guid = qof_instance_get_guid (inst);
223  if (!qof_instance_get_destroying (inst))
224  {
225  is_ok = gnc_sql_slots_save (sql_be, guid, is_infant, inst);
226  }
227  else
228  {
229  is_ok = gnc_sql_slots_delete (sql_be, guid);
230  }
231  }
232 
233  return is_ok;
234 }
235 
236 /* ================================================================= */
237 static gboolean
238 invoice_should_be_saved (GncInvoice* invoice)
239 {
240  const char* id;
241 
242  g_return_val_if_fail (invoice != NULL, FALSE);
243 
244  /* make sure this is a valid invoice before we save it -- should have an ID */
245  id = gncInvoiceGetID (invoice);
246  if (id == NULL || *id == '\0')
247  {
248  return FALSE;
249  }
250 
251  return TRUE;
252 }
253 
254 static void
255 write_single_invoice (QofInstance* term_p, gpointer data_p)
256 {
257  auto s = reinterpret_cast<write_objects_t*>(data_p);
258 
259  g_return_if_fail (term_p != NULL);
260  g_return_if_fail (GNC_IS_INVOICE (term_p));
261  g_return_if_fail (data_p != NULL);
262 
263  if (s->is_ok && invoice_should_be_saved (GNC_INVOICE (term_p)))
264  {
265  s->commit (term_p);
266  }
267 }
268 
269 bool
271 {
272  g_return_val_if_fail (sql_be != NULL, FALSE);
273  write_objects_t data{sql_be, true, this};
274 
275  qof_object_foreach (GNC_ID_INVOICE, sql_be->book(), write_single_invoice, &data);
276 
277  return data.is_ok;
278 }
279 
280 /* ================================================================= */
281 template<> void
283  GncSqlRow& row,
284  QofIdTypeConst obj_name,
285  gpointer pObject) const noexcept
286 {
287  load_from_guid_ref(row, obj_name, pObject,
288  [sql_be](GncGUID* g){
289  return gncInvoiceLookup (sql_be->book(), g);
290  });
291 }
292 
293 template<> void
295 {
296  add_objectref_guid_to_table(vec);
297 }
298 
299 template<> void
301  const gpointer pObject,
302  PairVec& vec) const noexcept
303 {
304  add_objectref_guid_to_query(obj_name, pObject, vec);
305 }
306 
307 /* ========================== END OF FILE ===================== */
bool do_db_operation(E_DB_OPERATION op, const char *table_name, QofIdTypeConst obj_name, gpointer pObject, const EntryVec &table) const noexcept
Performs an operation on the database.
bool create_table(const std::string &table_name, const EntryVec &col_table) const noexcept
Creates a table in the database.
bool set_table_version(const std::string &table_name, uint_t version) noexcept
Registers the version for a table.
GncSqlResultPtr execute_select_statement(const GncSqlStatementPtr &stmt) const noexcept
Executes an SQL SELECT statement and returns the result rows.
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
void gnc_sql_slots_load_for_sql_subquery(GncSqlBackend *sql_be, const std::string subquery, BookLookupFn lookup_fn)
gnc_sql_slots_load_for_sql_subquery - Loads slots for all objects whose guid is supplied by a subquer...
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
load and save data to SQL
const gchar * QofIdTypeConst
QofIdTypeConst declaration.
Definition: qofid.h:82
load and save accounts data to SQL
gboolean qof_instance_get_destroying(gconstpointer ptr)
Retrieve the flag that indicates whether or not this object is about to be destroyed.
bool write(GncSqlBackend *) override
Write all objects of m_type_name to the database.
gboolean gnc_sql_slots_save(GncSqlBackend *sql_be, const GncGUID *guid, gboolean is_infant, QofInstance *inst)
gnc_sql_slots_save - Saves slots for an object to the db.
void add_to_query(QofIdTypeConst obj_name, void *pObject, PairVec &vec) const noexcept override
Add a pair of the table column heading and object&#39;s value&#39;s string representation to a PairVec; used ...
void load_all(GncSqlBackend *) override
Load all objects of m_type in the database into memory.
#define QOF_BOOK_RETURN_ENTITY(book, guid, e_type, c_type)
Encapsulates all the information about a dataset manipulated by QOF.
Definition: qofbook.h:186
load and save accounts data to SQL
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
Definition: qofclass.h:185
void load(const GncSqlBackend *sql_be, GncSqlRow &row, QofIdTypeConst obj_name, void *pObject) const noexcept override
Load a value into an object from the database row.
bool save_commodity(gnc_commodity *comm) noexcept
Ensure that a commodity referenced in another object is in fact saved in the database.
Row of SQL Query results.
void upgrade_table(const std::string &table_name, const EntryVec &col_table) noexcept
Upgrades a table to a new structure.
void create_tables(GncSqlBackend *) override
Conditionally create or update a database table from m_col_table.
void qof_object_foreach(QofIdTypeConst type_name, QofBook *book, QofInstanceForeachCB cb, gpointer user_data)
Invoke the callback &#39;cb&#39; on every instance ov a particular object type.
Definition: qofobject.cpp:185
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition: qofclass.h:178
Encapsulates per-class table schema with functions to load, create a table, commit a changed front-en...
bool commit(GncSqlBackend *sql_be, QofInstance *inst) override
UPDATE/INSERT a single instance of m_type_name into the database.
Data-passing struct for callbacks to qof_object_foreach() used in GncSqlObjectBackend::write().
gboolean gnc_sql_slots_delete(GncSqlBackend *sql_be, const GncGUID *guid)
gnc_sql_slots_delete - Deletes slots for an object from the db.
void add_to_table(ColVec &vec) const noexcept override
Add a GncSqlColumnInfo structure for the column type to a ColVec.
load and save invoice data to SQL
The type used to store guids in C.
Definition: guid.h:75
uint_t get_table_version(const std::string &table_name) const noexcept
Returns the version number for a DB table.
Commodity handling public routines.
Main SQL backend structure.