예제 #1
0
    def __repr__(self):
        fromto = {True: 'from', False: 'to'}[self.amount > 0]
        if self.ttype.mem_sup == 'memb':
            partner = ascii_save(self.member.fullname)
        elif self.ttype.mem_sup == 'whol':
            partner = ascii_save(self.wholesaler.wh_name)
        elif self.ttype.mem_sup == 'vers':
            partner = ascii_save(self.vers_supplier.name)
        else:
            partner = 'Other'

        return "EUR {} {} {} [{}]".format(round(self.amount, 2), fromto,
                                          partner, self.ttype)
예제 #2
0
 def __repr__(self):
     mname = '<not assigned yet>'
     if self.member:
         mname = ascii_save(self.member.fullname)
     return "[Shift '{}' on day '{}', in month {}/{}, "\
            "by member {} in the '{}'-group (state:{})]"\
             .format(self.task, str(self.day), self.month, self.year, 
                     mname, self.workgroup.name, self.state)
예제 #3
0
 def mail_old_assignee():
     # send old assignee an email
     if old_member and not self.user == old_member:
         subject = 'You have been signed out of a shift.'
         body = 'Hi,\n\n{} has signed you off a shift that '\
                'you were previously assigned to.\nThe shift is '\
                'now:\n\n{}\n\nYou can view the shift '\
                'schedule at {}.\n{}'.format(
                 ascii_save(self.user.fullname), shift,
                 schedule_url, q)
         sendmail(old_member.mem_email,
                  subject,
                  body,
                  folder='shifts')
예제 #4
0
    def __call__(self):
        db_session = DBSession()
        params = self.request.params
        wg_id = self.request.matchdict['wg_id']
        wg = get_wg(db_session, self.request)
        if not wg.active:
            return self.redir_to_shiftlist(
                wg, int(params['year']), int(params['month']),
                'This workgroup is inactive, no new shifts can be added.')

        if not 'people' in params:
            people = 1
        else:
            people = int(params['people'])
        self.added_shifts = []

        def add_shift(month=None, year=None):
            ''' add a shift object to session, several times if people > 1 '''
            shift = Shift(wg_id, '', None, None, None, None)
            shift.workgroup = DBSession().query(Workgroup).get(wg_id)
            shift = fill_shift_from_request(shift, self.request)
            shift.validate()
            db_session.add(shift)
            self.added_shifts.append(shift)
            if month:
                shift.month = month
            if year:
                shift.year = year
            if people > 1:
                for _ in range(1, people):
                    s = shift.clone()
                    s.workgroup = DBSession().query(Workgroup).get(s.wg_id)
                    s.validate()
                    db_session.add(s)
                    self.added_shifts.append(s)

        day = params['day']
        if not str(day).isdigit():
            day = 1
        else:
            day = int(day)
        sdate = datetime.datetime(int(params['year']), int(params['month']),
                                  day)
        if not 'repeat' in params:
            repeat = 'once'
        else:
            repeat = params['repeat']
        if repeat == 'once':
            add_shift()
        else:
            udate = datetime.datetime(int(params['until_year']),
                                      int(params['until_month']), day)
            if repeat in ('monthly', 'bi-monthly-startnow',
                          'bi-monthly-startnext'):
                for year in range(sdate.year, udate.year + 1):
                    smonth = 1
                    if year == sdate.year:
                        smonth = sdate.month
                    umonth = 12
                    if year == udate.year:
                        umonth = udate.month
                    step = 1
                    if repeat.startswith('bi-monthly'):
                        step = 2
                    if repeat == 'bi-monthly-startnext':
                        smonth += 1
                    for month in range(smonth, umonth + 1, step):
                        add_shift(month, year)
                if len(self.added_shifts) == 0:
                    return self.redir_to_shiftlist(
                        wg, sdate.year, sdate.month,
                        "Invalid date range: {}/{} to {}/{}".format(
                            sdate.month, sdate.year, udate.month, udate.year))
            else:
                return self.redir_to_shiftlist(
                    wg, sdate.year, sdate.month,
                    'Could not create shifts. "repeat"-command unknown.')
        # inform (other) coordinators
        subject = "Workgroup {}: Shifts were created by {}"\
                    .format(ascii_save(wg.name), ascii_save(self.user.fullname))
        body = "These shifts were added:\n\n{}\n\nBest, Vokomokum"\
                .format('\n'.join([str(s) for s in self.added_shifts]))
        for c in wg.leaders:
            if c is not self.user:
                sendmail(c.mem_email, subject, body, folder='shifts')
        return self.redir_to_shiftlist(wg, sdate.year, sdate.month,
                    'Succesfully added {} shift(s) for task "{}".'\
                    .format(len(self.added_shifts),
                            ascii_save(self.request.params['task'])))
예제 #5
0
    def __call__(self):
        db_session = DBSession()
        wg = get_wg(db_session, self.request)
        if not wg:
            raise Exception(
                "Don't know which workgroup this is supposed to be.")

        shift = get_shift(db_session, self.request)
        if not shift:
            raise Exception("No shift with id %d" %
                            self.request.matchdict['s_id'])

        def redir(msg):
            return self.redir_to_shiftlist(wg, shift.year, shift.month, msg)

        if not wg.active:
            return redir(
                'Workgroup is inactive, editing shifts therefore not possible.'
            )

        action = self.request.matchdict['action']
        if action == "":
            raise Exception('No action given.')

        if action == "setmember":
            if not 'mem_id' in self.request.params:
                return redir('No member selected.')
            if not self.user in wg.members and not self.user.mem_admin:
                return redir(
                    'You are not allowed to assign shifts in this workgroup.')
            if self.request.params['mem_id'] == '--':
                member = None
            else:
                member = get_member(db_session, self.request)

            # prepare some things for mailing
            schedule_url = '{}/workgroup/{}/shifts/{}/{}'.format(
                self.request.application_url, shift.workgroup.id, shift.year,
                shift.month)
            q = 'This email was automatically generated, so please do not '\
                'directly reply to it. You may direct any questions regarding '\
                'the workgroup to your coordinator(s). Only technical questions '\
                'go to [email protected].'\
                '\n\nBest,\nVokomokum'
            old_member = shift.member

            def mail_old_assignee():
                # send old assignee an email
                if old_member and not self.user == old_member:
                    subject = 'You have been signed out of a shift.'
                    body = 'Hi,\n\n{} has signed you off a shift that '\
                           'you were previously assigned to.\nThe shift is '\
                           'now:\n\n{}\n\nYou can view the shift '\
                           'schedule at {}.\n{}'.format(
                            ascii_save(self.user.fullname), shift,
                            schedule_url, q)
                    sendmail(old_member.mem_email,
                             subject,
                             body,
                             folder='shifts')

            if member:
                shift.member = member
                shift.state = 'assigned'
                shift.validate()
                if not self.user == member:
                    # send new assignee an email
                    subject = 'You have been assigned to a shift.'
                    body = 'Hi,\n\n{} has assigned you to a shift: '\
                           '\n\n{}\n\nYou can view the shift schedule at {}'\
                           '\n\n{}'.format(ascii_save(self.user.fullname),
                            str(shift), schedule_url, q)
                    sendmail(member.mem_email, subject, body, folder='shifts')
                # let coordinator(s) know, as well
                subject = "Workgroup {}: The shift for {} on day '{}' in "\
                          "{}/{} is now assigned to {}".format(shift.workgroup,
                           shift.task, shift.day, shift.month, shift.year,
                           ascii_save(shift.member.fullname))
                body = "The assignment was done by member {}."\
                            .format(ascii_save(self.user.fullname))
                if old_member:
                    body += " The previous assignee was: {}."\
                            .format(ascii_save(old_member.fullname))
                else:
                    body += " No one was assigned to this shift before."
                body += "\n\n{}".format(q)
                for c in wg.leaders:
                    if c is not self.user:
                        sendmail(c.mem_email, subject, body, folder='shifts')
                # and inform previous assignee
                mail_old_assignee()
                name = ascii_save(shift.member.fullname)
                return redir(u'{} has been signed up for the shift.'\
                             .format(name))
            else:
                if shift.is_locked and not self.user in wg.leaders\
                                   and not self.user.mem_admin:
                    return redir(
                        'Shift is already locked. Ask your workgroup admin for help.'
                    )
                shift.member = None
                shift.state = 'open'
                shift.validate()
                mail_old_assignee()
                # let coordinator(s) know, as well
                subject = "Workgroup {}: Member {} was unassigned from the "\
                          "shift for {} on day '{}' in {}/{}"\
                           .format(shift.workgroup,
                           ascii_save(old_member.fullname),
                           shift.task, shift.day, shift.month, shift.year)
                body = "The un-assignment was done by member {}."\
                            .format(ascii_save(self.user.fullname))
                body += "\n\n{}".format(q)
                for c in wg.leaders:
                    if c is not self.user:
                        sendmail(c.mem_email, subject, body, folder='shifts')
                return redir('Shift is now open.')
            return redir('You are not allowed to do this.')

        elif action == "settask":
            if self.user in wg.leaders or self.user.mem_admin:
                if not 'task' in self.request.params:
                    return dict(msg='No task given.')
                shift.task = self.request.params['task']
                shift.validate()
                return redir('Changed task of shift.')
            return redir('You are not allowed to edit the task.')

        elif action == "setday":
            if self.user in wg.leaders or self.user.mem_admin:
                if not 'day' in self.request.params:
                    return dict(msg='No day given.')
                shift.day = self.request.params['day']
                shift.validate()
                return redir('Changed day of shift to {}.'.format(shift.day))
            return redir('You are not allowed to set the day.')

        elif action == "setstate":
            if self.user in wg.leaders or self.user.mem_admin:
                if not 'state' in self.request.params:
                    return redir('No state given.')
                shift.state = self.request.params['state']
                shift.validate()
                return redir('Changed shift state to {}.'.format(shift.state))
            return redir('You are not allowed to set the state.')

        elif action == 'delete':
            if self.user in wg.leaders or self.user.mem_admin:
                db_session.delete(shift)
                return redir('Deleted shift.')
            return redir('You are not allowed to delete a shift.')
예제 #6
0
    def __call__(self):
        '''
        Create order charges for a given order in the system
        '''
        o_id = int(self.request.matchdict['o_id'])
        session = DBSession()
        order = session.query(Order).\
                filter(Order.id == o_id).first()
        if not order:
            return dict(msg='An order with ID {} does not exist.'.format(o_id),
                        order=None, action=None)
        charge_ttype_id = get_ttypeid_by_name('Order Charge')

        if not 'Finance' in [wg.name for wg in self.user.workgroups]\
            and not self.user.mem_admin:
            return dict(order=order, action=None, 
                        msg='Only Finance people can do this.')
        # all (positive) charges for members who have not been charged for 
        # this order yet
        charges = [MemberOrder(m, order) for m in session.query(Member).all()]
        charges = [c for c in charges if c.amount > 0 and not o_id in\
                                [t.order.id for t in c.member.transactions\
                                            if t.ttype_id == charge_ttype_id]]
        first_orderers = []

        if not 'action' in self.request.params:
            # show charges that would be made
            return dict(order=order, action='show', charges=charges)
        else:
            # temporary backdoor to test this
            if self.request.params['action'] == 'gggraph':
                orders_money_and_people()
            if self.request.params['action'] == 'charge':
                # confirmation: make charges
                for c in charges:
                    t = Transaction(amount = -1 * c.amount,
                        comment = 'Automatically charged.' 
                    )
                    ttype = session.query(TransactionType)\
                                   .get(charge_ttype_id)
                    t.ttype = ttype
                    t.member = c.member
                    t.order = c.order
                    t.validate()
                    session.add(t)
                    # first order of this member? Charge Membership fee
                    if c.is_first_order():
                        first_orderers.append(c.member)
                        mf = Transaction(\
                                amount = membership_fee(c.member) * -1,
                                comment = 'Automatically charged (for {}'\
                                ' people in the household) on first-time'\
                                ' order ({})'\
                                .format(c.member.mem_household_size,
                                        c.order.label)
                        )
                        ttype = session.query(TransactionType)\
                                    .get(get_ttypeid_by_name('Membership Fee'))
                        mf.ttype = ttype
                        mf.member = c.member
                        mf.validate()
                        session.add(mf)
                # use this opportunity to update graph data
                orders_money_and_people()
                # inform membership about people who ordered for first time
                subject = 'First-time orderers'
                body = 'FYI: Below is a list of people who ordered for the'\
                       ' first time today. This mail was auto-generated.\n\n'
                body += '\n'.join(['{} [ID:{}]'.format(ascii_save(m.fullname), m.mem_id)\
                                  for m in first_orderers])
                sendmail('*****@*****.**', subject, body,
                        folder='order-charges/{}'.format(o_id),
                        sender='*****@*****.**')

                return dict(order=order, action='done')
        return dict(order=order, action='')
예제 #7
0
def get_todos(session, user, show_all):
    '''
    Go through a list of cases to find current TODOs for this user.
    If show_all is true, find all TODOs system-wide
    '''
    todos = []
    workgroups = session.query(Workgroup).all()
    all_members = session.query(Member).all()
    act_members = [m for m in all_members if m.mem_active]
    now = datetime.datetime.now()
    settings = get_settings()

    def df(i):
        return str(i).rjust(2, '0')

    # ---- Todos for every user:
    # negative balance
     
    if user.balance < 0 and settings.get("vokomokum.warn_on_negative_balance", "true") == "true":
        todos.append(Todo(msg='You have a negative balance of {}.'\
                             .format(round(user.balance, 2)),
                          wg='Finance',
                          link_act='member/{}'.format(user.mem_id),
                          link_txt='See the transaction list on your profile.',
                          link_title='You should transfer the missing amount.'))
    # shift user is assigned to
    ass_shifts = session.query(Shift)\
                        .filter(Shift.mem_id == user.mem_id)\
                        .filter(Shift.state == 'assigned')\
                        .order_by(Shift.year, Shift.month).all()
    for s in ass_shifts:
        todos.append(Todo(msg='You are assigned for a shift in "{}" on ({}) '\
                              'in {}/{}.'.format(s.workgroup, 
                                            s.day and s.day or 'any day',
                                            df(s.month), df(s.year)),
                              wg=s.workgroup.name,
                              link_act='workgroup/{}/shifts/{}/{}'\
                                            .format(s.wg_id, s.year, s.month),
                              link_txt='Shift schedule.',
                              link_title="Don't forget :)"))

    # ---- Workgroup Finance:
    if 'Finance' in [w.name for w in user.workgroups] or show_all:
        if settings.get("vokomokum.warn_on_negative_balance", "true") == "true":
            for m in [m for m in all_members if m.balance < 0]:
                todos.append(Todo(msg='Member {} has a negative balance of EUR {}.'\
                                    .format(ascii_save(m.fullname),
                                            round(m.balance, 2)),
                                wg='Finance',
                                link_act='member/{}'.format(m.mem_id),
                                link_txt='See member profile.',
                                link_title='You should contact the member and '\
                                    'tell them to transfer the missing amount.'))
   
        nov12 = datetime.datetime(2012, 11, 1)
        orders = session.query(Order).order_by(desc(Order.completed)).all()
        new_orders = [o for o in orders if str(o.completed) != ''\
                                        and str(o.completed) > str(nov12)]
        for no in new_orders:
            charges_made = session.query(Transaction)\
                                .filter(Transaction.ord_no == no.id).count()
            if charges_made == 0:
                todos.append(Todo(msg='Order "{}" has yet to be charged.'\
                                       .format(no.label),
                                  wg='Finance',
                                  link_act='charge-order/{}'.format(no.id),
                                  link_txt='Charge members now.',
                                  link_title='There have been no charges made '\
                                    'for this order to members. Clicking this '\
                                    'link will show you a list of charges '\
                                    'that should be made and you can then '\
                                    'confirm to actually make them.'))
            else:
                settings = get_settings()
                order_mail_folder = '{}/order-charges/{}'\
                        .format(settings['vokomokum.mail_folder'], no.id)
                # we might have already sent a mail about firt-time orderers
                if not os.path.exists(order_mail_folder)\
                   or len(os.listdir(order_mail_folder)) <= 1:
                    todos.append(Todo(msg='Members have not gotten mail about '\
                                          'charges for order "{}".'.format(no.label),
                                  wg='Finance',
                                  link_act='mail-order-charges/{}'.format(no.id),
                                  link_txt='Email members now.',
                                  link_title='There have been charges made '\
                                    'for this order to members. If these charges seem '\
                                    'to be correct, you can inform them what they '\
                                    'should pay.'))


    # ---- Workgroup Membership:
    if 'Membership' in [w.name for w in user.workgroups] or show_all:
        # Members without a workgroup
        for m in [am for am in act_members if len(am.workgroups) == 0\
                  or ('new members' in [wg.name.lower() for wg in am.workgroups]\
                      and len(am.workgroups) == 1)]:
            # check if they ordered
            mt = session.query(Transaction)\
                .filter(Transaction.mem_id == m.mem_id)\
                .filter(Transaction.ttype_id == \
                        get_ttypeid_by_name('Order Charge')).first()
            if mt:
                todos.append(Todo(msg='Member {} has ordered but is still '\
                                      'without a workgroup.'\
                                      .format(ascii_save(m.fullname)),
                                  wg='Membership',
                                  link_act='member/{}'.format(m.mem_id),
                                  link_txt='See member profile.',
                                  link_title='You should contact the member and '\
                                   'discuss which openings he/she would '\
                                   'like. If they refuse, inactivate him/her.'))
   
        # Workgroups lacking members
        for wg in workgroups:
            if wg.required_members > wg.headcount:
                todos.append(Todo(msg='Workgroup {} needs {} more member(s).'\
                                      .format(wg.name, wg.required_members - wg.headcount),
                                wg='Membership',
                                link_act='workgroup/{}'.format(wg.id),
                                link_txt='See workgroup profile.',
                                link_title='You should contact the coordinators '\
                                           'in order to reduce the amount of '\
                                           'required members or assign more members '\
                                           'to the group.'))
    # ---- Todos for coordinators in general:
    # unfilled shifts
    wgs = user.led_workgroups
    if show_all:
        wgs = session.query(Workgroup).all()
    for wg in wgs:
        open_shifts = session.query(Shift)\
                             .filter(Shift.wg_id == wg.id)\
                             .filter(Shift.state == 'open')\
                             .order_by(Shift.year, Shift.month).all()
        for s in open_shifts: 
            todos.append(Todo(msg='Open shift in group "{}" in {}/{}.'\
                                  .format(s.workgroup, df(s.month), df(s.year)),
                              wg=s.workgroup,
                              link_act='workgroup/{}/shifts/{}/{}'\
                                  .format(s.wg_id, df(s.year), df(s.month)),
                              link_txt='Shift schedule.',
                              link_title='Go to the shift schedule and sign '\
                                       'someone up, or mail group members .'\
                                       'to find a volunteer.'))

        # shifts to check upon
        ass_shifts = session.query(Shift)\
                            .filter(Shift.wg_id == wg.id)\
                            .filter(Shift.state == 'assigned')\
                            .order_by(Shift.year, Shift.month).all()
        for s in [s for s in ass_shifts\
                  if s.month < now.month or s.year < now.year]:
            todos.append(Todo(msg='Group "{}": Please write off shift by {} ({}), '\
                                  'in {}/{}.'.format(s.workgroup, 
                                        ascii_save(s.member.fullname), 
                                        s.day and s.day or 'any day',
                                        df(s.month), df(s.year)),
                              wg=s.workgroup.name,
                              link_act='workgroup/{}/shifts/{}/{}'\
                                            .format(s.wg_id, s.year, s.month),
                              link_txt='Shift schedule.',
                              link_title='Go to the shift schedule and put '\
                                  'the shift in "worked" or "no-show" mode.'))
        
    return todos