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);
|
GDate txn_date = xaccTransGetDatePostedGDate (txn);
|
||||||
gnc_ui_payment_window_set_date(pw, &txn_date);
|
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)
|
if (payment_split)
|
||||||
gnc_ui_payment_window_set_xferaccount(pw, xaccSplitGetAccount(payment_split));
|
gnc_ui_payment_window_set_xferaccount(pw, xaccSplitGetAccount(payment_split));
|
||||||
return pw;
|
return pw;
|
||||||
|
|||||||
@@ -756,10 +756,12 @@ gncOwnerCreatePaymentLotSecs (const GncOwner *owner, Transaction **preset_txn,
|
|||||||
QofBook *book;
|
QofBook *book;
|
||||||
Split *split;
|
Split *split;
|
||||||
const char *name;
|
const char *name;
|
||||||
gnc_commodity *commodity;
|
gnc_commodity *post_comm, *xfer_comm;
|
||||||
Split *xfer_split = NULL;
|
Split *xfer_split = NULL;
|
||||||
Transaction *txn = NULL;
|
Transaction *txn = NULL;
|
||||||
GNCLot *payment_lot;
|
GNCLot *payment_lot;
|
||||||
|
gnc_numeric xfer_amount = gnc_numeric_zero();
|
||||||
|
gnc_numeric txn_value = gnc_numeric_zero();
|
||||||
|
|
||||||
/* Verify our arguments */
|
/* Verify our arguments */
|
||||||
if (!owner || !posted_acc || !xfer_acc) return NULL;
|
if (!owner || !posted_acc || !xfer_acc) return NULL;
|
||||||
@@ -768,7 +770,9 @@ gncOwnerCreatePaymentLotSecs (const GncOwner *owner, Transaction **preset_txn,
|
|||||||
/* Compute the ancillary data */
|
/* Compute the ancillary data */
|
||||||
book = gnc_account_get_book (posted_acc);
|
book = gnc_account_get_book (posted_acc);
|
||||||
name = gncOwnerGetName (gncOwnerGetEndOwner ((GncOwner*)owner));
|
name = gncOwnerGetName (gncOwnerGetEndOwner ((GncOwner*)owner));
|
||||||
commodity = gncOwnerGetCurrency (owner);
|
post_comm = xaccAccountGetCommodity (posted_acc);
|
||||||
|
xfer_comm = xaccAccountGetCommodity (xfer_acc);
|
||||||
|
|
||||||
// reverse = use_reversed_payment_amounts(owner);
|
// reverse = use_reversed_payment_amounts(owner);
|
||||||
|
|
||||||
if (preset_txn && *preset_txn)
|
if (preset_txn && *preset_txn)
|
||||||
@@ -776,110 +780,90 @@ gncOwnerCreatePaymentLotSecs (const GncOwner *owner, Transaction **preset_txn,
|
|||||||
|
|
||||||
if (txn)
|
if (txn)
|
||||||
{
|
{
|
||||||
xaccTransSetDescription (txn, name ? name : "");
|
int i = 0;
|
||||||
|
|
||||||
/* Pre-existing transaction was specified. We completely clear it,
|
/* Pre-existing transaction was specified. We completely clear it,
|
||||||
* except for the split in the transfer account, unless the
|
* except for a pre-existing transfer split. We're very conservative
|
||||||
* transaction can't be reused (wrong currency, wrong transfer account).
|
* in preserving that one as it may have been reconciled already. */
|
||||||
* In that case, the transaction is simply removed and an new
|
|
||||||
* one created. */
|
|
||||||
|
|
||||||
xfer_split = xaccTransFindSplitByAccount(txn, xfer_acc);
|
xfer_split = xaccTransFindSplitByAccount(txn, xfer_acc);
|
||||||
|
xaccTransBeginEdit (txn);
|
||||||
if (xaccTransGetCurrency(txn) != gncOwnerGetCurrency (owner))
|
while (i < xaccTransCountSplits(txn))
|
||||||
{
|
{
|
||||||
PINFO("Uh oh, mismatching currency/commodity between selected transaction and owner. We fall back to manual creation of a new transaction.");
|
Split *split = xaccTransGetSplit (txn, i);
|
||||||
xfer_split = NULL;
|
if (split == xfer_split)
|
||||||
}
|
++i;
|
||||||
|
else
|
||||||
if (!xfer_split)
|
xaccSplitDestroy(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.*/
|
|
||||||
}
|
}
|
||||||
|
/* Note: don't commit transaction now - that would insert an imbalance split.*/
|
||||||
}
|
}
|
||||||
|
else
|
||||||
/* Create the transaction if we don't have one yet */
|
|
||||||
if (!txn)
|
|
||||||
{
|
{
|
||||||
txn = xaccMallocTransaction (book);
|
txn = xaccMallocTransaction (book);
|
||||||
xaccTransBeginEdit (txn);
|
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 */
|
/* Insert a split for the transfer account if we don't have one yet */
|
||||||
if (!xfer_split)
|
if (!xfer_split)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Set up the transaction */
|
|
||||||
xaccTransSetDescription (txn, name ? name : "");
|
|
||||||
/* set per book option */
|
|
||||||
xaccTransSetCurrency (txn, commodity);
|
|
||||||
|
|
||||||
|
|
||||||
/* The split for the transfer account */
|
/* The split for the transfer account */
|
||||||
split = xaccMallocSplit (book);
|
xfer_split = xaccMallocSplit (book);
|
||||||
xaccSplitSetMemo (split, memo);
|
xaccSplitSetMemo (xfer_split, memo);
|
||||||
/* set per book option */
|
/* set per book option */
|
||||||
gnc_set_num_action (NULL, split, num, _("Payment"));
|
gnc_set_num_action (NULL, xfer_split, num, _("Payment"));
|
||||||
xaccAccountBeginEdit (xfer_acc);
|
xaccAccountBeginEdit (xfer_acc);
|
||||||
xaccAccountInsertSplit (xfer_acc, split);
|
xaccAccountInsertSplit (xfer_acc, xfer_split);
|
||||||
xaccAccountCommitEdit (xfer_acc);
|
xaccAccountCommitEdit (xfer_acc);
|
||||||
xaccTransAppendSplit (txn, split);
|
xaccTransAppendSplit (txn, xfer_split);
|
||||||
|
|
||||||
if (gnc_commodity_equal(xaccAccountGetCommodity(xfer_acc), commodity))
|
xaccSplitSetAmount(xfer_split, xfer_amount); /* Payment in xfer account currency */
|
||||||
{
|
xaccSplitSetValue(xfer_split, txn_value); /* Payment in transaction currency */
|
||||||
xaccSplitSetBaseValue (split, amount, commodity);
|
}
|
||||||
}
|
/* For a pre-existing xfer split, let's check if the amount and value
|
||||||
else
|
* have changed. If so, update them and unreconcile. */
|
||||||
{
|
else if (!gnc_numeric_equal (xaccSplitGetAmount (xfer_split), xfer_amount) ||
|
||||||
/* This will be a multi-currency transaction. The amount passed to this
|
!gnc_numeric_equal (xaccSplitGetValue (xfer_split), txn_value))
|
||||||
* 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
|
xaccSplitSetAmount (xfer_split, xfer_amount);
|
||||||
* commodity.
|
xaccSplitSetValue (xfer_split, txn_value);
|
||||||
* exch is from post account to xfer account so that can be used directly
|
xaccSplitSetReconcile (xfer_split, NREC);
|
||||||
* 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 */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a split in the post account */
|
/* Add a split in the post account */
|
||||||
split = xaccMallocSplit (book);
|
split = xaccMallocSplit (book);
|
||||||
xaccSplitSetMemo (split, memo);
|
xaccSplitSetMemo (split, memo);
|
||||||
/* set per book option */
|
/* set per book option */
|
||||||
gnc_set_num_action (NULL, split, num, _("Payment"));
|
xaccSplitSetAction (split, _("Payment"));
|
||||||
xaccAccountBeginEdit (posted_acc);
|
xaccAccountBeginEdit (posted_acc);
|
||||||
xaccAccountInsertSplit (posted_acc, split);
|
xaccAccountInsertSplit (posted_acc, split);
|
||||||
xaccAccountCommitEdit (posted_acc);
|
xaccAccountCommitEdit (posted_acc);
|
||||||
xaccTransAppendSplit (txn, split);
|
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 */
|
/* Create a new lot for the payment */
|
||||||
payment_lot = gnc_lot_new (book);
|
payment_lot = gnc_lot_new (book);
|
||||||
@@ -887,7 +871,7 @@ gncOwnerCreatePaymentLotSecs (const GncOwner *owner, Transaction **preset_txn,
|
|||||||
gnc_lot_add_split (payment_lot, split);
|
gnc_lot_add_split (payment_lot, split);
|
||||||
|
|
||||||
/* Mark the transaction as a payment */
|
/* Mark the transaction as a payment */
|
||||||
gnc_set_num_action (txn, NULL, num, _("Payment"));
|
xaccTransSetNum (txn, num);
|
||||||
xaccTransSetTxnType (txn, TXN_TYPE_PAYMENT);
|
xaccTransSetTxnType (txn, TXN_TYPE_PAYMENT);
|
||||||
|
|
||||||
/* Set date for transaction */
|
/* Set date for transaction */
|
||||||
|
|||||||
Reference in New Issue
Block a user