static void gncOwnerOffsetLots (GNCLot *from_lot, GNCLot *to_lot, const GncOwner *owner) { gnc_numeric target_offset; Split *split; /* from lot should not be a document lot because we're removing a split from there ! */ if (gncInvoiceGetInvoiceFromLot (from_lot)) { PWARN ("from_lot %p is a document lot. That is not allowed in gncOwnerOffsetLots", from_lot); return; } /* Get best matching split from from_lot to offset to_lot */ target_offset = gnc_lot_get_balance (to_lot); if (gnc_numeric_zero_p (target_offset)) return; // to_lot is already balanced, nothing more to do split = gncOwnerFindOffsettingSplit (from_lot, target_offset); if (!split) return; // No suitable offsetting split found, nothing more to do /* If the offsetting split is bigger than the amount needed to balance * to_lot, reduce the split so its reduced value closes to_lot exactly. * Note the negation in the reduction function. The split must be of * opposite sign of to_lot's balance in order to be able to close it. */ if (gnc_numeric_compare (gnc_numeric_abs (xaccSplitGetValue (split)), gnc_numeric_abs (target_offset)) > 0) gncOwnerReduceSplitTo (split, gnc_numeric_neg (target_offset)); /* Move the reduced split from from_lot to to_lot */ gnc_lot_add_split (to_lot, split); }
static gboolean scrub_other_link (GNCLot *from_lot, Split *ll_from_split, GNCLot *to_lot, Split *ll_to_split) { Split *real_from_split; // This refers to the split in the payment lot representing the payment itself gboolean modified = FALSE; gnc_numeric real_from_val; gnc_numeric from_val = xaccSplitGetValue (ll_from_split); gnc_numeric to_val = xaccSplitGetValue (ll_to_split); Transaction *ll_txn = xaccSplitGetParent (ll_to_split); // Per iteration we can only scrub at most min (val-doc-split, val-pay-split) // So set the ceiling for finding a potential offsetting split in the lot if (gnc_numeric_compare (gnc_numeric_abs (from_val), gnc_numeric_abs (to_val)) >= 0) from_val = gnc_numeric_neg (to_val); // Next we have to find the original payment split so we can // add (part of) it to the document lot real_from_split = gncOwnerFindOffsettingSplit (from_lot, from_val); if (!real_from_split) return FALSE; // No usable split in the payment lot // We now have found 3 splits involved in the scrub action: // 2 lot link splits which we want to reduce // 1 other split to move into the original lot instead of the lot link split // As said only value of the split can be offset. // So split the bigger ones in two if needed and continue with equal valued splits only // The remainder is added to the lot link transaction and the lot to keep everything balanced // and will be processed in a future iteration modified = reduce_biggest_split (ll_from_split, ll_to_split); modified |= reduce_biggest_split (real_from_split, ll_from_split); modified |= reduce_biggest_split (ll_from_split, ll_to_split); // At this point ll_to_split and real_from_split should have the same value // If not, flag a warning and skip to the next iteration to_val = xaccSplitGetValue (ll_to_split); from_val = xaccSplitGetValue (ll_from_split); real_from_val = xaccSplitGetValue (real_from_split); if (!gnc_numeric_equal (real_from_val, to_val)) { // This is unexpected - write a warning message and skip this split PWARN("real_from_val (%s) and to_val (%s) differ. " "This is unexpected! Skip scrubbing of real_from_split %p against ll_to_split %p.", gnc_numeric_to_string (real_from_val), // gnc_numeric_denom (real_from_val), gnc_numeric_to_string (to_val), // gnc_numeric_denom (to_val), real_from_split, ll_to_split); return modified; } // Now do the actual split dance // - move real payment split to doc lot // - delete both lot link splits from the lot link transaction gnc_lot_add_split (to_lot, real_from_split); xaccTransBeginEdit (ll_txn); xaccSplitDestroy (ll_to_split); xaccSplitDestroy (ll_from_split); xaccTransCommitEdit (ll_txn); // Cleanup the lots xaccScrubMergeLotSubSplits (to_lot, FALSE); xaccScrubMergeLotSubSplits (from_lot, FALSE); return TRUE; // We did change splits/transactions/lots... }