Ejemplo n.º 1
0
static gboolean
invoice_should_be_saved (GncInvoice* invoice)
{
    const char* id;

    /* make sure this is a valid invoice before we save it -- should have an ID */
    id = gncInvoiceGetID (invoice);
    if (id == NULL || *id == '\0')
        return FALSE;

    return TRUE;
}
Ejemplo n.º 2
0
/***********************************************************************
 * @todo Maybe invoice checking should be done in gnc_bi_import_fix_bis (...)
 * rather than in here?  But that is more concerned with ensuring the csv is consistent.
 * @param GtkListStore *store
 * @param guint *n_invoices_created
 * @param guint *n_invoices_updated
 * @return void
 ***********************************************************************/
void
gnc_bi_import_create_bis (GtkListStore * store, QofBook * book,
                          guint * n_invoices_created,
                          guint * n_invoices_updated,
                          gchar * type, gchar * open_mode, GString * info)
{
    gboolean valid;
    GtkTreeIter iter;
    gchar *id, *date_opened, *owner_id, *billing_id, *notes;
    gchar *date, *desc, *action, *account, *quantity, *price, *disc_type,
          *disc_how, *discount, *taxable, *taxincluded, *tax_table;
    gchar *date_posted, *due_date, *account_posted, *memo_posted,
          *accumulatesplits;
    guint dummy;
    GncInvoice *invoice;
    GncEntry *entry;
    gint day, month, year;
    gnc_numeric value;
    GncOwner *owner;
    Account *acc;
    enum update {YES = GTK_RESPONSE_YES, NO = GTK_RESPONSE_NO} update;
    GtkWidget *dialog;
    Timespec today;
    InvoiceWindow *iw;
    gchar *new_id = NULL;
    gint64 denom = 0;
    gnc_commodity *currency;
    
    // these arguments are needed
    g_return_if_fail (store && book);
    // logic of this function only works for bills or invoices
    g_return_if_fail ((g_ascii_strcasecmp (type, "INVOICE") == 0) ||
            (g_ascii_strcasecmp (type, "BILL") == 0));

    // allow to call this function without statistics
    if (!n_invoices_created)
        n_invoices_created = &dummy;
    if (!n_invoices_updated)
        n_invoices_updated = &dummy;
    *n_invoices_created = 0;
    *n_invoices_updated = 0;

    invoice = NULL;
    update = NO;

    valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
    while (valid)
    {
        // Walk through the list, reading each row
        gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
                            ID, &id,
                            DATE_OPENED, &date_opened,
                            DATE_POSTED, &date_posted,       // if autoposting requested
                            DUE_DATE, &due_date,             // if autoposting requested
                            ACCOUNT_POSTED, &account_posted, // if autoposting requested
                            MEMO_POSTED, &memo_posted,       // if autoposting requested
                            ACCU_SPLITS, &accumulatesplits,  // if autoposting requested
                            OWNER_ID, &owner_id,
                            BILLING_ID, &billing_id,
                            NOTES, &notes,
                            DATE, &date,
                            DESC, &desc,
                            ACTION, &action,
                            ACCOUNT, &account,
                            QUANTITY, &quantity,
                            PRICE, &price,
                            DISC_TYPE, &disc_type,
                            DISC_HOW, &disc_how,
                            DISCOUNT, &discount,
                            TAXABLE, &taxable,
                            TAXINCLUDED, &taxincluded,
                            TAX_TABLE, &tax_table, -1);

        // TODO:  Assign a new invoice number if one is absent.  BUT we don't want to assign a new invoice for every line!!
        // so we'd have to flag this up somehow or add an option in the import GUI.  The former implies that we make
        // an assumption about what the importer (person) wants to do.  It seems reasonable that a CSV file full of items with
        // If an invoice exists then we add to it in this current schema.
        // no predefined invoice number is a new invoice that's in need of a new number.
        // This was  not designed to satisfy the need for repeat invoices however, so maybe we need a another method for this, after all
        // It should be easier to copy an invoice with a new ID than to go through all this malarky.
        if (g_ascii_strcasecmp (type, "BILL") == 0)
            invoice = gnc_search_bill_on_id (book, id);
        else if (g_ascii_strcasecmp (type, "INVOICE") == 0)
            invoice = gnc_search_invoice_on_id (book, id);
        DEBUG( "Existing %s ID: %s\n", type, gncInvoiceGetID(invoice));

        // If the search is empty then there is no existing invoice so make a new one
        if (invoice == NULL)
        {
             DEBUG( "Creating a new : %s\n", type );
            // new invoice
            invoice = gncInvoiceCreate (book);
            /* Protect against thrashing the DB and trying to write the invoice
             * record prematurely */
            gncInvoiceBeginEdit (invoice);
            gncInvoiceSetID (invoice, id);
            owner = gncOwnerNew ();
            if (g_ascii_strcasecmp (type, "BILL") == 0)
                gncOwnerInitVendor (owner,
                                    gnc_search_vendor_on_id (book, owner_id));
            else if (g_ascii_strcasecmp (type, "INVOICE") == 0)
                gncOwnerInitCustomer (owner,
                                      gnc_search_customer_on_id (book, owner_id));
            gncInvoiceSetOwner (invoice, owner);
            gncInvoiceSetCurrency (invoice, gncOwnerGetCurrency (owner));	// Set the invoice currency based on the owner
            if (strlen (date_opened) != 0)	// If a date is specified in CSV
            {
                // FIXME: Must check for the return value of qof_scan_date!
                qof_scan_date (date_opened, &day, &month, &year);
                gncInvoiceSetDateOpened (invoice,
                                         gnc_dmy2timespec (day, month, year));
            }
            else			// If no date in CSV
            {
                time64 now = gnc_time (NULL);
                Timespec now_timespec;
                timespecFromTime64 (&now_timespec, now);
                gncInvoiceSetDateOpened (invoice, now_timespec);
            }
            gncInvoiceSetBillingID (invoice, billing_id ? billing_id : "");
            gncInvoiceSetNotes (invoice, notes ? notes : "");
            gncInvoiceSetActive (invoice, TRUE);
            //if (g_ascii_strcasecmp(type,"INVOICE"))gncInvoiceSetBillTo( invoice, billto );
            (*n_invoices_created)++;
            update = YES;

            // open new bill / invoice in a tab, if requested
            if (g_ascii_strcasecmp(open_mode, "ALL") == 0
                    || (g_ascii_strcasecmp(open_mode, "NOT_POSTED") == 0
                        && strlen(date_posted) == 0))
            {
                iw =  gnc_ui_invoice_edit (invoice);
                gnc_plugin_page_invoice_new (iw);
            }
            gncInvoiceCommitEdit (invoice);
        }
// I want to warn the user that an existing billvoice exists, but not every
// time.
// An import can contain many lines usually referring to the same invoice.
// NB: Posted invoices are NEVER updated.
        else			// if invoice exists
        {
            if (gncInvoiceIsPosted (invoice))	// Is it already posted?
            {
                valid =
                    gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
                continue;		// If already posted then never import
            }
            if (update != YES)	// Pop up a dialog to ask if updates are the expected action
            {
                dialog = gtk_message_dialog_new (NULL,
                                                 GTK_DIALOG_MODAL,
                                                 GTK_MESSAGE_ERROR,
                                                 GTK_BUTTONS_YES_NO,
                                                 "%s",
                                                 _("Are you sure you have bills/invoices to update?"));
                update = gtk_dialog_run (GTK_DIALOG (dialog));
                gtk_widget_destroy (dialog);
                if (update == NO)
                {
                    // Cleanup and leave
                    g_free (id);
                    g_free (date_opened);
                    g_free (owner_id);
                    g_free (billing_id);
                    g_free (notes);
                    g_free (date);
                    g_free (desc);
                    g_free (action);
                    g_free (account);
                    g_free (quantity);
                    g_free (price);
                    g_free (disc_type);
                    g_free (disc_how);
                    g_free (discount);
                    g_free (taxable);
                    g_free (taxincluded);
                    g_free (tax_table);
                    g_free (date_posted);
                    g_free (due_date);
                    g_free (account_posted);
                    g_free (memo_posted);
                    g_free (accumulatesplits);
                    return;
                }
            }
            (*n_invoices_updated)++;
        }


        // add entry to invoice/bill
        entry = gncEntryCreate (book);
        gncEntryBeginEdit(entry);
        currency = gncInvoiceGetCurrency(invoice);
        if (currency) denom = gnc_commodity_get_fraction(currency);
        // FIXME: Must check for the return value of qof_scan_date!
        qof_scan_date (date, &day, &month, &year);
        {
            GDate *date = g_date_new_dmy(day, month, year);
            gncEntrySetDateGDate (entry, date);
            g_date_free (date);
        }
        timespecFromTime64 (&today, gnc_time (NULL));	// set today to the current date
        gncEntrySetDateEntered (entry, today);
        gncEntrySetDescription (entry, desc);
        gncEntrySetAction (entry, action);
        value = gnc_numeric_zero();
        gnc_exp_parser_parse (quantity, &value, NULL);
        gncEntrySetQuantity (entry, value);
        acc = gnc_account_lookup_for_register (gnc_get_current_root_account (),
                                               account);
        
        if (g_ascii_strcasecmp (type, "BILL") == 0)
        {
            gncEntrySetBillAccount (entry, acc);
            value = gnc_numeric_zero();
            gnc_exp_parser_parse (price, &value, NULL);
            gncEntrySetBillPrice (entry, value);
            gncEntrySetBillTaxable (entry, text2bool (taxable));
            gncEntrySetBillTaxIncluded (entry, text2bool (taxincluded));
            gncEntrySetBillTaxTable (entry, gncTaxTableLookupByName (book, tax_table));
            gncEntryCommitEdit(entry);
            gncBillAddEntry (invoice, entry);
        }
        else if (g_ascii_strcasecmp (type, "INVOICE") == 0)
        {
            gncEntrySetNotes (entry, notes);
            gncEntrySetInvAccount (entry, acc);
            value = gnc_numeric_zero();
            gnc_exp_parser_parse (price, &value, NULL);
            gncEntrySetInvPrice (entry, value);
            gncEntrySetInvTaxable (entry, text2bool (taxable));
            gncEntrySetInvTaxIncluded (entry, text2bool (taxincluded));
            gncEntrySetInvTaxTable (entry, gncTaxTableLookupByName (book, tax_table));
            value = gnc_numeric_zero();
            gnc_exp_parser_parse (discount, &value, NULL);
            gncEntrySetInvDiscount (entry, value);
            gncEntrySetInvDiscountType (entry, text2disc_type (disc_type));
            gncEntrySetInvDiscountHow (entry, text2disc_how (disc_how));
            gncEntryCommitEdit(entry);
            gncInvoiceAddEntry (invoice, entry);
        }
        valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);

        // handle auto posting of invoices
    
        
        if (valid)
            gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, ID, &new_id, -1);
        if (g_strcmp0 (id, new_id) != 0)
        {
            // the next invoice id is different => try to autopost this invoice
            if (qof_scan_date (date_posted, &day, &month, &year))
            {
                // autopost this invoice
                gboolean auto_pay;
                Timespec d1, d2;

                if (g_ascii_strcasecmp (type, "INVOICE") == 0)
                    auto_pay = gnc_prefs_get_bool (GNC_PREFS_GROUP_INVOICE, GNC_PREF_AUTO_PAY);
                else
                    auto_pay = gnc_prefs_get_bool (GNC_PREFS_GROUP_BILL, GNC_PREF_AUTO_PAY);

                d1 = gnc_dmy2timespec (day, month, year);
                // FIXME: Must check for the return value of qof_scan_date!
                qof_scan_date (due_date, &day, &month, &year);	// obtains the due date, or leaves it at date_posted
                d2 = gnc_dmy2timespec (day, month, year);
                acc = gnc_account_lookup_for_register
                      (gnc_get_current_root_account (), account_posted);
                gncInvoicePostToAccount (invoice, acc, &d1, &d2,
                                         memo_posted,
                                         text2bool (accumulatesplits),
                                         auto_pay);
            }

        }
        
        
    }
    // cleanup
    g_free (new_id);
    g_free (id);
    g_free (date_opened);
    g_free (owner_id);
    g_free (billing_id);
    g_free (notes);
    g_free (date);
    g_free (desc);
    g_free (action);
    g_free (account);
    g_free (quantity);
    g_free (price);
    g_free (disc_type);
    g_free (disc_how);
    g_free (discount);
    g_free (taxable);
    g_free (taxincluded);
    g_free (tax_table);
    g_free (date_posted);
    g_free (due_date);
    g_free (account_posted);
    g_free (memo_posted);
    g_free (accumulatesplits);
    
}
Ejemplo n.º 3
0
static xmlNodePtr
invoice_dom_tree_create (GncInvoice* invoice)
{
    xmlNodePtr ret;
    Timespec ts;
    Transaction* txn;
    GNCLot* lot;
    Account* acc;
    GncBillTerm* term;
    GncOwner* billto;
    gnc_numeric amt;

    ret = xmlNewNode (NULL, BAD_CAST gnc_invoice_string);
    xmlSetProp (ret, BAD_CAST "version", BAD_CAST invoice_version_string);

    xmlAddChild (ret, guid_to_dom_tree (invoice_guid_string,
                                        qof_instance_get_guid (QOF_INSTANCE (invoice))));

    xmlAddChild (ret, text_to_dom_tree (invoice_id_string,
                                        gncInvoiceGetID (invoice)));

    xmlAddChild (ret, gnc_owner_to_dom_tree (invoice_owner_string,
                                             gncInvoiceGetOwner (invoice)));

    ts = gncInvoiceGetDateOpened (invoice);
    xmlAddChild (ret, timespec_to_dom_tree (invoice_opened_string, &ts));

    maybe_add_timespec (ret, invoice_posted_string,
                        gncInvoiceGetDatePosted (invoice));

    term = gncInvoiceGetTerms (invoice);
    if (term)
        xmlAddChild (ret, guid_to_dom_tree (invoice_terms_string,
                                            qof_instance_get_guid (QOF_INSTANCE (term))));

    maybe_add_string (ret, invoice_billing_id_string,
                      gncInvoiceGetBillingID (invoice));
    maybe_add_string (ret, invoice_notes_string, gncInvoiceGetNotes (invoice));

    xmlAddChild (ret, int_to_dom_tree (invoice_active_string,
                                       gncInvoiceGetActive (invoice)));

    txn = gncInvoiceGetPostedTxn (invoice);
    if (txn)
        xmlAddChild (ret, guid_to_dom_tree (invoice_posttxn_string,
                                            xaccTransGetGUID (txn)));

    lot = gncInvoiceGetPostedLot (invoice);
    if (lot)
        xmlAddChild (ret, guid_to_dom_tree (invoice_postlot_string,
                                            gnc_lot_get_guid (lot)));

    acc = gncInvoiceGetPostedAcc (invoice);
    if (acc)
        xmlAddChild (ret, guid_to_dom_tree (invoice_postacc_string,
                                            qof_instance_get_guid (QOF_INSTANCE (acc))));

    xmlAddChild
    (ret,
     commodity_ref_to_dom_tree (invoice_currency_string,
                                gncInvoiceGetCurrency (invoice)));

    billto = gncInvoiceGetBillTo (invoice);
    if (billto && billto->owner.undefined != NULL)
        xmlAddChild (ret, gnc_owner_to_dom_tree (invoice_billto_string, billto));

    amt = gncInvoiceGetToChargeAmount (invoice);
    if (! gnc_numeric_zero_p (amt))
        xmlAddChild (ret, gnc_numeric_to_dom_tree (invoice_tochargeamt_string, &amt));

    /* xmlAddChild won't do anything with a NULL, so tests are superfluous. */
    xmlAddChild (ret, qof_instance_slots_to_dom_tree (invoice_slots_string,
                                                      QOF_INSTANCE (invoice)));
    return ret;
}
Ejemplo n.º 4
0
void
gnc_payment_window_fill_docs_list (PaymentWindow *pw)
{
    GtkListStore *store;
    GList *list = NULL, *node;

    g_return_if_fail (pw->docs_list_tree_view && GTK_IS_TREE_VIEW(pw->docs_list_tree_view));

    /* Get a list of open lots for this owner and post account */
    if (pw->owner.owner.undefined)
        list = xaccAccountFindOpenLots (pw->post_acct, gncOwnerLotMatchOwnerFunc,
                                        &pw->owner, NULL);

    /* Clear the existing list */
    store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(pw->docs_list_tree_view)));
    gtk_list_store_clear(store);

    /* Add the documents and overpayments to the tree view */
    for (node = list; node; node = node->next)
    {
        GNCLot *lot = node->data;
        time64 doc_date_time = 0;
        const gchar *doc_type_str = NULL;
        const gchar *doc_id_str   = NULL;
        const gchar *doc_deb_str  = NULL;
        const gchar *doc_cred_str = NULL;
        GtkTreeIter iter;
        Timespec doc_date;
        GncInvoice *document;
        gnc_numeric value = gnc_numeric_zero();
        gnc_numeric debit = gnc_numeric_zero();
        gnc_numeric credit = gnc_numeric_zero();

        /* Find the lot's document if it exists,
         * it could also be a prepayment lot. */
        document = gncInvoiceGetInvoiceFromLot (lot);

        /* Find the document's date or pre-payment date */
        if (document)
            doc_date = gncInvoiceGetDatePosted (document);
        else
        {
            /* Calculate the payment date based on the lot splits */
            Transaction *trans = xaccSplitGetParent (gnc_lot_get_latest_split (lot));
            if (trans)
                doc_date = xaccTransRetDatePostedTS (trans);
            else
                continue; /* No valid split in this lot, skip it */
        }
        doc_date_time = timespecToTime64 (doc_date);

        /* Find the document type. No type means pre-payment in this case */
        if (document)
        {
            doc_type_str = gncInvoiceGetTypeString (document);
        }
        else
            doc_type_str = _("Pre-Payment");

        /* Find the document id. Empty for pre-payments. */
        if (document)
        {
            doc_id_str = gncInvoiceGetID (document);
        }

        /* Find the debit/credit amount.
         * Invoices/vendor credit notes are debit (increasing the balance)
         * Customer credit notes/bills are credit (decreasing the balance)
         * Pre-payments are debit or credit depending on their sign
         */
        value = gnc_lot_get_balance (lot);

        if (gnc_numeric_positive_p (value))
            debit = value;
        else
            credit = gnc_numeric_neg (value);

        /* Only display non-zero debits/credits */
        if (!gnc_numeric_zero_p (debit))
            doc_deb_str = xaccPrintAmount (debit, gnc_default_print_info (FALSE));
        if (!gnc_numeric_zero_p (credit))
            doc_cred_str = xaccPrintAmount (credit, gnc_default_print_info (FALSE));

        gtk_list_store_append (store, &iter);
        gtk_list_store_set (store, &iter,
                            0, doc_date_time,
                            1, doc_id_str,
                            2, doc_type_str,
                            3, doc_deb_str,
                            4, doc_cred_str,
                            5, (gpointer)lot,
                            -1);

    }

    g_list_free (list);

    /* Highlight the preset invoice if it's in the new list */
    gnc_payment_dialog_highlight_document (pw);
}
Ejemplo n.º 5
0
void
gncOwnerSetLotLinkMemo (Transaction *ll_txn)
{
    gchar *memo_prefix = _("Offset between documents: ");
    gchar *new_memo;
    SplitList *lts_iter;
    SplitList *splits = NULL, *siter;
    GList *titles = NULL, *titer;

    if (!ll_txn)
        return;

    if (xaccTransGetTxnType (ll_txn) != TXN_TYPE_LINK)
        return;

    // Find all splits in the lot link transaction that are also in a document lot
    for (lts_iter = xaccTransGetSplitList (ll_txn); lts_iter; lts_iter = lts_iter->next)
    {
        Split *split = lts_iter->data;
        GNCLot *lot;
        GncInvoice *invoice;
        gchar *title;

        if (!split)
            continue;

        lot = xaccSplitGetLot (split);
        if (!lot)
            continue;

        invoice = gncInvoiceGetInvoiceFromLot (lot);
        if (!invoice)
            continue;

        title = g_strdup_printf ("%s %s", gncInvoiceGetTypeString (invoice), gncInvoiceGetID (invoice));

        titles = g_list_insert_sorted (titles, title, (GCompareFunc)g_strcmp0);
        splits = g_list_prepend (splits, split); // splits don't need to be sorted
    }

    if (!titles)
        return; // We didn't find document lots

    // Create the memo as we'd want it to be
    new_memo = g_strconcat (memo_prefix, titles->data, NULL);
    for (titer = titles->next; titer; titer = titer->next)
    {
        gchar *tmp_memo = g_strconcat (new_memo, " - ", titer->data, NULL);
        g_free (new_memo);
        new_memo = tmp_memo;
    }
    g_list_free_full (titles, g_free);

    // Update the memos of all the splits we found previously (if needed)
    for (siter = splits; siter; siter = siter->next)
    {
        if (g_strcmp0 (xaccSplitGetMemo (siter->data), new_memo) != 0)
            xaccSplitSetMemo (siter->data, new_memo);
    }

    g_list_free (splits);
    g_free (new_memo);
}