1 /********************************************************************\
2 * gnc-customer-sql.c -- customer 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
23 /** @file gnc-customer-sql.c
24 * @brief load and save address data to SQL
25 * @author Copyright (c) 2007-2008 Phil Longstaff <plongstaff@rogers.com>
26 *
27 * This file implements the top-level QofBackend API for saving/
28 * restoring data to/from an SQL database
29 */
30 #include <glib.h>
31
32 extern "C"
33 {
34 #include <config.h>
35
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include "gncBillTermP.h"
40 #include "gncCustomerP.h"
41 #include "gncTaxTableP.h"
42 }
43
44 #include "gnc-sql-connection.hpp"
45 #include "gnc-sql-backend.hpp"
46 #include "gnc-sql-object-backend.hpp"
47 #include "gnc-sql-column-table-entry.hpp"
48 #include "gnc-slots-sql.h"
49 #include "gnc-customer-sql.h"
50 #include "gnc-bill-term-sql.h"
51 #include "gnc-tax-table-sql.h"
52
53 #define _GNC_MOD_NAME GNC_ID_CUSTOMER
54
55 static QofLogModule log_module = G_LOG_DOMAIN;
56
57 #define TABLE_NAME "customers"
58 #define TABLE_VERSION 2
59
60 #define MAX_NAME_LEN 2048
61 #define MAX_ID_LEN 2048
62 #define MAX_NOTES_LEN 2048
63
64 static EntryVec col_table
65 ({
66 gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid" ),
67 gnc_sql_make_table_entry<CT_STRING>("name", MAX_NAME_LEN, COL_NNUL, "name"),
68 gnc_sql_make_table_entry<CT_STRING>("id", MAX_ID_LEN, COL_NNUL,
69 CUSTOMER_ID, true),
70 gnc_sql_make_table_entry<CT_STRING>("notes", MAX_NOTES_LEN, COL_NNUL,
71 CUSTOMER_NOTES, true),
72 gnc_sql_make_table_entry<CT_BOOLEAN>("active", 0, COL_NNUL,
73 QOF_PARAM_ACTIVE, true),
74 gnc_sql_make_table_entry<CT_NUMERIC>("discount", 0, COL_NNUL,
75 CUSTOMER_DISCOUNT, true),
76 gnc_sql_make_table_entry<CT_NUMERIC>("credit", 0, COL_NNUL,
77 CUSTOMER_CREDIT, true),
78 gnc_sql_make_table_entry<CT_COMMODITYREF>("currency", 0, COL_NNUL,
79 (QofAccessFunc)gncCustomerGetCurrency,
80 (QofSetterFunc)gncCustomerSetCurrency),
81 gnc_sql_make_table_entry<CT_BOOLEAN>("tax_override", 0, COL_NNUL,
82 CUSTOMER_TT_OVER, true),
83 gnc_sql_make_table_entry<CT_ADDRESS>("addr", 0, 0, CUSTOMER_ADDR,
84 true),
85 gnc_sql_make_table_entry<CT_ADDRESS>("shipaddr", 0, 0, CUSTOMER_SHIPADDR,
86 true),
87 gnc_sql_make_table_entry<CT_BILLTERMREF>("terms", 0, 0, CUSTOMER_TERMS,
88 true),
89 gnc_sql_make_table_entry<CT_INT>("tax_included", 0, 0,
90 (QofAccessFunc)gncCustomerGetTaxIncluded,
91 (QofSetterFunc)gncCustomerSetTaxIncluded),
92 gnc_sql_make_table_entry<CT_TAXTABLEREF>("taxtable", 0, 0,
93 (QofAccessFunc)gncCustomerGetTaxTable,
94 (QofSetterFunc)gncCustomerSetTaxTable),
95 });
96
GncSqlCustomerBackend()97 GncSqlCustomerBackend::GncSqlCustomerBackend() :
98 GncSqlObjectBackend(TABLE_VERSION, GNC_ID_CUSTOMER,
99 TABLE_NAME, col_table) {}
100
101 static GncCustomer*
load_single_customer(GncSqlBackend * sql_be,GncSqlRow & row)102 load_single_customer (GncSqlBackend* sql_be, GncSqlRow& row)
103 {
104 const GncGUID* guid;
105 GncCustomer* pCustomer;
106
107 g_return_val_if_fail (sql_be != NULL, NULL);
108
109 guid = gnc_sql_load_guid (sql_be, row);
110 pCustomer = gncCustomerLookup (sql_be->book(), guid);
111 if (pCustomer == NULL)
112 {
113 pCustomer = gncCustomerCreate (sql_be->book());
114 }
115 gnc_sql_load_object (sql_be, row, GNC_ID_CUSTOMER, pCustomer, col_table);
116 qof_instance_mark_clean (QOF_INSTANCE (pCustomer));
117
118 return pCustomer;
119 }
120
121 /* Because gncCustomerLookup has the arguments backwards: */
122 static inline GncCustomer*
gnc_customer_lookup(const GncGUID * guid,const QofBook * book)123 gnc_customer_lookup (const GncGUID *guid, const QofBook *book)
124 {
125 QOF_BOOK_RETURN_ENTITY(book, guid, GNC_ID_CUSTOMER, GncCustomer);
126 }
127
128 void
load_all(GncSqlBackend * sql_be)129 GncSqlCustomerBackend::load_all (GncSqlBackend* sql_be)
130 {
131 g_return_if_fail (sql_be != NULL);
132
133 std::string sql("SELECT * FROM " TABLE_NAME);
134 auto stmt = sql_be->create_statement_from_sql(sql);
135 auto result = sql_be->execute_select_statement(stmt);
136
137 for (auto row : *result)
138 load_single_customer (sql_be, row);
139
140 std::string pkey(col_table[0]->name());
141 sql = "SELECT DISTINCT ";
142 sql += pkey + " FROM " TABLE_NAME;
143 gnc_sql_slots_load_for_sql_subquery (sql_be, sql,
144 (BookLookupFn)gnc_customer_lookup);
145 }
146
147 /* ================================================================= */
148 void
create_tables(GncSqlBackend * sql_be)149 GncSqlCustomerBackend::create_tables (GncSqlBackend* sql_be)
150 {
151 gint version;
152
153 g_return_if_fail (sql_be != NULL);
154
155 version = sql_be->get_table_version( TABLE_NAME);
156 if (version == 0)
157 {
158 sql_be->create_table(TABLE_NAME, TABLE_VERSION, col_table);
159 }
160 else if (version < m_version)
161 {
162 /* Upgrade 64 bit int handling */
163 sql_be->upgrade_table(TABLE_NAME, col_table);
164 sql_be->set_table_version (TABLE_NAME, TABLE_VERSION);
165
166 PINFO ("Customers table upgraded from version 1 to version %d\n",
167 TABLE_VERSION);
168 }
169 }
170
171 /* ================================================================= */
172 static gboolean
customer_should_be_saved(GncCustomer * customer)173 customer_should_be_saved (GncCustomer* customer)
174 {
175 const char* id;
176
177 g_return_val_if_fail (customer != NULL, FALSE);
178
179 /* Make sure this is a valid customer before we save it -- should have an ID */
180 id = gncCustomerGetID (customer);
181 if (id == NULL || *id == '\0')
182 {
183 return FALSE;
184 }
185
186 return TRUE;
187 }
188
189 static void
write_single_customer(QofInstance * term_p,gpointer data_p)190 write_single_customer (QofInstance* term_p, gpointer data_p)
191 {
192 auto data = reinterpret_cast<write_objects_t*>(data_p);
193
194 g_return_if_fail (term_p != NULL);
195 g_return_if_fail (GNC_IS_CUSTOMER (term_p));
196 g_return_if_fail (data_p != NULL);
197
198 if (customer_should_be_saved (GNC_CUSTOMER (term_p)))
199 {
200 data->commit (term_p);
201 }
202 }
203
204 bool
write(GncSqlBackend * sql_be)205 GncSqlCustomerBackend::write (GncSqlBackend* sql_be)
206 {
207 write_objects_t data;
208
209 g_return_val_if_fail (sql_be != NULL, FALSE);
210
211 data.be = sql_be;
212 data.is_ok = TRUE;
213 data.obe = this;
214 qof_object_foreach (GNC_ID_CUSTOMER, sql_be->book(), write_single_customer,
215 (gpointer)&data);
216 return data.is_ok;
217 }
218
219 /* ========================== END OF FILE ===================== */
220