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