00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include <glib.h>
00043 #include <glib/gi18n.h>
00044
00045 #include "config.h"
00046 #include "Account.h"
00047 #include "AccountP.h"
00048 #include "gnc-lot.h"
00049 #include "gnc-lot-p.h"
00050 #include "cap-gains.h"
00051 #include "Transaction.h"
00052 #include "TransactionP.h"
00053
00054
00055 static QofLogModule log_module = GNC_MOD_LOT;
00056
00057
00058
00059
00060 QOF_GOBJECT_IMPL(gnc_lot, GNCLot, QOF_TYPE_INSTANCE);
00061
00062 static void
00063 gnc_lot_init(GNCLot* lot)
00064 {
00065 }
00066
00067 static void
00068 gnc_lot_dispose_real (GObject *lotp)
00069 {
00070 }
00071
00072 static void
00073 gnc_lot_finalize_real(GObject* lotp)
00074 {
00075 }
00076
00077 static void
00078 gnc_lot_init_data (GNCLot *lot, QofBook *book)
00079 {
00080 ENTER ("(lot=%p, book=%p)", lot, book);
00081 lot->account = NULL;
00082 lot->splits = NULL;
00083 lot->is_closed = -1;
00084 lot->marker = 0;
00085
00086 qof_instance_init_data(&lot->inst, GNC_ID_LOT, book);
00087 LEAVE ("(lot=%p, book=%p)", lot, book);
00088 }
00089
00090 GNCLot *
00091 gnc_lot_new (QofBook *book)
00092 {
00093 GNCLot *lot;
00094 g_return_val_if_fail (book, NULL);
00095
00096 lot = g_object_new (GNC_TYPE_LOT, NULL);
00097 gnc_lot_init_data (lot, book);
00098 qof_event_gen (&lot->inst, QOF_EVENT_CREATE, NULL);
00099 return lot;
00100 }
00101
00102 static void
00103 gnc_lot_free(GNCLot* lot)
00104 {
00105 GList *node;
00106 if (!lot) return;
00107
00108 ENTER ("(lot=%p)", lot);
00109 qof_event_gen (&lot->inst, QOF_EVENT_DESTROY, NULL);
00110
00111
00112 for (node=lot->splits; node; node=node->next)
00113 {
00114 Split *s = node->data;
00115 s->lot = NULL;
00116 }
00117 g_list_free (lot->splits);
00118
00119 lot->account = NULL;
00120 lot->is_closed = TRUE;
00121
00122 g_object_unref (lot);
00123 }
00124
00125 void
00126 gnc_lot_destroy (GNCLot *lot)
00127 {
00128 if (!lot) return;
00129
00130 gnc_lot_begin_edit(lot);
00131 qof_instance_set_destroying(lot, TRUE);
00132 gnc_lot_commit_edit(lot);
00133 }
00134
00135
00136
00137 void
00138 gnc_lot_begin_edit (GNCLot *lot)
00139 {
00140 qof_begin_edit(&lot->inst);
00141 }
00142
00143 static void commit_err (QofInstance *inst, QofBackendError errcode)
00144 {
00145 PERR ("Failed to commit: %d", errcode);
00146 }
00147
00148 static void lot_free(QofInstance* inst)
00149 {
00150 GNCLot* lot = GNC_LOT(inst);
00151
00152 gnc_lot_free(lot);
00153 }
00154
00155 static void noop (QofInstance *inst) {}
00156
00157 void
00158 gnc_lot_commit_edit (GNCLot *lot)
00159 {
00160 if (!qof_commit_edit (QOF_INSTANCE(lot))) return;
00161 qof_commit_edit_part2 (&lot->inst, commit_err, noop, lot_free);
00162 }
00163
00164
00165
00166 GNCLot *
00167 gnc_lot_lookup (const GUID *guid, QofBook *book)
00168 {
00169 QofCollection *col;
00170 if (!guid || !book) return NULL;
00171 col = qof_book_get_collection (book, GNC_ID_LOT);
00172 return (GNCLot *) qof_collection_lookup_entity (col, guid);
00173 }
00174
00175 QofBook *
00176 gnc_lot_get_book (GNCLot *lot)
00177 {
00178 return qof_instance_get_book(QOF_INSTANCE(lot));
00179 }
00180
00181
00182
00183 gboolean
00184 gnc_lot_is_closed (GNCLot *lot)
00185 {
00186 if (!lot) return TRUE;
00187 if (0 > lot->is_closed) gnc_lot_get_balance (lot);
00188 return lot->is_closed;
00189 }
00190
00191 Account *
00192 gnc_lot_get_account (const GNCLot *lot)
00193 {
00194 if (!lot) return NULL;
00195 return lot->account;
00196 }
00197
00198 KvpFrame *
00199 gnc_lot_get_slots (const GNCLot *lot)
00200 {
00201 return qof_instance_get_slots(QOF_INSTANCE(lot));
00202 }
00203
00204 SplitList *
00205 gnc_lot_get_split_list (const GNCLot *lot)
00206 {
00207 if (!lot) return NULL;
00208 return lot->splits;
00209 }
00210
00211 gint gnc_lot_count_splits (const GNCLot *lot)
00212 {
00213 if (!lot) return 0;
00214 return g_list_length (lot->splits);
00215 }
00216
00217
00218
00219
00220 const char *
00221 gnc_lot_get_title (const GNCLot *lot)
00222 {
00223 if (!lot) return NULL;
00224 return kvp_frame_get_string (lot->inst.kvp_data, "/title");
00225 }
00226
00227 const char *
00228 gnc_lot_get_notes (const GNCLot *lot)
00229 {
00230 if (!lot) return NULL;
00231 return kvp_frame_get_string (lot->inst.kvp_data, "/notes");
00232 }
00233
00234 void
00235 gnc_lot_set_title (GNCLot *lot, const char *str)
00236 {
00237 if (!lot) return;
00238 qof_begin_edit(QOF_INSTANCE(lot));
00239 qof_instance_set_dirty(QOF_INSTANCE(lot));
00240 kvp_frame_set_str (lot->inst.kvp_data, "/title", str);
00241 gnc_lot_commit_edit(lot);
00242 }
00243
00244 void
00245 gnc_lot_set_notes (GNCLot *lot, const char *str)
00246 {
00247 if (!lot) return;
00248 gnc_lot_begin_edit(lot);
00249 qof_instance_set_dirty(QOF_INSTANCE(lot));
00250 kvp_frame_set_str (lot->inst.kvp_data, "/notes", str);
00251 gnc_lot_commit_edit(lot);
00252 }
00253
00254
00255
00256 gnc_numeric
00257 gnc_lot_get_balance (GNCLot *lot)
00258 {
00259 GList *node;
00260 gnc_numeric zero = gnc_numeric_zero();
00261 gnc_numeric baln = zero;
00262 if (!lot) return zero;
00263
00264 if (!lot->splits)
00265 {
00266 lot->is_closed = FALSE;
00267 return zero;
00268 }
00269
00270
00271
00272
00273 for (node=lot->splits; node; node=node->next)
00274 {
00275 Split *s = node->data;
00276 gnc_numeric amt = xaccSplitGetAmount (s);
00277 baln = gnc_numeric_add_fixed (baln, amt);
00278 }
00279
00280
00281 if (gnc_numeric_equal (baln, zero))
00282 {
00283 lot->is_closed = TRUE;
00284 }
00285 else
00286 {
00287 lot->is_closed = FALSE;
00288 }
00289
00290 return baln;
00291 }
00292
00293
00294
00295 void
00296 gnc_lot_get_balance_before (const GNCLot *lot, const Split *split,
00297 gnc_numeric *amount, gnc_numeric *value)
00298 {
00299 GList *node;
00300 gnc_numeric zero = gnc_numeric_zero();
00301 gnc_numeric amt = zero;
00302 gnc_numeric val = zero;
00303
00304 if (lot && lot->splits)
00305 {
00306 Transaction *ta, *tb;
00307 const Split *target;
00308
00309
00310
00311 target = xaccSplitGetGainsSourceSplit (split);
00312 if (target == NULL)
00313 target = split;
00314 tb = xaccSplitGetParent (target);
00315 for (node = lot->splits; node; node = node->next)
00316 {
00317 Split *s = node->data;
00318 Split *source = xaccSplitGetGainsSourceSplit (s);
00319 if (source == NULL)
00320 source = s;
00321 ta = xaccSplitGetParent (source);
00322 if ((ta == tb && source != target) ||
00323 xaccTransOrder (ta, tb) < 0)
00324 {
00325 gnc_numeric tmpval = xaccSplitGetAmount (s);
00326 amt = gnc_numeric_add_fixed (amt, tmpval);
00327 tmpval = xaccSplitGetValue (s);
00328 val = gnc_numeric_add_fixed (val, tmpval);
00329 }
00330 }
00331 }
00332
00333 *amount = amt;
00334 *value = val;
00335 }
00336
00337
00338
00339 void
00340 gnc_lot_add_split (GNCLot *lot, Split *split)
00341 {
00342 Account * acc;
00343 if (!lot || !split) return;
00344
00345 ENTER ("(lot=%p, split=%p) %s amt=%s val=%s", lot, split,
00346 gnc_lot_get_title (lot),
00347 gnc_num_dbg_to_string (split->amount),
00348 gnc_num_dbg_to_string (split->value));
00349 gnc_lot_begin_edit(lot);
00350 acc = xaccSplitGetAccount (split);
00351 qof_instance_set_dirty(QOF_INSTANCE(lot));
00352 if (NULL == lot->account)
00353 {
00354 xaccAccountInsertLot (acc, lot);
00355 }
00356 else if (lot->account != acc)
00357 {
00358 PERR ("splits from different accounts cannot "
00359 "be added to this lot!\n"
00360 "\tlot account=\'%s\', split account=\'%s\'\n",
00361 xaccAccountGetName(lot->account), xaccAccountGetName (acc));
00362 gnc_lot_commit_edit(lot);
00363 LEAVE("different accounts");
00364 return;
00365 }
00366
00367 if (lot == split->lot) {
00368 gnc_lot_commit_edit(lot);
00369 LEAVE("already in lot");
00370 return;
00371 }
00372 if (split->lot)
00373 {
00374 gnc_lot_remove_split (split->lot, split);
00375 }
00376 xaccSplitSetLot(split, lot);
00377
00378 lot->splits = g_list_append (lot->splits, split);
00379
00380
00381 lot->is_closed = -1;
00382 gnc_lot_commit_edit(lot);
00383
00384 qof_event_gen (&lot->inst, QOF_EVENT_MODIFY, NULL);
00385 LEAVE("added to lot");
00386 }
00387
00388 void
00389 gnc_lot_remove_split (GNCLot *lot, Split *split)
00390 {
00391 if (!lot || !split) return;
00392
00393 ENTER ("(lot=%p, split=%p)", lot, split);
00394 gnc_lot_begin_edit(lot);
00395 qof_instance_set_dirty(QOF_INSTANCE(lot));
00396 lot->splits = g_list_remove (lot->splits, split);
00397 xaccSplitSetLot(split, NULL);
00398 lot->is_closed = -1;
00399
00400 if (NULL == lot->splits)
00401 {
00402 xaccAccountRemoveLot (lot->account, lot);
00403 lot->account = NULL;
00404 }
00405 gnc_lot_commit_edit(lot);
00406 qof_event_gen (&lot->inst, QOF_EVENT_MODIFY, NULL);
00407 }
00408
00409
00410
00411
00412 Split *
00413 gnc_lot_get_earliest_split (GNCLot *lot)
00414 {
00415 if (! lot->splits)
00416 return NULL;
00417 lot->splits = g_list_sort (lot->splits, (GCompareFunc) xaccSplitOrderDateOnly);
00418 return lot->splits->data;
00419 }
00420
00421 Split *
00422 gnc_lot_get_latest_split (GNCLot *lot)
00423 {
00424 SplitList *node;
00425
00426 if (! lot->splits)
00427 return NULL;
00428 lot->splits = g_list_sort (lot->splits, (GCompareFunc) xaccSplitOrderDateOnly);
00429
00430 for (node = lot->splits; node->next; node = node->next)
00431 ;
00432
00433 return node->data;
00434 }
00435
00436
00437
00438 static QofObject gncLotDesc =
00439 {
00440 interface_version: QOF_OBJECT_VERSION,
00441 e_type: GNC_ID_LOT,
00442 type_label: "Lot",
00443 create: (gpointer)gnc_lot_new,
00444 book_begin: NULL,
00445 book_end: NULL,
00446 is_dirty: qof_collection_is_dirty,
00447 mark_clean: qof_collection_mark_clean,
00448 foreach: qof_collection_foreach,
00449 printable: NULL,
00450 version_cmp: (int (*)(gpointer,gpointer))qof_instance_version_cmp,
00451 };
00452
00453
00454 gboolean gnc_lot_register (void)
00455 {
00456 static const QofParam params[] = {
00457 { LOT_TITLE, QOF_TYPE_STRING,
00458 (QofAccessFunc) gnc_lot_get_title,
00459 (QofSetterFunc) gnc_lot_set_title },
00460 { LOT_NOTES, QOF_TYPE_STRING,
00461 (QofAccessFunc) gnc_lot_get_notes,
00462 (QofSetterFunc) gnc_lot_set_notes },
00463 { QOF_PARAM_GUID, QOF_TYPE_GUID,
00464 (QofAccessFunc) qof_entity_get_guid, NULL },
00465 { QOF_PARAM_BOOK, QOF_ID_BOOK,
00466 (QofAccessFunc) gnc_lot_get_book, NULL },
00467 { LOT_IS_CLOSED, QOF_TYPE_BOOLEAN,
00468 (QofAccessFunc) gnc_lot_is_closed, NULL },
00469 { LOT_BALANCE, QOF_TYPE_NUMERIC,
00470 (QofAccessFunc) gnc_lot_get_balance, NULL },
00471 { NULL },
00472 };
00473
00474 qof_class_register (GNC_ID_LOT, NULL, params);
00475 return qof_object_register(&gncLotDesc);
00476 }
00477
00478 GNCLot * gnc_lot_make_default (Account *acc)
00479 {
00480 GNCLot * lot;
00481 gint64 id;
00482 char buff[200];
00483
00484 lot = gnc_lot_new (qof_instance_get_book(acc));
00485
00486
00487 id = kvp_frame_get_gint64 (xaccAccountGetSlots (acc), "/lot-mgmt/next-id");
00488 snprintf (buff, 200, ("%s %" G_GINT64_FORMAT), _("Lot"), id);
00489 kvp_frame_set_str (gnc_lot_get_slots (lot), "/title", buff);
00490 id ++;
00491 kvp_frame_set_gint64 (xaccAccountGetSlots (acc), "/lot-mgmt/next-id", id);
00492
00493 return lot;
00494 }
00495
00496