mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
* 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
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user