Opt-in vs. Opt-out?

It has been pretty quiet on the development front.  Now that swim team season is in full gear, I am spending a bunch of time actually using what I have developed to date.  So far, everything is working pretty well although I definitely have some things to do.

Next on the agenda is an online scratch sheet which I will likely implement as a an opt-in or opt-out feature on a meet.  Some meets make more sense to opt out of where as others make more sense to opt in. For example, our regular season meets will be opt-out meets.  All swimmers are assumed to be participating unless they opt out.  On the other hand, our local city meet which we only have 25-30 swimmers entered in, will be an opt-in meet.  All swimmers will assumed to be not participating unless they opt in.  I believe supporting both makes the most sense and will ultimately make the system work better.  Forunately this should be a pretty simple extension to the meet functionality I implemented a few weeks ago.

Fixed Assign Label Bug

I just committed a pretty important fix to address a bug in the Assign Label function.  If a label is manually assigned, the swimmer would be marked as Inactive on the master swimmer list which is incorrect.  This was a leftover artifact from reusing the Unregister code.  It has been fixed and now swimmers are  propertly labeled AND if Swimmer Label field is properly initialized with an existing value if there one (which wasn’t happening either).

The other thing I ran into as a result of running our Time Trials last night is the need for a confirmation on the “Assign Labels” functionality as it will re-assign all the swimmer labels which may not be the desired state as it was in my case last night.  Fortunately only 2-3 new swimmers had been added to the database since I had assigned labels so manually fixing them wasn’t too much work but I’d rather not have done it at all.

Swim Meets and Swim Club Profiles

Over the last couple of days, actually since I flew home from Paris on Friday, I have added functionality to set up a swim season schedule.  To do this, I added swim club profiles and swim meets.  The swim meet functionality also includes a summary which is added to the overview page.  The summary reports the schedule for the current season, results. and lcation of the meets.

Adding swim meets is base functionality which is necessary to support online scratch sheets (need to know which meet a swimmer is scratching from) and ultimately results.  The online scratch will probably be the next thing I implement, results are a bit trickly because loading, parsing, and connecting results to swim meets and swimmers will be a fairly extensive problem.  I suspect I won’t have this working until after our season completes but you never know!

I also want to go back and visit the Team Profile functionality.  I am storing the Team Profile in the WordPress options table but now that I have Swim Club Profiles, there isn’t any reason to store the Team Profile any differently than any other Swim Club.  It isn’t urgent so I may defer that as well.

Lastly, I need to make changes to many of the classes to allow some of the methods to be called without needing a class variable first (the class::method() format).  For example – I should be able to call SwimTeamSwimmer::getAllSwimmerIds() and return an array of SwimmerIds without declaring a class variable first but right now I can’t due to the way I constructed the base level database query class.  There are a number of places where this would be really handy.

Swimmer Numbers? Swimmer Labels?

I have spent a fair amount of time this week implementing what I am now calling Swimmer Labels.  I may go back to Swimmer Numbers but I am not sure.  I’d like to call them Swimmer Ids but I have used that terminology all through the plugin for the unique MySQL record id field that changing it would be a pretty sizable task.

On the good news front, I have auto-assigment of Swimmer Labels working under several different scenarios.  I am particularly pleased with the auto-assignment of labels within an age group with a prefix – it is pretty slick if I do say so myself.  Since the MacDolphins use this format, it was particularly important to me!

Enhancement List!

My wife gave me a list of all of the things she’d like to be able to do the other day.  None were a real surprise and I hope to get some of them implemented this week.  Probably the hardest one will be to do an online scratch list because I need to finish the Meet Module first since scratching is dependent on having a swim meet to scratch from.

CSV Export Enhanced

It is somewhat duplication of the Report Generator functionality but I went ahead and enhanced the CSV Roster Export to include the age, adjusted age, and the age group assignment.  With the clean up of the age group calculation, the information is now readily available any time a swimmer record is queried.  As such, the age and age group now appear on the detail profiled as well as a couple other places.

Finally fixed age calculation

Over the weekend I was speaking with one of the swim team parents who was asking me about our web site and I showed her what she could see about her daughter.  As soon as I popped her daugher’s information she noticed that she was placed in the wrong age group.  Oops.

I had seen this situation previously but couldn’t pin it down but now that I had a swimmer I could test against, I dug into it.  It turns out that I had made the age calculation much, much, harder than it really needed to be.  And it was wrong.

I was trying to use MySQL’s PERIOD_DIFF() function so the age and cutoff date adjusted age would be returned as part of the query.  It turns out that PERIOD_DIFF() only accounts for months (which I knew when I used it) but not taking into account the days causes the calculation to be wrong and limits the age cutoff date to be the first  of a month which may or may not be acceptable.

My first search yielded this example which turns out to be wrong as it doesn’t always return the correct age.

Here is the correct SQL to calculate age:

SELECT YEAR(birthdate) - (MONTH(CURRENT_DATE()) < MONTH(birthdate)) -
    ((MONTH(CURRENT_DATE()) = MONTH(birthdate)) & (DAY(CURRENT_DATE()) <
    DAY(birthdate))) AS age 

Here is the correct SQL to calcualte age based on a specific cutoff date, in this case the cutoff date is June 1st:

SELECT YEAR(CURRENT_DATE()) - YEAR(birthdate) - (MONTH('2008-06-01') <
    MONTH(birthdate)) - ((MONTH('2008-06-01') = MONTH(birthdate)) &
    (DAY('2008-06-01') <= DAY(birthdate))) AS agegroupage

By using the calculations, the swimmer’s age and age group age are always returned with the query as opposed to computed on the fly.

Report Generator

I have started working on a report generator for the plugin.  The report generator will allow an administrator to run reports for the swim team with control over what is included in the report as well as the ability to apply filters.  The report can be generated as either a web page (table) or as a CSV download which could then be loaded into Excel.  For the most part I have completed the GUI, now I need to actually generate the report.

Fixes to SDIF, Age calculation, and other stuff

It has been a pretty hectic week for Swim Team and as such, I have found some bugs and some minor annoyances and tried to fix most of them.  The most serious bug was in the SDIF export which I was working with one of our coaches on so he could started working with WinSwim with our roster.  If the parent profile wasn’t entered, the last last profile found was being used to construct the D1 and D2 records.  Now when a parent profile record isn’t found, it reverts to the site admin’s record to populate the data.

I also switched a bunch of the swimmer lists (roster, all swimmers) back to sorting by last name because that is how the data is usually looked at.  I also fixed a bug in the age computation which was rather elusive – it only appeared once in a while.  It turns out the logic was wrong in an age computation function I had grabbed off a PHP site a while back.  Lastly, I made progress on the swimmer id/number/label but am not yet computing them.  I think all of the infrastructure for them is down now.