mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Revisit invoice payment in multi-currency context
- Show proper amount in dialog when applying or editing an existing transaction as payment - Be more careful not to waste the existing payment split - If the user changed the payment amount while starting from an existing transaction unreconcile the changed payment split - Avoid needlessly changing transaction currency (only do so if the user chose a new transfer account and the old currency is neither the new transfer account's currency nor the post account's currency)
This commit is contained in:
@@ -1825,7 +1825,8 @@ PaymentWindow * gnc_ui_payment_new_with_txn (GtkWindow* parent, GncOwner *owner,
|
||||
GDate txn_date = xaccTransGetDatePostedGDate (txn);
|
||||
gnc_ui_payment_window_set_date(pw, &txn_date);
|
||||
}
|
||||
gnc_ui_payment_window_set_amount(pw, xaccSplitGetValue(payment_split));
|
||||
|
||||
gnc_ui_payment_window_set_amount(pw, xaccSplitConvertAmount (payment_split, post_acct));
|
||||
if (payment_split)
|
||||
gnc_ui_payment_window_set_xferaccount(pw, xaccSplitGetAccount(payment_split));
|
||||
return pw;
|
||||
|
||||
@@ -756,10 +756,12 @@ gncOwnerCreatePaymentLotSecs (const GncOwner *owner, Transaction **preset_txn,
|
||||
QofBook *book;
|
||||
Split *split;
|
||||
const char *name;
|
||||
gnc_commodity *commodity;
|
||||
gnc_commodity *post_comm, *xfer_comm;
|
||||
Split *xfer_split = NULL;
|
||||
Transaction *txn = NULL;
|
||||
GNCLot *payment_lot;
|
||||
gnc_numeric xfer_amount = gnc_numeric_zero();
|
||||
gnc_numeric txn_value = gnc_numeric_zero();
|
||||
|
||||
/* Verify our arguments */
|
||||
if (!owner || !posted_acc || !xfer_acc) return NULL;
|
||||
@@ -768,7 +770,9 @@ gncOwnerCreatePaymentLotSecs (const GncOwner *owner, Transaction **preset_txn,
|
||||
/* Compute the ancillary data */
|
||||
book = gnc_account_get_book (posted_acc);
|
||||
name = gncOwnerGetName (gncOwnerGetEndOwner ((GncOwner*)owner));
|
||||
commodity = gncOwnerGetCurrency (owner);
|
||||
post_comm = xaccAccountGetCommodity (posted_acc);
|
||||
xfer_comm = xaccAccountGetCommodity (xfer_acc);
|
||||
|
||||
// reverse = use_reversed_payment_amounts(owner);
|
||||
|
||||
if (preset_txn && *preset_txn)
|
||||
@@ -776,110 +780,90 @@ gncOwnerCreatePaymentLotSecs (const GncOwner *owner, Transaction **preset_txn,
|
||||
|
||||
if (txn)
|
||||
{
|
||||
xaccTransSetDescription (txn, name ? name : "");
|
||||
int i = 0;
|
||||
|
||||
/* Pre-existing transaction was specified. We completely clear it,
|
||||
* except for the split in the transfer account, unless the
|
||||
* transaction can't be reused (wrong currency, wrong transfer account).
|
||||
* In that case, the transaction is simply removed and an new
|
||||
* one created. */
|
||||
|
||||
* except for a pre-existing transfer split. We're very conservative
|
||||
* in preserving that one as it may have been reconciled already. */
|
||||
xfer_split = xaccTransFindSplitByAccount(txn, xfer_acc);
|
||||
|
||||
if (xaccTransGetCurrency(txn) != gncOwnerGetCurrency (owner))
|
||||
{
|
||||
PINFO("Uh oh, mismatching currency/commodity between selected transaction and owner. We fall back to manual creation of a new transaction.");
|
||||
xfer_split = NULL;
|
||||
}
|
||||
|
||||
if (!xfer_split)
|
||||
{
|
||||
PINFO("Huh? Asset account not found anymore. Fully deleting old txn and now creating a new one.");
|
||||
|
||||
xaccTransBeginEdit (txn);
|
||||
xaccTransDestroy (txn);
|
||||
xaccTransCommitEdit (txn);
|
||||
|
||||
txn = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = 0;
|
||||
xaccTransBeginEdit (txn);
|
||||
while (i < xaccTransCountSplits(txn))
|
||||
{
|
||||
Split *split = xaccTransGetSplit (txn, i);
|
||||
if (split == xfer_split)
|
||||
{
|
||||
gnc_set_num_action (NULL, split, num, _("Payment"));
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
xaccSplitDestroy(split);
|
||||
}
|
||||
}
|
||||
/* Note: don't commit transaction now - that would insert an imbalance split.*/
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the transaction if we don't have one yet */
|
||||
if (!txn)
|
||||
else
|
||||
{
|
||||
txn = xaccMallocTransaction (book);
|
||||
xaccTransBeginEdit (txn);
|
||||
}
|
||||
|
||||
/* Complete transaction setup */
|
||||
xaccTransSetDescription (txn, name ? name : "");
|
||||
if (!gnc_commodity_equal(xaccTransGetCurrency (txn), post_comm) &&
|
||||
!gnc_commodity_equal (xaccTransGetCurrency (txn), xfer_comm))
|
||||
xaccTransSetCurrency (txn, xfer_comm);
|
||||
|
||||
/* With all commodities involved known, define split amounts and txn value.
|
||||
* - post amount (amount passed in as parameter) is always in post_acct commodity,
|
||||
* - xfer amount requires conversion if the xfer account has a different
|
||||
* commodity than the post account.
|
||||
* - txn value requires conversion if the post account has a different
|
||||
* commodity than the transaction */
|
||||
if (gnc_commodity_equal(post_comm, xfer_comm))
|
||||
xfer_amount = amount;
|
||||
else
|
||||
xfer_amount = gnc_numeric_mul (amount, exch, GNC_DENOM_AUTO,
|
||||
GNC_HOW_RND_ROUND_HALF_UP);
|
||||
|
||||
if (gnc_commodity_equal(post_comm, xaccTransGetCurrency (txn)))
|
||||
txn_value = amount;
|
||||
else
|
||||
txn_value = gnc_numeric_mul (amount, exch, GNC_DENOM_AUTO,
|
||||
GNC_HOW_RND_ROUND_HALF_UP);
|
||||
|
||||
/* Insert a split for the transfer account if we don't have one yet */
|
||||
if (!xfer_split)
|
||||
{
|
||||
|
||||
/* Set up the transaction */
|
||||
xaccTransSetDescription (txn, name ? name : "");
|
||||
/* set per book option */
|
||||
xaccTransSetCurrency (txn, commodity);
|
||||
|
||||
|
||||
/* The split for the transfer account */
|
||||
split = xaccMallocSplit (book);
|
||||
xaccSplitSetMemo (split, memo);
|
||||
xfer_split = xaccMallocSplit (book);
|
||||
xaccSplitSetMemo (xfer_split, memo);
|
||||
/* set per book option */
|
||||
gnc_set_num_action (NULL, split, num, _("Payment"));
|
||||
gnc_set_num_action (NULL, xfer_split, num, _("Payment"));
|
||||
xaccAccountBeginEdit (xfer_acc);
|
||||
xaccAccountInsertSplit (xfer_acc, split);
|
||||
xaccAccountInsertSplit (xfer_acc, xfer_split);
|
||||
xaccAccountCommitEdit (xfer_acc);
|
||||
xaccTransAppendSplit (txn, split);
|
||||
xaccTransAppendSplit (txn, xfer_split);
|
||||
|
||||
if (gnc_commodity_equal(xaccAccountGetCommodity(xfer_acc), commodity))
|
||||
{
|
||||
xaccSplitSetBaseValue (split, amount, commodity);
|
||||
xaccSplitSetAmount(xfer_split, xfer_amount); /* Payment in xfer account currency */
|
||||
xaccSplitSetValue(xfer_split, txn_value); /* Payment in transaction currency */
|
||||
}
|
||||
else
|
||||
/* For a pre-existing xfer split, let's check if the amount and value
|
||||
* have changed. If so, update them and unreconcile. */
|
||||
else if (!gnc_numeric_equal (xaccSplitGetAmount (xfer_split), xfer_amount) ||
|
||||
!gnc_numeric_equal (xaccSplitGetValue (xfer_split), txn_value))
|
||||
{
|
||||
/* This will be a multi-currency transaction. The amount passed to this
|
||||
* function is in the owner commodity (also used by the post account).
|
||||
* For the xfer split we also need to value the payment in the xfer account's
|
||||
* commodity.
|
||||
* exch is from post account to xfer account so that can be used directly
|
||||
* to calculate the equivalent amount in the xfer account's commodity. */
|
||||
gnc_numeric xfer_amount = gnc_numeric_mul (amount, exch, GNC_DENOM_AUTO,
|
||||
GNC_HOW_RND_ROUND_HALF_UP);
|
||||
|
||||
xaccSplitSetAmount(split, xfer_amount); /* Payment in xfer account currency */
|
||||
xaccSplitSetValue(split, amount); /* Payment in transaction currency */
|
||||
}
|
||||
xaccSplitSetAmount (xfer_split, xfer_amount);
|
||||
xaccSplitSetValue (xfer_split, txn_value);
|
||||
xaccSplitSetReconcile (xfer_split, NREC);
|
||||
}
|
||||
|
||||
/* Add a split in the post account */
|
||||
split = xaccMallocSplit (book);
|
||||
xaccSplitSetMemo (split, memo);
|
||||
/* set per book option */
|
||||
gnc_set_num_action (NULL, split, num, _("Payment"));
|
||||
xaccSplitSetAction (split, _("Payment"));
|
||||
xaccAccountBeginEdit (posted_acc);
|
||||
xaccAccountInsertSplit (posted_acc, split);
|
||||
xaccAccountCommitEdit (posted_acc);
|
||||
xaccTransAppendSplit (txn, split);
|
||||
xaccSplitSetBaseValue (split, gnc_numeric_neg (amount), commodity);
|
||||
xaccSplitSetAmount (split, gnc_numeric_neg (amount));
|
||||
xaccSplitSetValue (split, gnc_numeric_neg (txn_value));
|
||||
|
||||
/* Create a new lot for the payment */
|
||||
payment_lot = gnc_lot_new (book);
|
||||
@@ -887,7 +871,7 @@ gncOwnerCreatePaymentLotSecs (const GncOwner *owner, Transaction **preset_txn,
|
||||
gnc_lot_add_split (payment_lot, split);
|
||||
|
||||
/* Mark the transaction as a payment */
|
||||
gnc_set_num_action (txn, NULL, num, _("Payment"));
|
||||
xaccTransSetNum (txn, num);
|
||||
xaccTransSetTxnType (txn, TXN_TYPE_PAYMENT);
|
||||
|
||||
/* Set date for transaction */
|
||||
|
||||
Reference in New Issue
Block a user