Beispiel #1
0
    def prep(self, private):
        # print 'prep', self.id, private
        cached = dict()
        def _node_data(_node):
            d = cached.get(_node)
            iscached = d is not None
            if not iscached:
                _upnodes = utils.tree_ups(_node)
                _itemcats = utils.tree_all_downs(utils.list_flatten(_upnodes, lambda enode: enode.itemcats.all()))
                d = dict(
                    upnodes = _upnodes,
                    itemcats = _itemcats,
                    items = ItemCat.els_get(_itemcats),
                )
                cached[_node] = d
            # print '_node_data cached', iscached, _node, d
            return d

        loc = self.loc
        user = loc.user
        formtypes, forms_ids, repdict_items_ids, repdict_usercats_ids = Form.get_forms_reps(
            baseuser = user,
            private = private,
            visit = self,
            usercats = user.cats.all(),
            loccats = loc.cats.all(),
            **_node_data(self.node)
        )
        addr = loc.addr()
        def _dt(datetime):
            return str(datetime) if datetime else ''
        dt = self.datetime
        v = dict(
            name = self.name,
            datetime = _dt(dt),
            end = _dt(utils.datetime_plus(dt, self.duration)),
            status = self.status,
            accompanied = self.accompanied,

            f_contact = self.f_contact,
            f_goal = self.f_goal,
            f_option = self.f_option,

            observations = self.observations,
            user_name = user.fullname(),
            user_email = user.email,
            user_cats = utils.db_names(user.cats),
            loc_name = loc.name,
            loc_address = '%s # %s, %s' % (addr.street, addr.unit, addr.area),
            formtypes = formtypes,
            forms = forms_ids,
            repdict_items = repdict_items_ids,
            repdict_usercats = repdict_usercats_ids,
            rec = self.rec_dict(),
        )
        # print 'prep', self, v
        return v
Beispiel #2
0
    def _generate(self):
        sys = Sys.objects.first()
        print '_generate', self, sys

        qn = [] # collection of multiple conds.

        def _qn_and_or(_qn, _isand):
            return _qn_and(_qn) if _isand else _qn_or(_qn)

        for cond in self.conds.all():
            eqn = cond.qn()
            if eqn:
                qn.append(_qn_and_or(eqn, not self.isand))

        if not qn: # not any ([ getattr(self, e).exists() for e in 'usercats loccats areas cities states countries zips bricks'.split() ])
            # raise ValidationError('Must select at least one condition for Users / Locs.')
            self.generate = False
            self.save()
            return # revert generate and ABORT, so we do NOT waste this builder.

        if qn:
            locs = Loc.objects.filter(_qn_and_or(qn, self.isand))
            # print 'query', locs.query
            locs = list(locs)
        else:
            locs = []

        def _sortkey(eloc):
            addr = eloc.addr()
            by = self.orderby
            def _val():
                v = addr.area
                if by == 'area': return v
                if by in [ 'zip', 'brick' ]:
                    v = v.zip
                    return v if by == 'zip' else v.brick
                v = v.city
                if by == 'city': return v
                v = v.state
                if by == 'state': return v
                v = v.country
                if by == 'country': return v
                error
            val = _val().name
            # print '_sortkey', by, val, eloc
            return val

        locs = sorted(locs, key=_sortkey)
        print 'locs', len(locs), locs

        pcats = utils.tree_all_downs(self.periodcats.all())
        pn1 = list(PeriodCat.els_get(pcats))
        pn2 = list(self.periods.all())
        pn = sorted(set(pn1 + pn2), key=lambda e: e.end)
        print 'pn', pn

        def _day(week, date):
            return getattr(week, utils.weekdays[date.weekday()])

        def _onoff(dt, week, sources, suffix):
            day = _day(week, dt)
            # print '_onoff', dt, week, day
            ok = False
            if day:
                dtdate = dt.date()
                dttime = dt.time()
                intime = False
                for time in day.times.all():
                    if dttime >= time.start and dttime <= time.end:
                        intime = True
                        break
                if intime:
                    sources = utils.list_compact(sources) # remove None's.
                    def _get(prefix, cmp2, checkdate):
                        xn = utils.list_flatten(sources, lambda e: getattr(e, prefix + suffix).all())
                        # print '_onoff._get', cmp2, xn
                        def _filter(e):
                            return cmp2 >= e.start and cmp2 <= e.end and (not e.date or e.date == dtdate if checkdate else True)
                        return utils.list_last(sorted(
                            [ e for e in xn if _filter(e) ],
                            key = lambda e: e.start,
                        ))
                    def _ison(pt):
                        return not pt or pt.on
                    operiod = _get('onoffperiod', dtdate, False)
                    if _ison(operiod):
                        otime = _get('onofftime', dttime, True)
                        if _ison(otime):
                            ok = True
            # if not ok: print '_onoff - FAILED', dt
            return ok

        with transaction.atomic():
            mgr = ForceVisit.objects
            self.qty_slots = 0
            self.qty_slots_skips = 0
            self.qty_locs = len(locs)
            self.qty_locs_skips = 0
            self.qty_node_skips = 0
            nodeskips = 0
            visits = []

            for ep in pn:
                start, end = ep.dates()
                qv = mgr.filter(datetime__range=(start, end)) # query within the current period (start - end).
                delta = end - start
                dates = [ start + datetime.timedelta(days=i) for i in range(delta.days + 1) ]
                week = ep.week or sys.week_period
                print '_generate > ep', ep, week, start, end # dates
                for edate in dates:
                    day = _day(week, edate)
                    print '_generate > edate', edate, day
                    if day:
                        def _datetime(_time): # can't use timedelta with simple times.
                            return datetime.datetime.combine(edate, _time)
                        for etime in day.times.all():
                            dt = _datetime(etime.start)
                            dt2 = _datetime(etime.end)
                            while dt < dt2:
                                self.qty_slots += 1
                                # print '_generate > slot', dt
                                user = self.node.user
                                ison = _onoff(
                                    dt,
                                    (user.week_visit if user else None) or sys.week_user_visit,
                                    [ user ],
                                    '_visit',
                                )
                                if ison:
                                    if qv.filter(node=self.node, datetime=dt).exists(): # visit already generated for the node in this time slot.
                                        self.qty_node_skips += 1
                                        print '_generate > qty_node_skips', dt, self.node
                                    else:

                                        # try (potentially multiple) locs for this specific time slot.
                                        tryloc = True
                                        locs2 = [] # queue for tried locs, which should be retried in the next time slot.
                                        while locs and tryloc:
                                            loc = locs.pop(0) if locs else None
                                            # print '_tryloc', dt, loc
                                            if loc:
                                                if qv.filter(loc=loc): # loc already visited during this period.
                                                    self.qty_locs_skips += 1
                                                    print '_generate > qty_locs_skips', dt, loc
                                                else:
                                                    ison = _onoff(
                                                        dt,
                                                        loc.week or loc.user.week_visited or sys.week_user_visited,
                                                        [ loc, loc.user ],
                                                        '_visited',
                                                    )
                                                    if ison:
                                                        visit = mgr.create(
                                                            builder = self,
                                                            node = self.node,
                                                            loc = loc,
                                                            datetime = dt,
                                                            duration = self.duration,
                                                        )
                                                        print '==> _generate > visit', dt, visit
                                                        visits.append(visit)
                                                        tryloc = False
                                                    else:
                                                        # print '_generate > SKIP VISITED (locs2 queue)', dt, loc
                                                        locs2.append(loc)
                                        locs[0:0] = locs2 # re-insert in order at the beginning, for immediate try during the subsequent time slots.

                                else:
                                    # print '_generate > SKIP VISIT', dt, user
                                    pass
                                dt = utils.datetime_plus(dt, self.duration, self.gap)
            self.qty_visits = len(visits)
            print 'done > generated visits & remaining locs', self.qty_visits, len(locs)
            self.save()