GnuCash c935c2f+
Loading...
Searching...
No Matches
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
53static 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
62static 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
100GncSqlInvoiceBackend::GncSqlInvoiceBackend() :
101 GncSqlObjectBackend(TABLE_VERSION, GNC_ID_INVOICE,
102 TABLE_NAME, col_table) {}
103
104static GncInvoice*
105load_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: */
125static inline GncInvoice*
126gnc_invoice_lookup (const GncGUID *guid, const QofBook *book)
127{
128 QOF_BOOK_RETURN_ENTITY(book, guid, GNC_ID_INVOICE, GncInvoice);
129}
130
131void
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;
146 gnc_sql_slots_load_for_sql_subquery (sql_be, sql,
147 (BookLookupFn)gnc_invoice_lookup);
148}
149
150/* ================================================================= */
151void
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/* ================================================================= */
179bool
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);
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/* ================================================================= */
237static gboolean
238invoice_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
254static void
255write_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
269bool
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/* ================================================================= */
281template<> 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
293template<> void
295{
296 add_objectref_guid_to_table(vec);
297}
298
299template<> 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 ===================== */
Main SQL backend structure.
uint_t get_table_version(const std::string &table_name) const noexcept
Returns the version number for a DB table.
bool create_table(const std::string &table_name, const EntryVec &col_table) const noexcept
Creates a table in the database.
GncSqlResultPtr execute_select_statement(const GncSqlStatementPtr &stmt) const noexcept
Executes an SQL SELECT statement and returns the result rows.
void upgrade_table(const std::string &table_name, const EntryVec &col_table) noexcept
Upgrades a table to a new structure.
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 save_commodity(gnc_commodity *comm) noexcept
Ensure that a commodity referenced in another object is in fact saved in the database.
bool set_table_version(const std::string &table_name, uint_t version) noexcept
Registers the version for a table.
void add_to_query(QofIdTypeConst obj_name, void *pObject, PairVec &vec) const noexcept override
Add a pair of the table column heading and object's value's string representation to a PairVec; used ...
void add_to_table(ColVec &vec) const noexcept override
Add a GncSqlColumnInfo structure for the column type to a ColVec.
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 write(GncSqlBackend *) override
Write all objects of m_type_name to the database.
bool commit(GncSqlBackend *sql_be, QofInstance *inst) override
UPDATE/INSERT a single instance of m_type_name into the database.
void load_all(GncSqlBackend *) override
Load all objects of m_type in the database into memory.
void create_tables(GncSqlBackend *) override
Conditionally create or update a database table from m_col_table.
Encapsulates per-class table schema with functions to load, create a table, commit a changed front-en...
Row of SQL Query results.
load and save accounts data to SQL
load and save data to SQL
Commodity handling public routines.
load and save invoice data to SQL
load and save accounts data to SQL
#define QOF_BOOK_RETURN_ENTITY(book, guid, e_type, c_type)
Encapsulates all the information about a dataset manipulated by QOF.
Definition qofbook.h:101
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition qofclass.h:123
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
Definition qofclass.h:130
const gchar * QofIdTypeConst
QofIdTypeConst declaration.
Definition qofid.h:82
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
gboolean qof_instance_get_destroying(gconstpointer ptr)
Retrieve the flag that indicates whether or not this object is about to be destroyed.
#define PINFO(format, args...)
Print an informational note.
Definition qoflog.h:256
void qof_object_foreach(QofIdTypeConst type_name, QofBook *book, QofInstanceForeachCB cb, gpointer user_data)
Invoke the callback 'cb' on every instance ov a particular object type.
The type used to store guids in C.
Definition guid.h:75
QofBook reference.
Definition qofbook-p.hpp:47
Data-passing struct for callbacks to qof_object_foreach() used in GncSqlObjectBackend::write().