Esempio n. 1
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 )
{
    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 n;
    GncOwner *owner;
    Account *acc;
    enum update {YES = GTK_RESPONSE_YES, NO = GTK_RESPONSE_NO} update;
    GtkWidget *dialog;
    Timespec today;
    InvoiceWindow *iw;

    // these arguments are needed
    g_return_if_fail (store && book);

    // 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 resonable 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);

        if (!invoice)
        {
            // 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);
        // 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);

        n = gnc_numeric_zero ();
        gnc_exp_parser_parse (quantity, &n, NULL);
        gncEntrySetQuantity (entry, n);
        acc = gnc_account_lookup_for_register (gnc_get_current_root_account (),
                                               account);
        if (g_ascii_strcasecmp (type, "BILL") == 0)
        {
            gncEntrySetBillAccount (entry, acc);
            n = gnc_numeric_zero ();
            gnc_exp_parser_parse (price, &n, NULL);
            gncEntrySetBillPrice (entry, n);
            gncEntrySetBillTaxable (entry, text2bool (taxable));
            gncEntrySetBillTaxIncluded (entry, text2bool (taxincluded));
            gncEntrySetBillTaxTable (entry,
                                     gncTaxTableLookupByName (book, tax_table));
            n = gnc_numeric_zero ();
            gnc_exp_parser_parse (discount, &n, NULL);
            gncBillAddEntry (invoice, entry);
        }
        else if (g_ascii_strcasecmp (type, "INVOICE") == 0)
        {
            gncEntrySetNotes (entry, notes);
            gncEntrySetInvAccount (entry, acc);
            n = gnc_numeric_zero ();
            gnc_exp_parser_parse (price, &n, NULL);
            gncEntrySetInvPrice (entry, n);
            gncEntrySetInvTaxable (entry, text2bool (taxable));
            gncEntrySetInvTaxIncluded (entry, text2bool (taxincluded));
            gncEntrySetInvTaxTable (entry,
                                    gncTaxTableLookupByName (book, tax_table));
            n = gnc_numeric_zero ();
            gnc_exp_parser_parse (discount, &n, NULL);
            gncEntrySetInvDiscount (entry, n);
            gncEntrySetInvDiscountType (entry, text2disc_type (disc_type));
            gncEntrySetInvDiscountHow (entry, text2disc_how (disc_how));
            gncInvoiceAddEntry (invoice, entry);
        }
        valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);

        // handle auto posting of invoices
        {
            gchar *new_id = NULL;
            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
                    Timespec d1, d2;
                    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));
                }
            }
            g_free (new_id);
        }

        // cleanup
        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);
    }
}
static void gnc_entry_ledger_save_cells (gpointer save_data,
        gpointer user_data)
{
    GncEntryLedger *ledger = user_data;
    GncEntry *entry = save_data;

    g_return_if_fail (entry != NULL);

    /* copy the contents from the cursor to the split */

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_IACCT_CELL, TRUE))
    {
        Account *acc;

        acc = gnc_entry_ledger_get_account (ledger, ENTRY_IACCT_CELL);

        if (acc != NULL)
            gncEntrySetInvAccount (entry, acc);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_BACCT_CELL, TRUE))
    {
        Account *acc;

        acc = gnc_entry_ledger_get_account (ledger, ENTRY_BACCT_CELL);

        if (acc != NULL)
            gncEntrySetBillAccount (entry, acc);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_ACTN_CELL, TRUE))
    {
        const char *value;

        value = gnc_table_layout_get_cell_value (ledger->table->layout,
                ENTRY_ACTN_CELL);
        gncEntrySetAction (entry, value);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_DATE_CELL, TRUE))
    {
        BasicCell *cell;
        GDate date;

        cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_DATE_CELL);

        /* commit any pending changes */
        gnc_date_cell_commit ((DateCell *) cell);

        gnc_date_cell_get_date_gdate ((DateCell *) cell, &date);
        gncEntrySetDateGDate (entry, &date);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_DESC_CELL, TRUE))
    {
        const char *value;

        value = gnc_table_layout_get_cell_value (ledger->table->layout,
                ENTRY_DESC_CELL);
        gncEntrySetDescription (entry, value);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_DISC_CELL, TRUE))
    {
        gnc_numeric amount;

        if (gnc_entry_ledger_get_numeric (ledger, ENTRY_DISC_CELL, &amount))
            gncEntrySetInvDiscount (entry, amount);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_DISTYPE_CELL, TRUE))
    {
        gint type;

        type = gnc_entry_ledger_get_type (ledger, ENTRY_DISTYPE_CELL);

        if (type != -1)
            gncEntrySetInvDiscountType (entry, type);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_DISHOW_CELL, TRUE))
    {
        gint type;

        type = gnc_entry_ledger_get_type (ledger, ENTRY_DISHOW_CELL);

        if (type != -1)
            gncEntrySetInvDiscountHow (entry, type);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_QTY_CELL, TRUE))
    {
        gnc_numeric amount;

        if (gnc_entry_ledger_get_numeric (ledger, ENTRY_QTY_CELL, &amount))
        {
            gncEntrySetDocQuantity (entry, amount, ledger->is_credit_note);
        }
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_BILLABLE_CELL, TRUE))
    {
        gboolean billable;

        billable = gnc_entry_ledger_get_checkmark (ledger, ENTRY_BILLABLE_CELL);
        gncEntrySetBillable (entry, billable);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_PAYMENT_CELL, TRUE))
    {
        const char *value;

        value = gnc_table_layout_get_cell_value (ledger->table->layout,
                ENTRY_PAYMENT_CELL);
        if (!g_strcmp0 (value, _("Cash")))
            gncEntrySetBillPayment (entry, GNC_PAYMENT_CASH);
        else if (!g_strcmp0 (value, _("Charge")))
            gncEntrySetBillPayment (entry, GNC_PAYMENT_CARD);
        else
            g_warning ("Invalid Payment cell: %s", value ? value : "(null)");
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_PRIC_CELL, TRUE))
    {
        gnc_numeric amount;

        if (gnc_entry_ledger_get_numeric (ledger, ENTRY_PRIC_CELL, &amount))
        {
            if (ledger->is_cust_doc)
                gncEntrySetInvPrice (entry, amount);
            else
                gncEntrySetBillPrice (entry, amount);
        }
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_TAXABLE_CELL, TRUE))
    {
        gboolean taxable;

        taxable = gnc_entry_ledger_get_checkmark (ledger, ENTRY_TAXABLE_CELL);
        if (ledger->is_cust_doc)
            gncEntrySetInvTaxable (entry, taxable);
        else
            gncEntrySetBillTaxable (entry, taxable);
    }

    /* XXX: Only (re-set) these if taxable is TRUE? */
    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_TAXTABLE_CELL, TRUE))
    {
        GncTaxTable *table;

        table = gnc_entry_ledger_get_taxtable (ledger, ENTRY_TAXTABLE_CELL);
        if (table)
        {
            if (ledger->is_cust_doc)
                gncEntrySetInvTaxTable (entry, table);
            else
                gncEntrySetBillTaxTable (entry, table);
        }
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_TAXINCLUDED_CELL, TRUE))
    {
        gboolean taxincluded;

        taxincluded = gnc_entry_ledger_get_checkmark (ledger,
                      ENTRY_TAXINCLUDED_CELL);
        if (ledger->is_cust_doc)
            gncEntrySetInvTaxIncluded (entry, taxincluded);
        else
            gncEntrySetBillTaxIncluded (entry, taxincluded);
    }

    if (ledger->type == GNCENTRY_INVOICE_ENTRY ||
            ledger->type == GNCENTRY_CUST_CREDIT_NOTE_ENTRY)
    {
        gboolean inv_value;

        inv_value = gnc_entry_ledger_get_checkmark (ledger, ENTRY_INV_CELL);

        if (inv_value)
        {
            /* Add this to the invoice (if it's not already attached) */
            if (gncEntryGetInvoice (entry) == NULL)
                gncInvoiceAddEntry (ledger->invoice, entry);

        }
        else
        {
            /* Remove from the invoice iff we're attached to an order or bill */
            if ((gncEntryGetOrder (entry) != NULL) ||
                    (gncEntryGetBill (entry) != NULL))
                gncInvoiceRemoveEntry (ledger->invoice, entry);
        }
    }
}