Example #1
0
static const gchar *
iter_to_string (GtkTreeIter *iter)
{
#ifdef G_THREADS_ENABLED
    static GPrivate gtmits_buffer_key = G_PRIVATE_INIT(g_free);
    gchar *string;

    string = g_private_get (&gtmits_buffer_key);
    if (string == NULL)
    {
        string = g_malloc(ITER_STRING_LEN + 1);
        g_private_set (&gtmits_buffer_key, string);
    }
#else
    static char string[ITER_STRING_LEN + 1];
#endif

    if (iter)
        snprintf(string, ITER_STRING_LEN,
                 "[stamp:%x data:%p (%s), %p, %d]",
                 iter->stamp, iter->user_data,
                 gncOwnerGetName ((GncOwner *) iter->user_data),
                 iter->user_data2, GPOINTER_TO_INT(iter->user_data3));
    else
        strcpy(string, "(null)");
    return string;
}
Example #2
0
/*
 * Retrieve the selected owner from an owner tree view.  The
 * owner tree must be in single selection mode.
 */
GncOwner *
gnc_tree_view_owner_get_selected_owner (GncTreeViewOwner *view)
{
    GtkTreeSelection *selection;
    GtkTreeModel *f_model, *s_model;
    GtkTreeIter iter, f_iter, s_iter;
    GncOwner *owner;
    GtkSelectionMode mode;

    ENTER("view %p", view);
    g_return_val_if_fail (GNC_IS_TREE_VIEW_OWNER (view), NULL);

    selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view));
    mode = gtk_tree_selection_get_mode(selection);
    if ((mode != GTK_SELECTION_SINGLE) && (mode != GTK_SELECTION_BROWSE))
    {
        return NULL;
    }
    if (!gtk_tree_selection_get_selected (selection, &s_model, &s_iter))
    {
        LEAVE("no owner, get_selected failed");
        return FALSE;
    }

    gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (s_model),
            &f_iter, &s_iter);

    f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
    gtk_tree_model_filter_convert_iter_to_child_iter (
        GTK_TREE_MODEL_FILTER (f_model), &iter, &f_iter);

    owner = iter.user_data;
    LEAVE("owner %p (%s)", owner, gncOwnerGetName (owner));
    return owner;
}
Example #3
0
static gboolean
gnc_tree_view_owner_get_iter_from_owner (GncTreeViewOwner *view,
        GncOwner *owner,
        GtkTreeIter *s_iter)
{
    GtkTreeModel *model, *f_model, *s_model;
    GtkTreeIter iter, f_iter;

    g_return_val_if_fail(GNC_IS_TREE_VIEW_OWNER(view), FALSE);
    g_return_val_if_fail(owner != NULL, FALSE);
    g_return_val_if_fail(s_iter != NULL, FALSE);

    ENTER("view %p, owner %p (%s)", view, owner, gncOwnerGetName(owner));

    /* Reach down to the real model and get an iter for this owner */
    s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
    f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
    model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
    if (!gnc_tree_model_owner_get_iter_from_owner (
                GNC_TREE_MODEL_OWNER(model), owner, &iter))
    {
        LEAVE("model_get_iter_from_owner failed");
        return FALSE;
    }

    /* convert back to a sort iter */
    gtk_tree_model_filter_convert_child_iter_to_iter (
        GTK_TREE_MODEL_FILTER(f_model), &f_iter, &iter);
    gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT(s_model),
            s_iter, &f_iter);
    LEAVE(" ");
    return TRUE;
}
Example #4
0
GncOwner *
gnc_tree_view_owner_get_owner_from_iter (GtkTreeModel *s_model,
        GtkTreeIter  *s_iter)
{
    GtkTreeModel *model, *f_model;
    GtkTreeIter iter, f_iter;
    GncOwner *owner;

    g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT(s_model), NULL);
    g_return_val_if_fail (s_iter != NULL, NULL);

    ENTER("model %p, iter %p", s_model, s_iter);

    gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT(s_model),
            &f_iter,
            s_iter);
    f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
    gtk_tree_model_filter_convert_iter_to_child_iter (
        GTK_TREE_MODEL_FILTER(f_model), &iter, &f_iter);
    model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
    owner = gnc_tree_model_owner_get_owner (
                GNC_TREE_MODEL_OWNER(model), &iter);
    LEAVE("owner %p (%s)", owner, gncOwnerGetName (owner));
    return owner;
}
Example #5
0
/** This function tells the owner tree view whether or not to filter
 *  out a particular owner.  Owners may be filtered if the user
 *  has decided not to display inactive owners, or if the
 *  user has requested that owners with a zero total not be shown.
 *
 *  @param owner The owner that is being evaluated.
 *
 *  @param user_data A pointer to the OwnerFilterDialog struct.
 *
 *  @return TRUE if the owner should be visible.  FALSE if the
 *  owner should be hidden. */
gboolean
gnc_plugin_page_owner_tree_filter_owners (GncOwner *owner,
        gpointer user_data)
{
    OwnerFilterDialog *fd = user_data;
    gnc_numeric total;

    ENTER("owner %p:%s", owner, gncOwnerGetName(owner));

    if (!fd->show_inactive && !gncOwnerGetActive (owner))
    {
        LEAVE(" hide: inactive");
        return FALSE;
    }

    if (!fd->show_zero_total)
    {
        /* FIXME I'm not aware of any functions to get an owner's "balance" yet.
         *       This should be implemented before this function does anything useful.
         *       The code below is copied from the tree-view-account source to serve
         *       as an example.
        total = gncOwnerGetBalanceInCurrency (owner, NULL, TRUE);
        */
        total = gnc_numeric_zero();
        if (gnc_numeric_zero_p(total))
        {
            LEAVE(" hide: zero balance");
            return FALSE;
        }
    }

    return TRUE;
}
Example #6
0
static gboolean
gnc_job_verify_ok (JobWindow *jw)
{
    const char *res;
    gchar *string;

    /* Check for valid name */
    res = gtk_entry_get_text (GTK_ENTRY (jw->name_entry));
    if (g_strcmp0 (res, "") == 0)
    {
        const char *message = _("The Job must be given a name.");
        gnc_error_dialog(jw->dialog, "%s", message);
        return FALSE;
    }

    /* Check for owner */
    gnc_owner_get_owner (jw->cust_edit, &(jw->owner));
    res = gncOwnerGetName (&(jw->owner));
    if (res == NULL || g_strcmp0 (res, "") == 0)
    {
        const char *message = _("You must choose an owner for this job.");
        gnc_error_dialog(jw->dialog, "%s", message);
        return FALSE;
    }

    /* Set a valid id if one was not created */
    res = gtk_entry_get_text (GTK_ENTRY (jw->id_entry));
    if (g_strcmp0 (res, "") == 0)
    {
        string = gncJobNextID(jw->book);
        gtk_entry_set_text (GTK_ENTRY (jw->id_entry), string);
        g_free(string);
    }

    /* Now save it off */
    {
        GncJob *job = jw_get_job (jw);
        if (job)
        {
            gnc_ui_to_job (jw, job);
        }
    }

    /* Ok, it's been saved... Change to an editor.. */
    jw->dialog_type = EDIT_JOB;

    return TRUE;
}
Example #7
0
/*
 * Retrieve the selected owner from an owner tree view.  The
 * owner tree must be in single selection mode.
 */
GncOwner *
gnc_tree_view_owner_get_owner_from_path (GncTreeViewOwner *view,
        GtkTreePath *s_path)
{
    GtkTreeModel *model, *f_model, *s_model;
    GtkTreePath *path, *f_path;
    GtkTreeIter iter;
    GncOwner *owner;

    ENTER("view %p", view);
    g_return_val_if_fail (GNC_IS_TREE_VIEW_OWNER (view), NULL);
    g_return_val_if_fail (s_path != NULL, NULL);

    s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
    f_path = gtk_tree_model_sort_convert_path_to_child_path (
                 GTK_TREE_MODEL_SORT (s_model), s_path);
    if (!f_path)
    {
        LEAVE("no filter path");
        return NULL;
    }

    f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
    path = gtk_tree_model_filter_convert_path_to_child_path (
               GTK_TREE_MODEL_FILTER (f_model), f_path);
    gtk_tree_path_free(f_path);
    if (!path)
    {
        LEAVE("no path");
        return NULL;
    }

    model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
    if (!gtk_tree_model_get_iter (model, &iter, path))
    {
        LEAVE("no iter");
        return NULL;
    }

    owner = iter.user_data;
    gtk_tree_path_free(path);
    LEAVE("owner %p (%s)", owner, gncOwnerGetName (owner));
    return owner;
}
Example #8
0
/** Save information about the selected row.  Its job is to write the
 *  full owner name of the row out to the state file.
 *
 *  @param view A pointer to the GtkTreeView embedded in an
 *  owner tree page.
 *
 *  @param path A pointer to a particular entry in the tree.
 *
 *  @param data A pointer to a data structure holding the information
 *  related to the state file. */
static void
tree_save_selected_row (GncTreeViewOwner *view,
                        gpointer user_data)
{
    GncOwner *owner;
    GncOwnerType owner_type;
    bar_t *bar = user_data;
    const gchar *owner_name;

    owner = gnc_tree_view_owner_get_selected_owner(view);
    if (owner == NULL)
        return;

    owner_name = gncOwnerGetName (owner);
    if (owner_name == NULL)
        return;

    g_key_file_set_string(bar->key_file, bar->group_name, OWNER_SELECTED_LABEL,
                          owner_name);
}
Example #9
0
static GtkTreePath *
gnc_tree_view_owner_get_path_from_owner (GncTreeViewOwner *view,
        GncOwner *owner)
{
    GtkTreeModel *model, *f_model, *s_model;
    GtkTreePath *path, *f_path, *s_path;

    ENTER("view %p, owner %p (%s)", view, owner, gncOwnerGetName(owner));

    if (owner == NULL)
    {
        LEAVE("no owner");
        return NULL;
    }

    /* Reach down to the real model and get a path for this owner */
    s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
    f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
    model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
    path = gnc_tree_model_owner_get_path_from_owner (GNC_TREE_MODEL_OWNER(model), owner);
    if (path == NULL)
    {
        LEAVE("no path");
        return NULL;
    }

    /* convert back to a filtered path */
    f_path = gtk_tree_model_filter_convert_child_path_to_path (GTK_TREE_MODEL_FILTER (f_model), path);
    gtk_tree_path_free(path);
    if (!f_path)
    {
        LEAVE("no filter path");
        return NULL;
    }

    /* convert back to a sorted path */
    s_path = gtk_tree_model_sort_convert_child_path_to_path (GTK_TREE_MODEL_SORT (s_model), f_path);
    gtk_tree_path_free(f_path);
    debug_path(LEAVE, s_path);
    return s_path;
}
Example #10
0
/** This function is the handler for all event messages from the
 *  engine.  Its purpose is to update the owner tree model any time
 *  an owner is added to the engine or deleted from the engine.
 *  This change to the model is then propagated to any/all overlying
 *  filters and views.  This function listens to the ADD, REMOVE, and
 *  DESTROY events.
 *
 *  @internal
 *
 *  @warning There is a "Catch 22" situation here.
 *  gtk_tree_model_row_deleted() can't be called until after the item
 *  has been deleted from the real model (which is the engine's
 *  owner tree for us), but once the owner has been deleted from
 *  the engine we have no way to determine the path to pass to
 *  row_deleted().  This is a PITA, but the only other choice is to
 *  have this model mirror the engine's owners instead of
 *  referencing them directly.
 *
 *  @param entity The guid of the affected item.
 *
 *  @param type The type of the affected item.  This function only
 *  cares about items of type "owner".
 *
 *  @param event type The type of the event. This function only cares
 *  about items of type ADD, REMOVE, MODIFY, and DESTROY.
 *
 *  @param user_data A pointer to the owner tree model.
 */
static void
gnc_tree_model_owner_event_handler (QofInstance *entity,
                                    QofEventId event_type,
                                    GncTreeModelOwner *model,
                                    GncEventData *ed)
{
    GncTreeModelOwnerPrivate *priv;
    GtkTreePath *path = NULL;
    GtkTreeIter iter;
    GncOwner owner;

    g_return_if_fail(model);         /* Required */

    if (!GNC_IS_OWNER(entity))
        return;

    ENTER("entity %p of type %d, model %p, event_data %p",
          entity, event_type, model, ed);
    priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);

    qofOwnerSetEntity (&owner, entity);
    if (gncOwnerGetType(&owner) != priv->owner_type)
    {
        LEAVE("model type and owner type differ");
        return;
    }

    if (qof_instance_get_book (entity) != priv->book)
    {
        LEAVE("not in this book");
        return;
    }

    /* What to do, that to do. */
    switch (event_type)
    {
    case QOF_EVENT_ADD:
        /* Tell the filters/views where the new owner was added. */
        DEBUG("add owner %p (%s)", &owner, gncOwnerGetName(&owner));
        /* First update our copy of the owner list. This isn't done automatically */
        priv->owner_list = gncBusinessGetOwnerList (priv->book,
                           gncOwnerTypeToQofIdType(priv->owner_type), TRUE);
        increment_stamp(model);
        if (!gnc_tree_model_owner_get_iter_from_owner (model, &owner, &iter))
        {
            LEAVE("can't generate iter");
            break;
        }
        path = gnc_tree_model_owner_get_path(GTK_TREE_MODEL(model), &iter);
        if (!path)
        {
            DEBUG("can't generate path");
            break;
        }
        gtk_tree_model_row_inserted (GTK_TREE_MODEL(model), path, &iter);
        break;

    case QOF_EVENT_REMOVE:
        if (!ed) /* Required for a remove. */
            break;
        DEBUG("remove owner %d (%s) from owner_list %p", ed->idx,
              gncOwnerGetName(&owner), priv->owner_list);
        path = gtk_tree_path_new();
        if (!path)
        {
            DEBUG("can't generate path");
            break;
        }
        increment_stamp(model);
        gtk_tree_path_append_index (path, ed->idx);
        gtk_tree_model_row_deleted (GTK_TREE_MODEL(model), path);
        break;

    case QOF_EVENT_MODIFY:
        DEBUG("modify  owner %p (%s)", &owner, gncOwnerGetName(&owner));
        if (!gnc_tree_model_owner_get_iter_from_owner (model, &owner, &iter))
        {
            LEAVE("can't generate iter");
            return;
        }
        path = gnc_tree_model_owner_get_path(GTK_TREE_MODEL(model), &iter);
        if (!path)
        {
            DEBUG("can't generate path");
            break;
        }
        gtk_tree_model_row_changed(GTK_TREE_MODEL(model), path, &iter);
        break;

    default:
        LEAVE("unknown event type");
        return;
    }

    if (path)
        gtk_tree_path_free(path);
    LEAVE(" ");
    return;
}
Example #11
0
static void
gnc_tree_model_owner_get_value (GtkTreeModel *tree_model,
                                GtkTreeIter *iter,
                                int column,
                                GValue *value)
{
    GncTreeModelOwner *model = GNC_TREE_MODEL_OWNER (tree_model);
    GncOwner *owner;
    gboolean negative; /* used to set "deficit style" also known as red numbers */
    gchar *string = NULL;

    g_return_if_fail (GNC_IS_TREE_MODEL_OWNER (model));
    g_return_if_fail (iter != NULL);
    g_return_if_fail (iter->user_data != NULL);
    g_return_if_fail (iter->stamp == model->stamp);

    ENTER("model %p, iter %s, col %d", tree_model,
          iter_to_string(iter), column);

    owner = (GncOwner *) iter->user_data;

    switch (column)
    {
    case GNC_TREE_MODEL_OWNER_COL_NAME:
        g_value_init (value, G_TYPE_STRING);
        g_value_set_string (value, gncOwnerGetName (owner));
        break;
    case GNC_TREE_MODEL_OWNER_COL_TYPE:
        g_value_init (value, G_TYPE_STRING);
        g_value_set_string (value,
                            gncOwnerTypeToQofIdType (gncOwnerGetType (owner)));
        break;
    case GNC_TREE_MODEL_OWNER_COL_ID:
        g_value_init (value, G_TYPE_STRING);
        g_value_set_string (value, gncOwnerGetID (owner));
        break;
    case GNC_TREE_MODEL_OWNER_COL_CURRENCY:
        g_value_init (value, G_TYPE_STRING);
        g_value_set_string (value,
                            gnc_commodity_get_fullname(gncOwnerGetCurrency (owner)));
        break;
    case GNC_TREE_MODEL_OWNER_COL_ADDRESS_NAME:
        g_value_init (value, G_TYPE_STRING);
        string = g_strdup (gncAddressGetName (gncOwnerGetAddr (owner)));
        if (string)
            g_value_take_string (value, string);
        else
            g_value_set_static_string (value, "");
        break;
    case GNC_TREE_MODEL_OWNER_COL_ADDRESS_1:
        g_value_init (value, G_TYPE_STRING);
        string = g_strdup (gncAddressGetAddr1 (gncOwnerGetAddr (owner)));
        if (string)
            g_value_take_string (value, string);
        else
            g_value_set_static_string (value, "");
        break;
    case GNC_TREE_MODEL_OWNER_COL_ADDRESS_2:
        g_value_init (value, G_TYPE_STRING);
        string = g_strdup (gncAddressGetAddr2 (gncOwnerGetAddr (owner)));
        if (string)
            g_value_take_string (value, string);
        else
            g_value_set_static_string (value, "");
        break;
    case GNC_TREE_MODEL_OWNER_COL_ADDRESS_3:
        g_value_init (value, G_TYPE_STRING);
        string = g_strdup (gncAddressGetAddr3 (gncOwnerGetAddr (owner)));
        if (string)
            g_value_take_string (value, string);
        else
            g_value_set_static_string (value, "");
        break;
    case GNC_TREE_MODEL_OWNER_COL_ADDRESS_4:
        g_value_init (value, G_TYPE_STRING);
        string = g_strdup (gncAddressGetAddr4 (gncOwnerGetAddr (owner)));
        if (string)
            g_value_take_string (value, string);
        else
            g_value_set_static_string (value, "");
        break;
    case GNC_TREE_MODEL_OWNER_COL_PHONE:
        g_value_init (value, G_TYPE_STRING);
        string = g_strdup (gncAddressGetPhone (gncOwnerGetAddr (owner)));
        if (string)
            g_value_take_string (value, string);
        else
            g_value_set_static_string (value, "");
        break;
    case GNC_TREE_MODEL_OWNER_COL_FAX:
        g_value_init (value, G_TYPE_STRING);
        string = g_strdup (gncAddressGetFax (gncOwnerGetAddr (owner)));
        if (string)
            g_value_take_string (value, string);
        else
            g_value_set_static_string (value, "");
        break;
    case GNC_TREE_MODEL_OWNER_COL_EMAIL:
        g_value_init (value, G_TYPE_STRING);
        string = g_strdup (gncAddressGetEmail (gncOwnerGetAddr (owner)));
        if (string)
            g_value_take_string (value, string);
        else
            g_value_set_static_string (value, "");
        break;

    case GNC_TREE_MODEL_OWNER_COL_BALANCE:
        g_value_init (value, G_TYPE_STRING);
        string = gnc_ui_owner_get_print_balance(owner, &negative);
        g_value_take_string (value, string);
        break;

    case GNC_TREE_MODEL_OWNER_COL_BALANCE_REPORT:
        g_value_init (value, G_TYPE_STRING);
        string = gnc_ui_owner_get_print_report_balance(owner, &negative);
        g_value_take_string (value, string);
        break;
    case GNC_TREE_MODEL_OWNER_COL_COLOR_BALANCE:
        g_value_init (value, G_TYPE_STRING);
        string = gnc_ui_owner_get_print_balance(owner, &negative);
        gnc_tree_model_owner_set_color(model, negative, value);
        g_free(string);
        break;

    case GNC_TREE_MODEL_OWNER_COL_NOTES:
        g_value_init (value, G_TYPE_STRING);
        switch (gncOwnerGetType (owner))
        {
        case GNC_OWNER_NONE:
        case GNC_OWNER_UNDEFINED:
        case GNC_OWNER_EMPLOYEE:
        case GNC_OWNER_JOB:
        default:
            g_value_set_static_string (value, "");
            break;
        case GNC_OWNER_VENDOR:
            g_value_set_string (value, gncVendorGetNotes (gncOwnerGetVendor (owner)));
            break;
        case GNC_OWNER_CUSTOMER:
            g_value_set_string (value, gncCustomerGetNotes (gncOwnerGetCustomer (owner)));
            break;
        }
        break;

    case GNC_TREE_MODEL_OWNER_COL_ACTIVE:
        g_value_init (value, G_TYPE_BOOLEAN);
        g_value_set_boolean (value, gncOwnerGetActive (owner));
        break;

    default:
        g_assert_not_reached ();
    }
    LEAVE(" ");
}
Example #12
0
void gncOwnerAutoApplyPaymentsWithLots (const GncOwner *owner, GList *lots)
{
    GList *base_iter;

    /* General note: in the code below the term "payment" can
     * both mean a true payment or a document of
     * the opposite sign (invoice vs credit note) relative to
     * the lot being processed. In general this function will
     * perform a balancing action on a set of lots, so you
     * will also find frequent references to balancing instead. */

    /* Payments can only be applied when at least an owner
     * and a list of lots to use are given */
    if (!owner) return;
    if (!lots) return;

    for (base_iter = lots; base_iter; base_iter = base_iter->next)
    {
        GNCLot *base_lot = base_iter->data;
        QofBook *book;
        Account *acct;
        const gchar *name;
        GList *lot_list, *lot_iter;
        Transaction *txn = NULL;
        gnc_numeric base_lot_bal, val_to_pay, val_paid = { 0, 1 };
        gboolean base_bal_is_pos;
        const gchar *action, *memo;

        /* Only attempt to apply payments to open lots.
         * Note that due to the iterative nature of this function lots
         * in the list may become closed before they are evaluated as
         * base lot, so we should check this for each lot. */
        base_lot_bal = gnc_lot_get_balance (base_lot);
        if (gnc_numeric_zero_p (base_lot_bal))
            continue;

        book = gnc_lot_get_book (base_lot);
        acct = gnc_lot_get_account (base_lot);
        name = gncOwnerGetName (gncOwnerGetEndOwner (owner));
        lot_list = base_iter->next;

        /* Strings used when creating splits later on. */
        action = _("Lot Link");
        memo   = _("Internal link between invoice and payment lots");

        /* Note: to balance the lot the payment to assign
         * must have the opposite sign of the existing lot balance */
        val_to_pay = gnc_numeric_neg (base_lot_bal);
        base_bal_is_pos = gnc_numeric_positive_p (base_lot_bal);


        /* Create splits in a linking transaction between lots until
         * - either the invoice lot is balanced
         * - or there are no more balancing lots.
         */
        for (lot_iter = lot_list; lot_iter; lot_iter = lot_iter->next)
        {
            gnc_numeric payment_lot_balance;
            Split *split;
            Account *bal_acct;
            gnc_numeric  split_amt;

            GNCLot *balancing_lot = lot_iter->data;

            /* Only attempt to use open lots to balance the base lot.
             * Note that due to the iterative nature of this function lots
             * in the list may become closed before they are evaluated as
             * base lot, so we should check this for each lot. */
            if (gnc_lot_is_closed (balancing_lot))
                continue;

            /* Balancing transactions for invoice/payments can only happen
             * in the same account. */
            bal_acct = gnc_lot_get_account (balancing_lot);
            if (acct != bal_acct)
                continue;

            payment_lot_balance = gnc_lot_get_balance (balancing_lot);

            /* Only attempt to balance if the base lot and balancing lot are
             * of the opposite sign. (Otherwise we would increase the balance
             * of the lot - Duh */
            if (base_bal_is_pos == gnc_numeric_positive_p (payment_lot_balance))
                continue;

            /*
             * If there is less to pay than there's open in the lot; we're done -- apply the base_lot_vale.
             * Note that payment_value and balance are opposite in sign, so we have to compare absolute values here
             *
             * Otherwise, apply the balance, subtract that from the payment_value,
             * and move on to the next one.
             */
            if (gnc_numeric_compare (gnc_numeric_abs (val_to_pay), gnc_numeric_abs (payment_lot_balance)) <= 0)
            {
                /* abs(val_to_pay) <= abs(balance) */
                split_amt = val_to_pay;
            }
            else
            {
                /* abs(val_to_pay) > abs(balance)
                 * Remember payment_value and balance are opposite in sign,
                 * and we want a payment to neutralize the current balance
                 * so we need to negate here */
                split_amt = payment_lot_balance;
            }

            /* If not created yet, create a new transaction linking
             * the base lot and the balancing lot(s) */
            if (!txn)
            {
                Timespec ts = xaccTransRetDatePostedTS (xaccSplitGetParent (gnc_lot_get_latest_split (base_lot)));

                xaccAccountBeginEdit (acct);

                txn = xaccMallocTransaction (book);
                xaccTransBeginEdit (txn);

                xaccTransSetDescription (txn, name ? name : "");
                xaccTransSetCurrency (txn, xaccAccountGetCommodity(acct));
                xaccTransSetDateEnteredSecs (txn, gnc_time (NULL));
                xaccTransSetDatePostedTS (txn, &ts);
                xaccTransSetTxnType (txn, TXN_TYPE_LINK);
            }

            /* Create the split for this link in current balancing lot */
            split = xaccMallocSplit (book);
            xaccSplitSetMemo (split, memo);
            /* set Action using utility function */
            gnc_set_num_action (NULL, split, NULL, action);
            xaccAccountInsertSplit (acct, split);
            xaccTransAppendSplit (txn, split);
            xaccSplitSetBaseValue (split, gnc_numeric_neg (split_amt), xaccAccountGetCommodity(acct));
            gnc_lot_add_split (balancing_lot, split);

            /* If the balancing lot was linked to a document (invoice/credit note),
             * send an event for it as well so it gets potentially updated as paid */
            {
                GncInvoice *this_invoice = gncInvoiceGetInvoiceFromLot(balancing_lot);
                if (this_invoice)
                    qof_event_gen (QOF_INSTANCE(this_invoice), QOF_EVENT_MODIFY, NULL);
            }

            val_paid   = gnc_numeric_add (val_paid, split_amt, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
            val_to_pay = gnc_numeric_sub (val_to_pay, split_amt, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
            if (gnc_numeric_zero_p (val_to_pay))
                break;
        }


        /* If the above loop managed to create a transaction and some balancing splits,
         * create the final split for the link transaction in the base lot */
        if (txn)
        {
            GncInvoice *this_invoice;
            Split *split = xaccMallocSplit (book);

            xaccSplitSetMemo (split, memo);
            /* set Action with utiltity function */
            gnc_set_num_action (NULL, split, NULL, action);
            xaccAccountInsertSplit (acct, split);
            xaccTransAppendSplit (txn, split);
            xaccSplitSetBaseValue (split, val_paid, xaccAccountGetCommodity(acct));
            gnc_lot_add_split (base_lot, split);

            xaccTransCommitEdit (txn);
            xaccAccountCommitEdit (acct);

            /* If the base lot was linked to a document (invoice/credit note),
             * send an event for it as well so it gets potentially updated as paid */
            this_invoice = gncInvoiceGetInvoiceFromLot(base_lot);
            if (this_invoice)
                qof_event_gen (QOF_INSTANCE(this_invoice), QOF_EVENT_MODIFY, NULL);

        }

    }
}
Example #13
0
GNCLot *
gncOwnerCreatePaymentLot (const GncOwner *owner, Transaction *txn,
                          Account *posted_acc, Account *xfer_acc,
                          gnc_numeric amount, gnc_numeric exch, Timespec date,
                          const char *memo, const char *num)
{
    QofBook *book;
    Split *split;
    const char *name;
    gnc_commodity *commodity;
    Split *xfer_split = NULL;
    GNCLot *payment_lot;

    /* Verify our arguments */
    if (!owner || !posted_acc || !xfer_acc) return NULL;
    g_return_val_if_fail (owner->owner.undefined != NULL, NULL);

    /* Compute the ancillary data */
    book = gnc_account_get_book (posted_acc);
    name = gncOwnerGetName (gncOwnerGetEndOwner ((GncOwner*)owner));
    commodity = gncOwnerGetCurrency (owner);
//    reverse = use_reversed_payment_amounts(owner);

    if (txn)
    {
        /* 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. */

        xfer_split = xaccTransFindSplitByAccount(txn, xfer_acc);

        if (xaccTransGetCurrency(txn) != gncOwnerGetCurrency (owner))
        {
            g_message("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)
        {
            g_message("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)
    {
        txn = xaccMallocTransaction (book);
        xaccTransBeginEdit (txn);
    }

    /* 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);
        xaccTransSetDateEnteredSecs (txn, gnc_time (NULL));
        xaccTransSetDatePostedTS (txn, &date);


        /* The split for the transfer account */
        split = xaccMallocSplit (book);
        xaccSplitSetMemo (split, memo);
        /* set per book option */
        gnc_set_num_action (NULL, split, num, _("Payment"));
        xaccAccountBeginEdit (xfer_acc);
        xaccAccountInsertSplit (xfer_acc, split);
        xaccAccountCommitEdit (xfer_acc);
        xaccTransAppendSplit (txn, split);

        if (gnc_commodity_equal(xaccAccountGetCommodity(xfer_acc), commodity))
        {
            xaccSplitSetBaseValue (split, amount, commodity);
        }
        else
        {
            /* Need to value the payment in terms of the owner commodity */
            gnc_numeric payment_value = gnc_numeric_mul(amount,
                                        exch, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND_HALF_UP);

            xaccSplitSetAmount(split, amount);
            xaccSplitSetValue(split, payment_value);
        }
    }

    /* 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"));
    xaccAccountBeginEdit (posted_acc);
    xaccAccountInsertSplit (posted_acc, split);
    xaccAccountCommitEdit (posted_acc);
    xaccTransAppendSplit (txn, split);
    xaccSplitSetBaseValue (split, gnc_numeric_neg (amount), commodity);

    /* Create a new lot for the payment */
    payment_lot = gnc_lot_new (book);
    gncOwnerAttachToLot (owner, payment_lot);
    gnc_lot_add_split (payment_lot, split);

    /* Mark the transaction as a payment */
    gnc_set_num_action (txn, NULL, num, _("Payment"));
    xaccTransSetTxnType (txn, TXN_TYPE_PAYMENT);

    /* Commit this new transaction */
    xaccTransCommitEdit (txn);

    return payment_lot;
}
Example #14
0
static void
gncOwnerCreateLotLink (GNCLot *from_lot, GNCLot *to_lot, const GncOwner *owner)
{
    const gchar *action = _("Lot Link");
    Account *acct = gnc_lot_get_account (from_lot);
    const gchar *name = gncOwnerGetName (gncOwnerGetEndOwner (owner));
    Transaction *ll_txn = NULL;
    gnc_numeric from_lot_bal, to_lot_bal;
    Timespec from_ts, to_ts;
    time64 time_posted;
    Split *split;

    /* Sanity check */
    if (!gncInvoiceGetInvoiceFromLot (from_lot) ||
        !gncInvoiceGetInvoiceFromLot (to_lot))
        return;

    /* Determine transaction date based on lot splits */
    from_ts = xaccTransRetDatePostedTS (xaccSplitGetParent (gnc_lot_get_latest_split (from_lot)));
    to_ts   = xaccTransRetDatePostedTS (xaccSplitGetParent (gnc_lot_get_latest_split (to_lot)));
    if (timespecToTime64 (from_ts) >= timespecToTime64 (to_ts))
        time_posted = timespecToTime64 (from_ts);
    else
        time_posted = timespecToTime64 (to_ts);

    /* Figure out how much we can offset between the lots */
    from_lot_bal = gnc_lot_get_balance (from_lot);
    to_lot_bal = gnc_lot_get_balance (to_lot);
    if (gnc_numeric_compare (gnc_numeric_abs (from_lot_bal),
                             gnc_numeric_abs (to_lot_bal)) > 0)
        from_lot_bal = gnc_numeric_neg (to_lot_bal);
    else
        to_lot_bal = gnc_numeric_neg (from_lot_bal);

    xaccAccountBeginEdit (acct);

    /* Look for a pre-existing lot link we can extend */
    ll_txn = get_ll_transaction_from_lot (from_lot);

    if (!ll_txn)
        ll_txn = get_ll_transaction_from_lot (to_lot);

    if (!ll_txn)
    {
        /* No pre-existing lot link. Create one. */
        Timespec ts;

        timespecFromTime64 (&ts, time_posted);

        ll_txn = xaccMallocTransaction (gnc_lot_get_book (from_lot));
        xaccTransBeginEdit (ll_txn);

        xaccTransSetDescription (ll_txn, name ? name : "(Unknown)");
        xaccTransSetCurrency (ll_txn, xaccAccountGetCommodity(acct));
        xaccTransSetDateEnteredSecs (ll_txn, gnc_time (NULL));
        xaccTransSetDatePostedTS (ll_txn, &ts);
        xaccTransSetTxnType (ll_txn, TXN_TYPE_LINK);
    }
    else
    {
        Timespec ts = xaccTransRetDatePostedTS (ll_txn);
        xaccTransBeginEdit (ll_txn);

        /* Maybe we need to update the post date of the transaction ? */
        if (time_posted > timespecToTime64 (ts))
        {
            timespecFromTime64 (&ts, time_posted);
            xaccTransSetDatePostedTS (ll_txn, &ts);

        }
    }

    /* Create a split for the from_lot */
    split = xaccMallocSplit (gnc_lot_get_book (from_lot));
    /* set Action using utility function */
    gnc_set_num_action (NULL, split, NULL, action);
    xaccAccountInsertSplit (acct, split);
    xaccTransAppendSplit (ll_txn, split);
    /* To offset the lot balance, the split must be of the opposite sign */
    xaccSplitSetBaseValue (split, gnc_numeric_neg (from_lot_bal), xaccAccountGetCommodity(acct));
    gnc_lot_add_split (from_lot, split);

    /* Create a split for the to_lot */
    split = xaccMallocSplit (gnc_lot_get_book (to_lot));
    /* set Action using utility function */
    gnc_set_num_action (NULL, split, NULL, action);
    xaccAccountInsertSplit (acct, split);
    xaccTransAppendSplit (ll_txn, split);
    /* To offset the lot balance, the split must be of the opposite sign */
    xaccSplitSetBaseValue (split, gnc_numeric_neg (to_lot_bal), xaccAccountGetCommodity(acct));
    gnc_lot_add_split (to_lot, split);

    xaccTransCommitEdit (ll_txn);


    /* Do some post-cleaning on the lots
     * The above actions may have created splits that are
     * in the same transaction and lot. These can be merged.
     */
    xaccScrubMergeLotSubSplits (to_lot, FALSE);
    xaccScrubMergeLotSubSplits (from_lot, FALSE);
    /* And finally set the same memo for all remaining splits
     * It's a convenience for the users to identify all documents
     * involved in the link.
     */
    gncOwnerSetLotLinkMemo (ll_txn);
    xaccAccountCommitEdit (acct);
}
Example #15
0
/*
 * Selects a single owner in the owner tree view.  The owner
 * tree must be in single selection mode.
 */
void
gnc_tree_view_owner_set_selected_owner (GncTreeViewOwner *view,
                                        GncOwner *owner)
{
    GtkTreeModel *model, *f_model, *s_model;
    GtkTreePath *path, *f_path, *s_path, *parent_path;
    GtkTreeSelection *selection;

    ENTER("view %p, owner %p (%s)", view,
          owner, gncOwnerGetName (owner));
    g_return_if_fail (GNC_IS_TREE_VIEW_OWNER (view));

    /* Clear any existing selection. */
    selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
    gtk_tree_selection_unselect_all (selection);

    if (owner == NULL)
        return;

    s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
    f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
    model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));

    path = gnc_tree_model_owner_get_path_from_owner (
               GNC_TREE_MODEL_OWNER(model), owner);
    if (path == NULL)
    {
        LEAVE("no path");
        return;
    }
    debug_path(DEBUG, path);

    f_path = gtk_tree_model_filter_convert_child_path_to_path (
                 GTK_TREE_MODEL_FILTER (f_model), path);
    gtk_tree_path_free(path);
    if (f_path == NULL)
    {
        LEAVE("no filter path");
        return;
    }
    debug_path(DEBUG, f_path);

    s_path = gtk_tree_model_sort_convert_child_path_to_path (GTK_TREE_MODEL_SORT (s_model),
             f_path);
    gtk_tree_path_free(f_path);
    if (s_path == NULL)
    {
        LEAVE("no sort path");
        return;
    }

    gtk_tree_selection_select_path (selection, s_path);

    /* give gtk+ a chance to resize the tree view first by handling pending
     * configure events */
    while (gtk_events_pending ())
        gtk_main_iteration ();
    gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW(view), s_path, NULL, FALSE, 0.0, 0.0);
    debug_path(LEAVE, s_path);
    gtk_tree_path_free(s_path);
}
        /* XXX currently not properly implemented, so disabled for now
        gnc_ui_job_new (owner, gnc_get_current_book ()); */
        break;
    }
    case GNC_OWNER_VENDOR :
    {
        gnc_ui_vendor_new (gnc_get_current_book ());
        break;
    }
    case GNC_OWNER_EMPLOYEE :
    {
        gnc_ui_employee_new (gnc_get_current_book ());
        break;
    }
    }
}

static void
gnc_plugin_page_owner_tree_cmd_edit_owner (GtkAction *action, GncPluginPageOwnerTree *page)
{
    GncOwner *owner = gnc_plugin_page_owner_tree_get_current_owner (page);
    if (NULL == owner) return;

    ENTER("action %p, page %p", action, page);

    gnc_ui_owner_edit (owner);

    LEAVE(" ");
}

#if 0 /* Disabled due to crash */
static void
gnc_plugin_page_owner_tree_cmd_delete_owner (GtkAction *action, GncPluginPageOwnerTree *page)
{
    GncOwner *owner = gnc_plugin_page_owner_tree_get_current_owner (page);
    gchar *owner_name;
    GtkWidget *window;
    GtkWidget *dialog = NULL;
    gint response;
    GList* list;

    if (NULL == owner) return;

    /* If the owner has objects referring to it, show the list - the owner can't be deleted until these
       references are dealt with. */
    list = qof_instance_get_referring_object_list(QOF_INSTANCE(gncOwnerGetUndefined(owner)));
    if (list != NULL)
    {
#define EXPLANATION "The list below shows objects which make use of the owner which you want to delete.\nBefore you can delete it, you must either delete those objects or else modify them so they make use\nof another owner"

        gnc_ui_object_references_show( _(EXPLANATION), list);
        g_list_free(list);
        return;
    }

    window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
    owner_name = g_strdup (gncOwnerGetName(owner));
    if (!owner_name)
    {
        owner_name = g_strdup (_("(no name)"));
    }

    /*
     * Present a message to the user which specifies what will be
     * deleted, then ask for verification.
     */
    {
        char *message = g_strdup_printf(_("The owner %s will be deleted.\nAre you sure you want to do this?"), owner_name);

        dialog =  gtk_message_dialog_new(GTK_WINDOW(window),
                                         GTK_DIALOG_DESTROY_WITH_PARENT,
                                         GTK_MESSAGE_QUESTION,
                                         GTK_BUTTONS_NONE,
                                         "%s", message);
        g_free(message);
        gtk_dialog_add_buttons(GTK_DIALOG(dialog),
                               GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                               GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT,
                               (gchar *)NULL);
        gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
        response = gtk_dialog_run(GTK_DIALOG(dialog));
        gtk_widget_destroy(dialog);

        if (GTK_RESPONSE_ACCEPT == response)
        {
            /* FIXME The code below results in a crash.
             *       The corresponding menu item/toolbar button is disabled until this is fixed. */
            gnc_set_busy_cursor(NULL, TRUE);
            gnc_suspend_gui_refresh ();
            gncOwnerBeginEdit (owner);
            gncOwnerDestroy (owner);
            gnc_resume_gui_refresh ();
            gnc_unset_busy_cursor(NULL);
        }
    }
    g_free(owner_name);
}