def createExpenseItemsForEvents(request=None, datetimeTuple=None, rule=None, event=None):
<EOL>submissionUser = getattr(request, '<STR_LIT:user>', None)<EOL>generate_count = <NUM_LIT:0><EOL>rule_filters = Q(disabled=False) & Q(rentalRate__gt=<NUM_LIT:0>) &Q(Q(staffmemberwageinfo__isnull=False) | Q(staffdefaultwage__isnull=False))<EOL>if rule:<EOL><INDENT>rule_filters = rule_filters & Q(id=rule.id)<EOL><DEDENT>rulesToCheck = RepeatedExpenseRule.objects.filter(<EOL>rule_filters).distinct().order_by(<EOL>'<STR_LIT>', '<STR_LIT>'<EOL>)<EOL>event_timefilters = Q()<EOL>if datetimeTuple and len(datetimeTuple) == <NUM_LIT:2>:<EOL><INDENT>timelist = list(datetimeTuple)<EOL>timelist.sort()<EOL>event_timefilters = event_timefilters & (<EOL>Q(event__startTime__gte=timelist[<NUM_LIT:0>]) & Q(event__startTime__lte=timelist[<NUM_LIT:1>])<EOL>)<EOL><DEDENT>if event:<EOL><INDENT>event_timefilters = event_timefilters & Q(event__id=event.id)<EOL><DEDENT>for rule in rulesToCheck:<EOL><INDENT>staffMember = getattr(rule, '<STR_LIT>', None)<EOL>staffCategory = getattr(rule, '<STR_LIT>', None)<EOL>if (<EOL>(not staffMember and not staffCategory) or<EOL>(<EOL>not staffMember and not<EOL>getConstant('<STR_LIT>')<EOL>)<EOL>):<EOL><INDENT>continue<EOL><DEDENT>replacements = {<EOL>'<STR_LIT:type>': _('<STR_LIT>'),<EOL>'<STR_LIT:to>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>}<EOL>expense_category = getConstant('<STR_LIT>')<EOL>if staffCategory:<EOL><INDENT>if staffMember:<EOL><INDENT>eventstaff_filter = Q(staffMember=staffMember) & Q(category=staffCategory)<EOL><DEDENT>elif getConstant('<STR_LIT>'):<EOL><INDENT>eventstaff_filter = (<EOL>Q(category=staffCategory) &<EOL>~Q(staffMember__expenserules__category=staffCategory)<EOL>)<EOL><DEDENT>replacements['<STR_LIT:type>'] = staffCategory.name<EOL>if staffCategory == getConstant('<STR_LIT>'):<EOL><INDENT>expense_category = getConstant('<STR_LIT>')<EOL><DEDENT>elif staffCategory in [<EOL>getConstant('<STR_LIT>'),<EOL>getConstant('<STR_LIT>')<EOL>]:<EOL><INDENT>expense_category = getConstant('<STR_LIT>')<EOL><DEDENT><DEDENT>else:<EOL><INDENT>coveredCategories = list(staffMember.expenserules.filter(<EOL>category__isnull=False).values_list('<STR_LIT>', flat=True))<EOL>eventstaff_filter = Q(staffMember=staffMember) & ~Q(category__id__in=coveredCategories)<EOL><DEDENT>if rule.advanceDays is not None:<EOL><INDENT>if rule.advanceDaysReference == RepeatedExpenseRule.MilestoneChoices.end:<EOL><INDENT>event_timefilters = event_timefilters & Q(<EOL>event__endTime__lte=timezone.now() + timedelta(days=rule.advanceDays)<EOL>)<EOL><DEDENT>elif rule.advanceDaysReference == RepeatedExpenseRule.MilestoneChoices.start:<EOL><INDENT>event_timefilters = event_timefilters & Q(<EOL>event__startTime__lte=timezone.now() + timedelta(days=rule.advanceDays)<EOL>)<EOL><DEDENT><DEDENT>if rule.priorDays is not None:<EOL><INDENT>if rule.priorDaysReference == RepeatedExpenseRule.MilestoneChoices.end:<EOL><INDENT>event_timefilters = event_timefilters & Q(<EOL>event__endTime__gte=timezone.now() - timedelta(days=rule.priorDays)<EOL>)<EOL><DEDENT>elif rule.priorDaysReference == RepeatedExpenseRule.MilestoneChoices.start:<EOL><INDENT>event_timefilters = event_timefilters & Q(<EOL>event__startTime__gte=timezone.now() - timedelta(days=rule.priorDays)<EOL>)<EOL><DEDENT><DEDENT>if rule.startDate:<EOL><INDENT>event_timefilters = event_timefilters & Q(event__startTime__gte=timezone.now().replace(<EOL>year=rule.startDate.year, month=rule.startDate.month, day=rule.startDate.day,<EOL>hour=<NUM_LIT:0>, minute=<NUM_LIT:0>, second=<NUM_LIT:0>, microsecond=<NUM_LIT:0>,<EOL>))<EOL><DEDENT>if rule.endDate:<EOL><INDENT>event_timefilters = event_timefilters & Q(event__startTime__lte=timezone.now().replace(<EOL>year=rule.endDate.year, month=rule.endDate.month, day=rule.endDate.day,<EOL>hour=<NUM_LIT:0>, minute=<NUM_LIT:0>, second=<NUM_LIT:0>, microsecond=<NUM_LIT:0>,<EOL>))<EOL><DEDENT>staffers = EventStaffMember.objects.filter(eventstaff_filter & event_timefilters).exclude(<EOL>Q(event__expenseitem__expenseRule=rule)).distinct()<EOL>if rule.applyRateRule == rule.RateRuleChoices.hourly:<EOL><INDENT>for staffer in staffers:<EOL><INDENT>replacements['<STR_LIT>'] = staffer.event.name<EOL>replacements['<STR_LIT:name>'] = staffer.staffMember.fullName<EOL>replacements['<STR_LIT>'] = staffer.event.startTime.strftime('<STR_LIT>')<EOL>if (<EOL>staffer.event.startTime.strftime('<STR_LIT>') !=<EOL>staffer.event.endTime.strftime('<STR_LIT>')<EOL>):<EOL><INDENT>replacements['<STR_LIT>'] += '<STR_LIT>' % (<EOL>_('<STR_LIT:to>'), staffer.event.endTime.strftime('<STR_LIT>')<EOL>)<EOL><DEDENT>staffer_party = TransactionParty.objects.get_or_create(<EOL>staffMember=staffer.staffMember,<EOL>defaults={<EOL>'<STR_LIT:name>': staffer.staffMember.fullName,<EOL>'<STR_LIT:user>': getattr(staffer.staffMember, '<STR_LIT>', None)<EOL>}<EOL>)[<NUM_LIT:0>]<EOL>params = {<EOL>'<STR_LIT>': staffer.event,<EOL>'<STR_LIT>': expense_category,<EOL>'<STR_LIT>': rule,<EOL>'<STR_LIT:description>': '<STR_LIT>' %replacements,<EOL>'<STR_LIT>': submissionUser,<EOL>'<STR_LIT>': staffer.netHours,<EOL>'<STR_LIT>': rule.rentalRate,<EOL>'<STR_LIT>': staffer.netHours * rule.rentalRate,<EOL>'<STR_LIT>': staffer.event.startTime,<EOL>'<STR_LIT>': staffer_party,<EOL>}<EOL>ExpenseItem.objects.create(**params)<EOL>generate_count += <NUM_LIT:1><EOL><DEDENT><DEDENT>else:<EOL><INDENT>members = StaffMember.objects.filter(eventstaffmember__in=staffers)<EOL>for member in members:<EOL><INDENT>events = [x.event for x in staffers.filter(staffMember=member)]<EOL>staffer_party = TransactionParty.objects.get_or_create(<EOL>staffMember=member,<EOL>defaults={<EOL>'<STR_LIT:name>': member.fullName,<EOL>'<STR_LIT:user>': getattr(member, '<STR_LIT>', None)<EOL>}<EOL>)[<NUM_LIT:0>]<EOL>intervals = [<EOL>(x.localStartTime, x.localEndTime) for x in<EOL>EventOccurrence.objects.filter(event__in=events)<EOL>]<EOL>remaining_intervals = rule.getWindowsAndTotals(intervals)<EOL>for startTime, endTime, total, description in remaining_intervals:<EOL><INDENT>replacements['<STR_LIT>'] = description<EOL>replacements['<STR_LIT:name>'] = member.fullName<EOL>params = {<EOL>'<STR_LIT>': expense_category,<EOL>'<STR_LIT>': rule,<EOL>'<STR_LIT>': startTime,<EOL>'<STR_LIT>': endTime,<EOL>'<STR_LIT:description>': '<STR_LIT>' % replacements,<EOL>'<STR_LIT>': submissionUser,<EOL>'<STR_LIT>': total,<EOL>'<STR_LIT>': startTime,<EOL>'<STR_LIT>': staffer_party,<EOL>}<EOL>ExpenseItem.objects.create(**params)<EOL>generate_count += <NUM_LIT:1><EOL><DEDENT><DEDENT><DEDENT><DEDENT>rulesToCheck.update(lastRun=timezone.now())<EOL>return generate_count<EOL>
For each StaffMember-related Repeated Expense Rule, look for EventStaffMember
instances in the designated time window that do not already have expenses associated
with them.  For hourly rental expenses, then generate new expenses that are
associated with this rule.  For non-hourly expenses, generate new expenses
based on the non-overlapping intervals of days, weeks or months for which
there is not already an ExpenseItem associated with the rule in question.