Okay... more development of the important part: frequency specification... Thanks to Pete Yadlowsky <[EMAIL PROTECTED]> for suggesting the frequency divider common to elec.eng. stuff... here it shows up as a multiplier. Thanks to Dr. Dave Merrill for eliminating a special "yearly" enum value, and suggesting that, yes, it really can be that simple... :) If you take issue with this, it's preferred that you reply to the list. This isn't perfect, and I list some still-undealt-with issues [difference between "yearly:360" and "yearly:365", for instance. I've talked to a coworker of mine who mentioned he was working on the corporate budget recently, and need to sit down with him to get business-specific issues, but those can happen in time. I'm going to call this "good enough for now", and start working on a generic frequency-editing UI component [for both sched transactions and budgeting] and the rest of a scheduled transaction editor... Please forgive the loose-syntax and OO paradigm; that will go away in implementation. Once we can create/edit and save/restore scheduled xactions, we'll integrate them into the rest of GnuCash; recommendations about how to save/restore the data correctly is appreciated... More examples which can't be represented by this [see the end] are encouraged. ...jsled ----- /** * Updated frequency enum. **/ enum FrequencyType { DAILY, WEEKLY, // BI_WEEKLY: use WEEKLY[2] // SEMI_MONTHLY: use composite MONTHLY, // YEARLY: use MONTHLY[12] MONTH_RELATIVE, COMPOSITE, RELATIVE, }; /** * A single scheduled transaction. * * Scheduled transactions have a list of transactions, and a frequency * [and associated date anchors] with which they are scheduled. * * Things that make sense to have in a template transaction: * [not] Date [though eventually some/multiple template transactions * might have relative dates]. * Memo * Account * Funds In/Out... or an expr involving 'amt' [A, x, y, a?] for * variable expenses. * * Template transactions are instantiated by: * . copying the fields of the template * . setting the date to the calculated "due" date. * * We should be able to use the GeneralLedger [or, yet-another-subtype * of the internal ledger] for this editing. **/ struct ScheduledTransaction { FreqSpecifier freq; // start_date should have a valid value. time_t start_date; // If end_date is 0, then no end. time_t end_date; // if num_occurances_total is -1, then no limit [and the rest are undef] int num_occurances_total; int num_occurances_remaining; time_t as_of; /** * The template transactions. **/ GList /* <Transaction *> */ *templateTrans; }; /** * Integration possibilities: * * . create files/interface for scheduled transaction data structs. * . structs * . interface suitable for UI * . programatic interface * . user configuration: * . show future scheduled transactions? * . scheduled transaction post-blue-line window * . auto-instantiate scheduled transactions? * . some "since-last-run" UI for instantiating scheduled * transactions. * . create stand-alone UI for scheduled transactions. * . register modifications for scheduled transactions. * . register indication of recurring/scheduled transaction. * . post-blue-line display * . instantiation of pre/post-blue-line scheduled transactions **/ // ----- /** * Scheduled transactions have a frequency defined by a frequency * specifier. This specifier, given a start date, end date [present * in the scheduled transaction] and last occurance date [possibly not * present] can be used to determine that a s.transaction should be * instantiated on a given date [the given query date]. * * Frequency specifiers have two query operators: one tests a given * date, the other computes the next date from a given previous or * start date. * * * This still needs to deal with: * . exceptions * . relative dates * . yearly 360/365? * . re-based frequencies [based around a non-standard [read: * not-Jan-1-based/fiscal] year] * . "business days" -- m-f sans holidays [per-user list thereof] * * . user interface... * **/ class FreqSpecifier { FrequencyType freq; union specData { /** * The dateAnchor anchors the spec to determinable days. * * ONCE: * dA[0] contains time_t * DAILY: * dA[0] contains day multiplier * WEEKLY: * dA[0] contains week multiplier * dA[1] contains 0..6 [sun-based] * SEMI_MONTHLY: * dA[0] contains month multiplier * dA[1] contains the first date-of-month, * dA[2] the second. * MONTHLY: * dA[0] contains month multiplier * dA[1] contains the date-of-month * MONTH_RELATIVE: * dA[0] continas month multiplier * dA[1] contains week number [1..5, 6=="last"] * [1..5 is really 1..4.428 [31/7], but it's a UI issue] * dA[2] contains 0..6 [sun-based day of week] * COMPOSITE: * ... list ... * RELATIVE: * ... don't know yet ... **/ time_t dateAnchor[3]; // a list of specs for a composite freq. GList *freqSpecs; }; time_t getNext( time_t start, time_t end, time_t previous = NULL ); bool dueP( time_t start, time_t end, time_t previous, time_t query ); }; /** * Examples * * Here we have a set of plain-text frequency recurrances, and how we * would represent them. * * every day * DAILY * every business day * <not yet:bdays> * or * <not yet:"mon-fri" as below + exceptions for holidays> * mon-fri * COMPOSITE * WEEKLY:mon * WEEKLY:tue * WEEKLY:wed * WEEKLY:thu * WEEKLY:fri * sat,sun * COMPOSITE * WEEKLY:sat * WEEKLY:sun * every <day-of-week> * WEEKLY:<day-of-week> * the second thursday of the month * MONTH_RELATIVE:2[2nd],4[thursday] * the last friday of the month * MONTH_RELATIVE:6[last],5[friday] * The 1st and the 17th * COMPOSITE: * MONTHLY:1 * MONTHLY:17 * The 15th and the last day of the month * COMPOSITE: * MONTHLY:15 * MONTHLY:32[last day] * every month on the 15th * MONTHLY:15 * the 4th monday after the beginning of ea. quarter * MONTHLY_RELATIVE[3]:4[4th],1[monday]; start:Jan * Jan-Jun-Dec on the 3rd [semi-yearly] * MONTHLY[6]:3,start:Jan * Every year on March 18th * MONTHLY[12]:18,starting on March 18th **/ _______________________________________________ gnucash-devel mailing list [EMAIL PROTECTED] http://www.gnumatic.com/cgi-bin/mailman/listinfo/gnucash-devel