Implemented the period parser.
This commit is contained in:
		| @@ -18,6 +18,13 @@ | ||||
| """The utilities of the accounting application. | ||||
|  | ||||
| """ | ||||
| import re | ||||
| from datetime import date | ||||
|  | ||||
| from django.template import defaultfilters | ||||
| from django.utils import dateformat | ||||
| from django.utils.timezone import localdate, timedelta | ||||
| from django.utils.translation import pgettext, gettext | ||||
|  | ||||
|  | ||||
| class PeriodParser: | ||||
| @@ -27,14 +34,192 @@ class PeriodParser: | ||||
|         period_spec (str): The period specification. | ||||
|  | ||||
|     Attributes: | ||||
|         start (str): The start of the period. | ||||
|         end (str): The end of the period. | ||||
|         spec (str): The period specification. | ||||
|         start (date): The start of the period. | ||||
|         end (date): The end of the period. | ||||
|         description (str): The text description of the period. | ||||
|         error (str): The period specification format error, or | ||||
|                      None on success. | ||||
|     """ | ||||
|     spec = None | ||||
|     start = None | ||||
|     end = None | ||||
|     description = None | ||||
|     error = None | ||||
|  | ||||
|     def __init__(self, period_spec): | ||||
|         self.start = period_spec + "-01" | ||||
|         self.end = period_spec + "-30" | ||||
|         self.spec = period_spec | ||||
|         # A specific month | ||||
|         m = re.match("^([0-9]{4})-([0-9]{2})$", period_spec) | ||||
|         if m is not None: | ||||
|             try: | ||||
|                 year = int(m.group(1)) | ||||
|                 month = int(m.group(2)) | ||||
|                 self.set_month_range(year, month) | ||||
|                 self.description = self.get_month_description( | ||||
|                     year, month) | ||||
|             except ValueError: | ||||
|                 self.invalid_period() | ||||
|             return | ||||
|         # From a specific month | ||||
|         m = re.match("^([0-9]{4})-([0-9]{2})-$", period_spec) | ||||
|         if m is not None: | ||||
|             try: | ||||
|                 year = int(m.group(1)) | ||||
|                 month = int(m.group(2)) | ||||
|                 self.start = date(year, month, 1) | ||||
|                 self.end = self.get_month_last_day(localdate()) | ||||
|                 self.description = gettext( | ||||
|                     "Since %s") % self.get_month_description( | ||||
|                     year, month) | ||||
|             except ValueError: | ||||
|                 self.invalid_period() | ||||
|             return | ||||
|         # A specific year | ||||
|         m = re.match("^([0-9]{4})$", period_spec) | ||||
|         if m is not None: | ||||
|             try: | ||||
|                 year = int(m.group(1)) | ||||
|                 self.start = date(year, 1, 1) | ||||
|                 self.end = date(year, 12, 31) | ||||
|                 today = localdate() | ||||
|                 if year == today.year: | ||||
|                     self.description = gettext("This Year") | ||||
|                 elif year == today.year - 1: | ||||
|                     self.description = gettext("Last Year") | ||||
|                 else: | ||||
|                     self.description = str(year) | ||||
|             except ValueError: | ||||
|                 self.invalid_period() | ||||
|             return | ||||
|         # All time | ||||
|         if period_spec == "-": | ||||
|             self.start = date(2000, 1, 1) | ||||
|             self.end = self.get_month_last_day(localdate()) | ||||
|             self.description = gettext("All") | ||||
|             return | ||||
|         # A specific date | ||||
|         m = re.match("^([0-9]{4})-([0-9]{2})-([0-9]{2})$", | ||||
|                      period_spec) | ||||
|         if m is not None: | ||||
|             try: | ||||
|                 self.start = date( | ||||
|                     int(m.group(1)), int(m.group(2)), int(m.group(3))) | ||||
|                 self.end = self.start | ||||
|                 today = localdate() | ||||
|                 if self.start == today: | ||||
|                     self.description = gettext("Today") | ||||
|                 elif self.start == today - timedelta(days=1): | ||||
|                     self.description = gettext("Yesterday") | ||||
|                 elif self.start.year != today.year: | ||||
|                     self.description = defaultfilters.date( | ||||
|                         self.start, "Y/n/j") | ||||
|                 else: | ||||
|                     self.description = defaultfilters.date( | ||||
|                         self.start, "n/j") | ||||
|             except ValueError: | ||||
|                 self.invalid_period() | ||||
|             return | ||||
|         # A specific date period | ||||
|         m = re.match(("^([0-9]{4})-([0-9]{2})-([0-9]{2})" | ||||
|                       "-([0-9]{4})-([0-9]{2})-([0-9]{2})$"), | ||||
|                      period_spec) | ||||
|         if m is not None: | ||||
|             try: | ||||
|                 self.start = date( | ||||
|                     int(m.group(1)), int(m.group(2)), int(m.group(3))) | ||||
|                 self.end = date( | ||||
|                     int(m.group(4)), int(m.group(5)), int(m.group(6))) | ||||
|                 today = localdate() | ||||
|                 if self.start.year != self.end.year: | ||||
|                     self.description = "%s-%s" % ( | ||||
|                         defaultfilters.date(self.start, "Y/n/j"), | ||||
|                         defaultfilters.date(self.end, "Y/n/j")) | ||||
|                 elif self.start.month != self.end.month: | ||||
|                     if self.start.year != today.year: | ||||
|                         self.description = "%s-%s" % ( | ||||
|                             defaultfilters.date(self.start, "Y/n/j"), | ||||
|                             defaultfilters.date(self.end, "n/j")) | ||||
|                     else: | ||||
|                         self.description = "%s-%s" % ( | ||||
|                             defaultfilters.date(self.start, "n/j"), | ||||
|                             defaultfilters.date(self.end, "n/j")) | ||||
|                 else: | ||||
|                     if self.start.year != today.year: | ||||
|                         self.description = "%s-%s" % ( | ||||
|                             defaultfilters.date(self.start, "Y/n/j"), | ||||
|                             defaultfilters.date(self.end, "j")) | ||||
|                     else: | ||||
|                         self.description = "%s-%s" % ( | ||||
|                             defaultfilters.date(self.start, "n/j"), | ||||
|                             defaultfilters.date(self.end, "j")) | ||||
|             except ValueError: | ||||
|                 self.invalid_period() | ||||
|         # Wrong period format | ||||
|         self.invalid_period() | ||||
|  | ||||
|     def invalid_period(self): | ||||
|         """Sets the period when the period specification is invalid. | ||||
|         """ | ||||
|         self.error = pgettext("Accounting|", "Invalid period.") | ||||
|         today = localdate() | ||||
|         self.spec = dateformat.format(localdate(), "Y-m") | ||||
|         self.set_month_range(today.year, today.month) | ||||
|         self.description = gettext("This Month") | ||||
|  | ||||
|     def set_month_range(self, year, month): | ||||
|         """Calculates and returns the date range of a month. | ||||
|  | ||||
|         Args: | ||||
|             year (int): The year. | ||||
|             month (int): The month. | ||||
|  | ||||
|         Returns: | ||||
|             tuple(date): The date range of the month. | ||||
|  | ||||
|         Throws: | ||||
|             ValueError: When the year and month are invalid | ||||
|         """ | ||||
|         self.start = date(year, month, 1) | ||||
|         self.end = self.get_month_last_day(self.start) | ||||
|  | ||||
|     @staticmethod | ||||
|     def get_month_last_day(day): | ||||
|         """Calculates and returns the last day of a month. | ||||
|  | ||||
|         Args: | ||||
|             day (date): A day in the month. | ||||
|  | ||||
|         Returns: | ||||
|             date: The last day in the month | ||||
|         """ | ||||
|         next_month = day.month + 1 | ||||
|         next_year = day.year | ||||
|         if next_month > 12: | ||||
|             next_month = 1 | ||||
|             next_year = next_year + 1 | ||||
|         return date(next_year, next_month, 1) - timedelta(days=1) | ||||
|  | ||||
|     @staticmethod | ||||
|     def get_month_description(year, month): | ||||
|         """Returns the text description of a month. | ||||
|  | ||||
|         Args: | ||||
|             year (int): The year. | ||||
|             month (int): The month. | ||||
|  | ||||
|         Returns: | ||||
|             str: The description of the month | ||||
|         """ | ||||
|         today = localdate() | ||||
|         if year == today.year and month == today.month: | ||||
|             return gettext("This Month") | ||||
|         prev_month = today.month - 1 | ||||
|         prev_year = today.year | ||||
|         if prev_month < 1: | ||||
|             prev_month = 12 | ||||
|             prev_year = prev_year - 1 | ||||
|         prev = date(prev_year, prev_month, 1) | ||||
|         if year == prev.year and month == prev.month: | ||||
|             return gettext("Last Month") | ||||
|         return "%d/%d" % (year, month) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user