I am working on an application that needs to handle expiring airline miles. The miles can be used, but if they are not used by a certain date, they will expire. I want to make sure I expire the proper amount of miles but don’t expire them if they have been used. Therefore, I have to check if enough miles have been used in a given date range before they expire. Here are my initial thoughts:
Have a miles table with the following columns:
- user_id – Foreign key to the users table
- number_miles – The number of miles for this record
- miles_type – Indicates if miles were added, used, or expired
- miles_expire – Boolean value to indicate if these miles expire or not
- miles_date – The date this record was added
- exipration_date – The date these miles expire (if the
miles_expireflag is true) - processed – Indicates if this record has been processed – only applicable when the
miles_typeis set to expire
If I have a record every time miles are added, used, or expired from a particular user account, I figure I can calculate the expired miles as such:
- For each user, get the dates of the records where the
miles_expireflag set to true, theexpiration_dateis before the current date, and theprocessedflag is set to false. This will get the records for all miles that should be expired. - Get the first and last
expiration_datefrom the previous query. - Using the first and last
expiration_datevalues from the previous step, get a list of all used miles within that date range. - If the sum of the used miles from the previous step is less than the sum of the expiring points, expire the difference. If the used miles are equal or greater, nothing has to be expired.
- Set the
processedflag to true for all records within the first and lastexpiration_daterange. Either these miles have been expired or ignored as they have been used.
It appears this meets the following requirements:
- Expiring miles are used first
- It will only check the used miles for the same time frame as the used miles so using many miles in the past won’t save future miles from expiring
- Miles are only expired after the date and won’t be if the user has used enough miles
Are there other considerations I need to take into account? Will this work to properly expire miles?
Your method won’t work for several reasons. The easiest to explain is probably this:
Note that this could be only one record. If you run your check very often, it will typically be only one record in fact. Let’s assume for simplicity that max one record expires each day (if more than one expires, your algorithm still fails, it’s just harder to explain).
You’ll get the same date here, because there’s only one record.
Since first and last are equal, there is no range and so there will never be used miles in that range.
Since the previous step returned no rows, the sum is zero, so you will always expire the difference between ‘expired miles’ and ‘0’. Even if the miles have been used.
This process will repeat.
Overall your design seems unnecessarily compilcated. I would just store a list of unused vouchers for each user. When they pay, vouchers used are marked as used. If a voucher is half used, it is marked as used and a new voucher is issued with the same expiration date, but with a smaller amount. If there are more vouchers than needed, soon to expire vouchers are used up first, and non-expiring vouchers are used last. Vouchers that have expired can never be used for payment, so you don’t need to do anything to expire them.
So in summary: you don’t need to expire any vouchers, just make sure the payment code does not allow usage of expired or used vouchers.