From a9df3df3f920f6debfef4aa3885540076130ec00 Mon Sep 17 00:00:00 2001 From: Derek Atkins Date: Sat, 22 Jun 2002 21:55:00 +0000 Subject: [PATCH] * gncBillTerm: add functions to compute DueDate and DiscountDate from a Timespec (post_date) and the Billing Term definition. * dialog-date-close: use billing terms; if a term object is supplied, display the due date but do not allow the user to modify it directly. Use callbacks from the date-edit widget to update the due date. * dialog-invoice: don't worry about pre-computing a due date; pass the billing terms into the date-close dialog. * date: add a few convenience functions to convert from Timespec to day/month/year; compute the last mday from a Timespec; compute the last mday from a month/year. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@6997 57a11ea4-9604-0410-9ed3-97b8803252fd --- src/business/business-core/gncBillTerm.c | 78 +++++++++++++++++++ src/business/business-core/gncBillTerm.h | 8 ++ .../business-gnome/dialog-date-close.c | 27 ++++++- .../business-gnome/dialog-date-close.h | 2 + src/business/business-gnome/dialog-invoice.c | 11 ++- src/engine/date.c | 55 +++++++++---- src/engine/date.h | 4 + 7 files changed, 163 insertions(+), 22 deletions(-) diff --git a/src/business/business-core/gncBillTerm.c b/src/business/business-core/gncBillTerm.c index 9228a445ac..40ef2daabb 100644 --- a/src/business/business-core/gncBillTerm.c +++ b/src/business/business-core/gncBillTerm.c @@ -371,6 +371,84 @@ gboolean gncBillTermIsDirty (GncBillTerm *term) return term->dirty; } +/********************************************************/ +/* functions to compute dates from Bill Terms */ + +#define SECS_PER_DAY 86400 + +/* Based on the timespec and a proximo type, compute the month and + * year this is due. The actual day is filled in below. + */ +static void +compute_monthyear (GncBillTerm *term, Timespec post_date, + int *month, int *year) +{ + int iday, imonth, iyear; + int cutoff = term->cutoff; + + g_return_if_fail (term->type == GNC_TERM_TYPE_PROXIMO); + + gnc_timespec2dmy (post_date, &iday, &imonth, &iyear); + + if (cutoff <= 0) + cutoff += gnc_timespec_last_mday (post_date); + + if (iday <= cutoff) { + /* We apply this to next month */ + imonth++; + } else { + /* We apply to the following month */ + imonth += 2; + } + + if (imonth > 12) { + iyear++; + imonth -= 12; + } + + if (month) *month = imonth; + if (year) *year = iyear; +} + +static Timespec +compute_time (GncBillTerm *term, Timespec post_date, int days) +{ + Timespec res = post_date; + int day, month, year; + + switch (term->type) { + case GNC_TERM_TYPE_DAYS: + res.tv_sec += (SECS_PER_DAY * days); + break; + case GNC_TERM_TYPE_PROXIMO: + compute_monthyear (term, post_date, &month, &year); + day = gnc_date_my_last_mday (month, year); + if (days < day) + day = days; + res = gnc_dmy2timespec (day, month, year); + break; + } + return res; +} + +Timespec +gncBillTermComputeDueDate (GncBillTerm *term, Timespec post_date) +{ + Timespec res = post_date; + if (!term) return res; + + return compute_time (term, post_date, term->due_days); +} + +Timespec +gncBillTermComputeDiscountDate (GncBillTerm *term, Timespec post_date) +{ + Timespec res = post_date; + if (!term) return res; + + return compute_time (term, post_date, term->disc_days); +} + /* Package-Private functions */ static void add_or_rem_object (GncBillTerm *term, gboolean add) diff --git a/src/business/business-core/gncBillTerm.h b/src/business/business-core/gncBillTerm.h index ca81fc8ed6..08cb6cd67e 100644 --- a/src/business/business-core/gncBillTerm.h +++ b/src/business/business-core/gncBillTerm.h @@ -11,6 +11,7 @@ typedef struct _gncBillTerm GncBillTerm; #include "gnc-numeric.h" #include "gnc-book.h" +#include "date.h" #define GNC_BILLTERM_MODULE_NAME "gncBillTerm" @@ -66,4 +67,11 @@ gint64 gncBillTermGetRefcount (GncBillTerm *term); int gncBillTermCompare (GncBillTerm *a, GncBillTerm *b); +/********************************************************/ +/* functions to compute dates from Bill Terms */ + +/* Compute the due date and discount dates from the post date */ +Timespec gncBillTermComputeDueDate (GncBillTerm *term, Timespec post_date); +Timespec gncBillTermComputeDiscountDate (GncBillTerm *term, Timespec post_date); + #endif /* GNC_BILLTERM_H_ */ diff --git a/src/business/business-gnome/dialog-date-close.c b/src/business/business-gnome/dialog-date-close.c index d39221dc64..8a92cca71c 100644 --- a/src/business/business-gnome/dialog-date-close.c +++ b/src/business/business-gnome/dialog-date-close.c @@ -25,6 +25,7 @@ typedef struct _dialog_date_close_window { GtkWidget *post_date; GtkWidget *acct_combo; GtkWidget *memo_entry; + GncBillTerm *terms; Timespec *ts, *ts2; GList * acct_types; GNCBook *book; @@ -231,6 +232,18 @@ gnc_dialog_date_close_parented (GtkWidget *parent, const char *message, return retval; } +static void +post_date_changed_cb (GNCDateEdit *gde, gpointer d) +{ + DialogDateClose *ddc = d; + Timespec post_date; + Timespec due_date; + + post_date = gnc_date_edit_get_date_ts (gde); + due_date = gncBillTermComputeDueDate (ddc->terms, post_date); + gnc_date_edit_set_time_ts (GNC_DATE_EDIT (ddc->date), due_date); +} + gboolean gnc_dialog_dates_acct_parented (GtkWidget *parent, const char *message, const char *ddue_label_message, @@ -238,6 +251,7 @@ gnc_dialog_dates_acct_parented (GtkWidget *parent, const char *message, const char *acct_label_message, gboolean ok_is_default, GList * acct_types, GNCBook *book, + GncBillTerm *terms, /* Returned Data... */ Timespec *ddue, Timespec *post, char **memo, Account **acct) @@ -259,6 +273,7 @@ gnc_dialog_dates_acct_parented (GtkWidget *parent, const char *message, ddc->book = book; ddc->acct_types = acct_types; ddc->memo = memo; + ddc->terms = terms; xml = gnc_glade_xml_new ("date-close.glade", "Date Account Dialog"); ddc->dialog = glade_xml_get_widget (xml, "Date Account Dialog"); @@ -287,10 +302,18 @@ gnc_dialog_dates_acct_parented (GtkWidget *parent, const char *message, label = glade_xml_get_widget (xml, "acct_label"); gtk_label_set_text (GTK_LABEL (label), acct_label_message); - /* Set the date widget */ - gnc_date_edit_set_time_ts (GNC_DATE_EDIT (ddc->date), *ddue); + /* Set the post date widget */ gnc_date_edit_set_time_ts (GNC_DATE_EDIT (ddc->post_date), *post); + /* Deal with the terms handling of the due date */ + if (terms) { + gtk_signal_connect (GTK_OBJECT (ddc->post_date), "date_changed", + post_date_changed_cb, ddc); + gtk_widget_set_sensitive (ddc->date, FALSE); + post_date_changed_cb (ddc->post_date, ddc); + } else + gnc_date_edit_set_time_ts (GNC_DATE_EDIT (ddc->date), *ddue); + /* Setup the account widget */ fill_in_acct_info (ddc); diff --git a/src/business/business-gnome/dialog-date-close.h b/src/business/business-gnome/dialog-date-close.h index 14a7725617..a04152242c 100644 --- a/src/business/business-gnome/dialog-date-close.h +++ b/src/business/business-gnome/dialog-date-close.h @@ -10,6 +10,7 @@ #include "date.h" #include "Account.h" #include "gnc-book.h" +#include "gncBillTerm.h" gboolean gnc_dialog_date_close_parented (GtkWidget *parent, const char *message, @@ -32,6 +33,7 @@ gnc_dialog_dates_acct_parented (GtkWidget *parent, const char *message, const char *acct_label_message, gboolean ok_is_default, GList * acct_types, GNCBook *book, + GncBillTerm *terms, /* Returned Data... */ Timespec *ddue, Timespec *post, char **memo, Account **acct); diff --git a/src/business/business-gnome/dialog-invoice.c b/src/business/business-gnome/dialog-invoice.c index 0074211f40..f0800eb5fb 100644 --- a/src/business/business-gnome/dialog-invoice.c +++ b/src/business/business-gnome/dialog-invoice.c @@ -307,12 +307,12 @@ gnc_invoice_window_post_invoice_cb (GtkWidget *widget, gpointer data) /* Get the due date and posted account */ timespecFromTime_t (&postdate, time(NULL)); ddue = postdate; - ddue.tv_sec += 3600*24*30; /* XXX: due in 30 days */ memo = NULL; if (!gnc_dialog_dates_acct_parented (iw->dialog, message, ddue_label, - post_label, acct_label, TRUE, acct_types, - iw->book, &ddue, &postdate, &memo, &acc)) + post_label, acct_label, TRUE, + acct_types, iw->book, iw->terms, + &ddue, &postdate, &memo, &acc)) return; /* Yep, we're posting. So, save the invoice... @@ -1078,7 +1078,6 @@ gnc_invoice_update_window (InvoiceWindow *iw) /* gtk_widget_set_sensitive (iw->id_entry, FALSE); gtk_widget_set_sensitive (iw->terms_menu, FALSE); - gtk_widget_set_sensitive (iw->opened_date, FALSE); gtk_widget_set_sensitive (iw->notes_text, FALSE); *//* XXX: should notes remain writable? */ } @@ -1163,6 +1162,10 @@ gnc_invoice_new_window (GNCBook *bookp, InvoiceDialogType type, gtk_box_pack_start (GTK_BOX(iw->posted_date_hbox), iw->posted_date, TRUE, TRUE, 0); + /* Make the opened and posted dates insensitive in this window */ + gtk_widget_set_sensitive (iw->opened_date, FALSE); + gtk_widget_set_sensitive (iw->posted_date, FALSE); + /* Build the ledger */ switch (type) { case EDIT_INVOICE: diff --git a/src/engine/date.c b/src/engine/date.c index b15fef38c9..1f17cb4709 100644 --- a/src/engine/date.c +++ b/src/engine/date.c @@ -170,6 +170,24 @@ timespecCanonicalDayTime(Timespec t) return retval; } +int gnc_date_my_last_mday (int month, int year) +{ + gboolean is_leap; + static int days_in_month[2][12] = + {/* non leap */ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + /* leap */ {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; + + /* Is this a leap year? */ + if (year / 2000 == 0) + is_leap = TRUE; + else if (year / 400 == 0) + is_leap = FALSE; + else + is_leap = (year / 4 == 0); + + return days_in_month[is_leap][month-1]; +} + /** * date_get_last_mday * Retrieve the last nomerical day for the month specified in the @@ -179,22 +197,7 @@ timespecCanonicalDayTime(Timespec t) **/ int date_get_last_mday(struct tm *tm) { - int year; - gboolean is_leap; - static int days_in_month[2][12] = - {/* non leap */ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, - /* leap */ {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; - - /* Is this a leap year? */ - year = tm->tm_year + 1900; - if (year / 2000 == 0) - is_leap = TRUE; - else if (year / 400 == 0) - is_leap = FALSE; - else - is_leap = (year / 4 == 0); - - return days_in_month[is_leap][tm->tm_mon]; + return gnc_date_my_last_mday (tm->tm_mon+1, tm->tm_year+1900); } /** @@ -741,6 +744,26 @@ gnc_timespec_to_iso8601_buff (Timespec ts, char * buff) return buff; } +int +gnc_timespec_last_mday (Timespec t) +{ + struct tm *result; + time_t t_secs = t.tv_sec + (t.tv_nsec / NANOS_PER_SECOND); + result = localtime(&t_secs); + return date_get_last_mday (result); +} + +void +gnc_timespec2dmy (Timespec t, int *day, int *month, int *year) +{ + struct tm *result; + time_t t_secs = t.tv_sec + (t.tv_nsec / NANOS_PER_SECOND); + result = localtime(&t_secs); + + if (day) *day = result->tm_mday; + if (month) *month = result->tm_mon+1; + if (year) *year = result->tm_year+1900; +} /********************************************************************\ \********************************************************************/ diff --git a/src/engine/date.h b/src/engine/date.h index f842b9edbe..66447befb5 100644 --- a/src/engine/date.h +++ b/src/engine/date.h @@ -174,6 +174,10 @@ void scanDate (const char *buff, int *day, int *month, int *year); */ char dateSeparator(void); +int gnc_date_my_last_mday (int month, int year); +int gnc_timespec_last_mday (Timespec ts); +void gnc_timespec2dmy (Timespec ts, int *day, int *month, int *year); + /* * hack alert XXX FIXME -- these date routines return incorrect * values for dates before 1970. Most of them are good only up