コード例 #1
0
ファイル: csvimport.py プロジェクト: MoriEdan/sheltermanager
def gkd(dbo, m, f, usetoday = False):
    """ reads field f from map m, returning a display date. 
        string is empty if key not present or date is invalid.
        If usetoday is set to True, then today's date is returned
        if the date is blank.
    """
    if not m.has_key(f): return ""
    lv = str(m[f])
    # If there's a space, then I guess we have time info - throw it away
    if lv.find(" ") > 0:
        lv = lv[0:lv.find(" ")]
    # Now split it by either / or -
    b = lv.split("/")
    if lv.find("-") != -1:
        b = lv.split("-")
    # We should have three date bits now
    if len(b) != 3:
        # We don't have a valid date, if use today is on return that
        if usetoday:
            return i18n.python2display(dbo.locale, i18n.now(dbo.timezone))
        else:
            return ""
    else:
        # Which of our 3 bits is the year?
        if utils.cint(b[0]) > 1900:
            # it's Y/M/D
            d = datetime.datetime(utils.cint(b[0]), utils.cint(b[1]), utils.cint(b[2]))
        elif dbo.locale == "en":
            # Assume it's M/D/Y for US
            d = datetime.datetime(utils.cint(b[2]), utils.cint(b[0]), utils.cint(b[1]))
        else:
            # Assume it's D/M/Y
            d = datetime.datetime(utils.cint(b[2]), utils.cint(b[1]), utils.cint(b[0]))
        return i18n.python2display(dbo.locale, d)
コード例 #2
0
ファイル: lostfound.py プロジェクト: rutaq/asm3
def match_report(dbo, username = "******", lostanimalid = 0, foundanimalid = 0, animalid = 0, limit = 0):
    """
    Generates the match report and returns it as a string
    """
    l = dbo.locale
    title = _("Match lost and found animals", l)
    h = []
    h.append(reports.get_report_header(dbo, title, username))
    if limit > 0:
        h.append("<p>(" + _("Limited to {0} matches", l).format(limit) + ")</p>")
    def p(s): 
        return "<p>%s</p>" % s
    def td(s): 
        return "<td>%s</td>" % s
    def hr(): 
        return "<hr />"
    lastid = 0
    matches = match(dbo, lostanimalid, foundanimalid, animalid, limit)
    if len(matches) > 0:
        for m in matches:
            if lastid != m.lid:
                if lastid != 0:
                    h.append("</tr></table>")
                    h.append(hr())
                h.append(p(_("{0} - {1} {2} ({3}), contact {4} ({5}) - lost in {6}, postcode {7}, on {8}", l).format( \
                    m.lid, "%s %s %s" % (m.lagegroup, m.lbasecolourname, m.lsexname), \
                    "%s/%s" % (m.lspeciesname,m.lbreedname), \
                    m.ldistinguishingfeatures, m.lcontactname, m.lcontactnumber, m.larealost, m.lareapostcode,
                    python2display(l, m.ldatelost))))
                h.append("<table border=\"1\" width=\"100%\"><tr>")
                h.append("<th>%s</th>" % _("Reference", l))
                h.append("<th>%s</th>" % _("Description", l))
                h.append("<th>%s</th>" % _("Area Found", l))
                h.append("<th>%s</th>" % _("Area Postcode", l))
                h.append("<th>%s</th>" % _("Date Found", l))
                h.append("<th>%s</th>" % _("Contact", l))
                h.append("<th>%s</th>" % _("Number", l))
                h.append("<th>%s</th>" % _("Match", l))
                h.append("</tr>")
                lastid = m.lid
            h.append("<tr>")
            h.append(td(str(m.fid)))
            h.append(td("%s %s %s %s %s" % (m.fagegroup, m.fbasecolourname, m.fsexname, m.fspeciesname, m.fbreedname)))
            h.append(td(m.fareafound))
            h.append(td(m.fareapostcode))
            h.append(td(python2display(l, m.fdatefound)))
            h.append(td(m.fcontactname))
            h.append(td(m.fcontactnumber))
            h.append(td(str(m.matchpoints) + "%"))
            h.append("</tr>")
        h.append("</tr></table>")
    else:
        h.append(p(_("No matches found.", l)))
    h.append(reports.get_report_footer(dbo, title, username))
    return "\n".join(h)
コード例 #3
0
ファイル: mobile.py プロジェクト: MoriEdan/sheltermanager
def jqm_options_next_month(l):
    d = now()
    days = []
    for dummy in xrange(0, 31):
        days.append(jqm_option(python2display(l, d)))
        d = add_days(d, 1)
    d = add_months(now(), 3)
    days.append(jqm_option(python2display(l, d)))
    d = add_months(now(), 6)
    days.append(jqm_option(python2display(l, d)))
    d = add_years(now(), 1)
    days.append(jqm_option(python2display(l, d)))
    return "\n".join(days)
コード例 #4
0
ファイル: mobile.py プロジェクト: MoriEdan/sheltermanager
def jqm_options_next_month(l):
    d = now()
    days = []
    for dummy in xrange(0, 31):
        days.append(jqm_option(python2display(l, d)))
        d = add_days(d, 1)
    d = add_months(now(), 3)
    days.append(jqm_option(python2display(l, d)))
    d = add_months(now(), 6)
    days.append(jqm_option(python2display(l, d)))
    d = add_years(now(), 1)
    days.append(jqm_option(python2display(l, d)))
    return "\n".join(days)
コード例 #5
0
ファイル: lostfound.py プロジェクト: magul/asm3
def match_report(dbo, username = "******", lostanimalid = 0, foundanimalid = 0, animalid = 0):
    """
    Same interface as match above, but generates the match report
    """
    l = dbo.locale
    title = _("Match lost and found animals", l)
    h = []
    h.append(reports.get_report_header(dbo, title, username))
    def p(s): return "<p>%s</p>" % s
    def td(s): return "<td>%s</td>" % s
    def hr(): return "<hr />"
    lastid = 0
    matches = match(dbo, lostanimalid, foundanimalid, animalid)
    if len(matches) > 0:
        for m in matches:
            if lastid != m.lid:
                if lastid != 0:
                    h.append("</tr></table>")
                    h.append(hr())
                h.append(p(_("{0} - {1} {2} ({3}), contact {4} ({5}) - lost in {6}, postcode {7}, on {8}", l).format( \
                    m.lid, "%s %s %s" % (m.lagegroup, m.lbasecolourname, m.lsexname), \
                    "%s/%s" % (m.lspeciesname,m.lbreedname), \
                    m.ldistinguishingfeatures, m.lcontactname, m.lcontactnumber, m.larealost, m.lareapostcode,
                    python2display(l, m.ldatelost))))
                h.append("<table border=\"1\" width=\"100%\"><tr>")
                h.append("<th>%s</th>" % _("Reference", l))
                h.append("<th>%s</th>" % _("Description", l))
                h.append("<th>%s</th>" % _("Area Found", l))
                h.append("<th>%s</th>" % _("Area Postcode", l))
                h.append("<th>%s</th>" % _("Date Found", l))
                h.append("<th>%s</th>" % _("Contact", l))
                h.append("<th>%s</th>" % _("Number", l))
                h.append("<th>%s</th>" % _("Match", l))
                h.append("</tr>")
                lastid = m.lid
            h.append("<tr>")
            h.append(td(str(m.fid)))
            h.append(td("%s %s %s %s %s" % (m.fagegroup, m.fbasecolourname, m.fsexname, m.fspeciesname, m.fbreedname)))
            h.append(td(m.fareafound))
            h.append(td(m.fareapostcode))
            h.append(td(python2display(l, m.fdatefound)))
            h.append(td(m.fcontactname))
            h.append(td(m.fcontactnumber))
            h.append(td(str(m.matchpoints) + "%"))
            h.append("</tr>")
        h.append("</tr></table>")
    else:
        h.append(p(_("No matches found.", l)))
    h.append(reports.get_report_footer(dbo, title, username))
    return "\n".join(h)
コード例 #6
0
ファイル: animalcontrol.py プロジェクト: magul/asm3
def insert_animalcontrol(dbo, username):
    """
    Creates a new animal control incident record and returns the id
    """
    l = dbo.locale
    d = {
        "incidentdate":     python2display(l, now(dbo.timezone)),
        "incidenttime":     format_time_now(dbo.timezone),
        "incidenttype":     configuration.default_incident(dbo),
        "calldate":         python2display(l, now(dbo.timezone)),
        "calltime":         format_time_now(dbo.timezone),
        "calltaker":        username
    }
    return insert_animalcontrol_from_form(dbo, utils.PostedData(d, dbo.locale), username)
コード例 #7
0
ファイル: onlineform.py プロジェクト: MoriEdan/sheltermanager
def create_foundanimal(dbo, username, collationid):
    """
    Creates a found animal record from the incoming form data with collationid.
    Also, attaches the form to the found animal as media.
    """
    l = dbo.locale
    fields = get_onlineformincoming_detail(dbo, collationid)
    d = {}
    d["datefound"] = i18n.python2display(l, i18n.now(dbo.timezone))
    d["datereported"] = i18n.python2display(l, i18n.now(dbo.timezone))
    for f in fields:
        if f["FIELDNAME"] == "species":
            d["species"] = guess_species(dbo, f["VALUE"])
        if f["FIELDNAME"] == "sex": d["sex"] = guess_sex(dbo, f["VALUE"])
        if f["FIELDNAME"] == "breed": d["breed"] = guess_breed(dbo, f["VALUE"])
        if f["FIELDNAME"] == "agegroup":
            d["agegroup"] = guess_agegroup(dbo, f["VALUE"])
        if f["FIELDNAME"] == "color":
            d["colour"] = guess_colour(dbo, f["VALUE"])
        if f["FIELDNAME"] == "colour":
            d["colour"] = guess_colour(dbo, f["VALUE"])
        if f["FIELDNAME"] == "description": d["markings"] = f["VALUE"]
        if f["FIELDNAME"] == "areafound": d["areafound"] = f["VALUE"]
        if f["FIELDNAME"] == "areapostcode": d["areapostcode"] = f["VALUE"]
        if f["FIELDNAME"] == "areazipcode": d["areazipcode"] = f["VALUE"]
    if not d.has_key("species"): d["species"] = guess_species(dbo, "")
    if not d.has_key("sex"): d["sex"] = guess_sex(dbo, "")
    if not d.has_key("breed"): d["breed"] = guess_breed(dbo, "")
    if not d.has_key("agegroup"): d["agegroup"] = guess_agegroup(dbo, "")
    if not d.has_key("colour"): d["colour"] = guess_colour(dbo, "")
    # Have we got enough info to create the found animal record? We need a description and areafound
    if not d.has_key("markings") or not d.has_key("areafound"):
        raise utils.ASMValidationError(
            i18n._(
                "There is not enough information in the form to create a found animal record (need a description and area found).",
                l))
    # We need the person record before we create the found animal
    collationid, personid, personname = create_person(dbo, username,
                                                      collationid)
    d["owner"] = personid
    # Create the found animal
    foundanimalid = lostfound.insert_foundanimal_from_form(dbo, d, username)
    # Attach the form to the found animal
    formname = get_onlineformincoming_name(dbo, collationid)
    formhtml = get_onlineformincoming_html(dbo, collationid)
    media.create_document_media(dbo, username, media.FOUNDANIMAL,
                                foundanimalid, formname, formhtml)
    return (collationid, foundanimalid,
            utils.padleft(foundanimalid, 6) + " - " + personname)
コード例 #8
0
def insert_animalcontrol(dbo, username):
    """
    Creates a new animal control incident record and returns the id
    """
    l = dbo.locale
    d = {
        "incidentdate": python2display(l, dbo.now()),
        "incidenttime": format_time_now(dbo.timezone),
        "incidenttype": configuration.default_incident(dbo),
        "calldate": python2display(l, dbo.now()),
        "calltime": format_time_now(dbo.timezone),
        "calltaker": username
    }
    return insert_animalcontrol_from_form(dbo, utils.PostedData(d, dbo.locale),
                                          username)
コード例 #9
0
ファイル: movement.py プロジェクト: tgage/asm3
def insert_reserve_for_animal_name(dbo, username, personid, animalname):
    """
    Creates a reservation for the animal with animalname to personid.
    animalname can either be just the name of a shelter animal, or it
    can be in the form name::code. If a code is present, that will be
    used to locate the animal.
    If the person is banned from adopting animals, an exception is raised.
    """
    l = dbo.locale
    if animalname.find("::") != -1:
        animalcode = animalname.split("::")[1]
        aid = dbo.query_int("SELECT ID FROM animal WHERE ShelterCode = ? ORDER BY ID DESC", [animalcode])
    else:
        aid = dbo.query_int("SELECT ID FROM animal WHERE LOWER(AnimalName) LIKE ? ORDER BY ID DESC", [animalname.lower()])
    if 1 == dbo.query_int("SELECT IsBanned FROM owner WHERE ID=?", [personid]):
        raise utils.ASMValidationError("owner %s is banned from adopting animals - not creating reserve")
    if aid == 0: 
        raise utils.ASMValidationError("could not find an animal for '%s' - not creating reserve" % animalname)
    move_dict = {
        "person"                : str(personid),
        "animal"                : str(aid),
        "reservationdate"       : i18n.python2display(l, dbo.today()),
        "reservationstatus"     : configuration.default_reservation_status(dbo),
        "movementdate"          : "",
        "type"                  : str(NO_MOVEMENT),
        "returncategory"        : configuration.default_return_reason(dbo)
    }
    return insert_movement_from_form(dbo, username, utils.PostedData(move_dict, l))
コード例 #10
0
def save_values_for_link(dbo, post, linkid, linktype="animal"):
    """
    Saves incoming additional field values from a form, clearing any
    existing values first.
    """
    delete_values_for_link(dbo, linkid, linktype)
    af = get_field_definitions(dbo, linktype)
    l = dbo.locale
    for f in af:
        key = "a." + str(f["MANDATORY"]) + "." + str(f["ID"])
        if post.has_key(key):
            val = post[key]
            if f["FIELDTYPE"] == YESNO:
                val = str(post.boolean(key))
            elif f["FIELDTYPE"] == MONEY:
                val = str(post.integer(key))
            elif f["FIELDTYPE"] == DATE:
                if len(val.strip()) > 0 and post.date(key) == None:
                    raise utils.ASMValidationError(
                        _(
                            "Additional date field '{0}' contains an invalid date.",
                            l).format(f["FIELDNAME"]))
                val = python2display(dbo.locale, post.date(key))
            sql = db.make_insert_sql("additional",
                                     (("LinkType", db.di(f["LINKTYPE"])),
                                      ("LinkID", db.di(int(linkid))),
                                      ("AdditionalFieldID", db.di(f["ID"])),
                                      ("Value", db.ds(val))))
            try:
                db.execute(dbo, sql)
            except Exception, err:
                al.error("Failed saving additional field: %s" % str(err),
                         "animal.update_animal_from_form", dbo, sys.exc_info())
コード例 #11
0
ファイル: movement.py プロジェクト: magul/asm3
def insert_reserve_for_animal_name(dbo, username, personid, animalname):
    """
    Creates a reservation for the animal with animalname to personid.
    animalname can either be just the name of a shelter animal, or it
    can be in the form name::code. If a code is present, that will be
    used to locate the animal.
    """
    l = dbo.locale
    if animalname.find("::") != -1:
        animalcode = animalname.split("::")[1]
        aid = db.query_int(dbo, "SELECT ID FROM animal WHERE ShelterCode = %s ORDER BY ID DESC" % db.ds(animalcode))
    else:
        aid = db.query_int(dbo, "SELECT ID FROM animal WHERE LOWER(AnimalName) LIKE '%s' ORDER BY ID DESC" % animalname.lower())
    # Bail out if we couldn't find a matching animal
    if aid == 0: return
    move_dict = {
        "person"                : str(personid),
        "animal"                : str(aid),
        "reservationdate"       : i18n.python2display(l, i18n.now(dbo.timezone)),
        "reservationstatus"     : configuration.default_reservation_status(dbo),
        "movementdate"          : "",
        "type"                  : str(NO_MOVEMENT),
        "returncategory"        : configuration.default_return_reason(dbo)
    }
    return insert_movement_from_form(dbo, username, utils.PostedData(move_dict, l))
コード例 #12
0
ファイル: utils.py プロジェクト: magul/asm3
def csv(l, rows, cols = None, includeheader = True):
    """
    Creates a CSV file from a set of resultset rows. If cols has been 
    supplied as a list of strings, fields will be output in that
    order.
    """
    if rows is None or len(rows) == 0: return ""
    strio = StringIO()
    out = UnicodeCSVWriter(strio)
    if cols is None:
        cols = []
        for k, v in rows[0].iteritems():
            cols.append(k)
        cols = sorted(cols)
    if includeheader: 
        out.writerow(cols)
    for r in rows:
        rd = []
        for c in cols:
            if is_currency(c):
                rd.append(decode_html(format_currency(l, r[c])))
            elif type(r[c]) == datetime.datetime:
                rd.append(decode_html(python2display(l, r[c])))
            else:
                rd.append(decode_html(r[c]))
        out.writerow(rd)
    return strio.getvalue()
コード例 #13
0
ファイル: lostfound.py プロジェクト: MoriEdan/sheltermanager
def create_animal_from_found(dbo, username, aid):
    """
    Creates an animal record from a found animal with the id given
    """
    a = db.query(dbo, "SELECT * FROM animalfound WHERE ID = %d" % int(aid))[0]
    l = dbo.locale
    data = {
        "animalname":           _("Found Animal {0}", l).format(aid),
        "markings":             str(a["DISTFEAT"]),
        "species":              str(a["ANIMALTYPEID"]),
        "comments":             str(a["COMMENTS"]),
        "broughtinby":          str(a["OWNERID"]),
        "originalowner":        str(a["OWNERID"]),
        "animaltype":           configuration.default_type(dbo),
        "breed1":               a["BREEDID"],
        "breed2":               a["BREEDID"],
        "basecolour":           str(a["BASECOLOURID"]),
        "size":                 configuration.default_size(dbo),
        "internallocation":     configuration.default_location(dbo),
        "dateofbirth":          python2display(l, subtract_years(now(dbo.timezone))),
        "estimateddob":         "1",
    }
    # If we're creating shelter codes manually, we need to put something unique
    # in there for now. Use the id
    if configuration.manual_codes(dbo):
        data["sheltercode"] = "FA" + str(aid)
        data["shortcode"] = "FA" + str(aid)
    nextid, code = animal.insert_animal_from_form(dbo, data, username)
    return nextid
コード例 #14
0
ファイル: onlineform.py プロジェクト: MoriEdan/sheltermanager
def create_waitinglist(dbo, username, collationid):
    """
    Creates a waitinglist record from the incoming form data with collationid.
    Also, attaches the form to the waiting list as media.
    """
    l = dbo.locale
    fields = get_onlineformincoming_detail(dbo, collationid)
    d = {}
    d["dateputon"] = i18n.python2display(l, i18n.now(dbo.timezone))
    d["urgency"] = "5"
    for f in fields:
        if f["FIELDNAME"] == "species":
            d["species"] = guess_species(dbo, f["VALUE"])
        if f["FIELDNAME"] == "description": d["description"] = f["VALUE"]
        if f["FIELDNAME"] == "reason": d["reasonforwantingtopart"] = f["VALUE"]
    if not d.has_key("species"): d["species"] = guess_species(dbo, "")
    # Have we got enough info to create the waiting list record? We need a description
    if not d.has_key("description"):
        raise utils.ASMValidationError(
            i18n._(
                "There is not enough information in the form to create a waiting list record (need a description).",
                l))
    # We need the person record before we create the waiting list
    collationid, personid, personname = create_person(dbo, username,
                                                      collationid)
    d["owner"] = personid
    # Create the waiting list
    wlid = waitinglist.insert_waitinglist_from_form(dbo, d, username)
    # Attach the form to the waiting list
    formname = get_onlineformincoming_name(dbo, collationid)
    formhtml = get_onlineformincoming_html(dbo, collationid)
    media.create_document_media(dbo, username, media.WAITINGLIST, wlid,
                                formname, formhtml)
    return (collationid, wlid, utils.padleft(wlid, 6) + " - " + personname)
コード例 #15
0
ファイル: lostfound.py プロジェクト: rutaq/asm3
def create_animal_from_found(dbo, username, aid):
    """
    Creates an animal record from a found animal with the id given
    """
    a = dbo.first_row( dbo.query("SELECT * FROM animalfound WHERE ID = %d" % int(aid)) )
    l = dbo.locale
    data = {
        "animalname":           _("Found Animal {0}", l).format(aid),
        "markings":             str(a["DISTFEAT"]),
        "species":              str(a["ANIMALTYPEID"]),
        "comments":             str(a["COMMENTS"]),
        "broughtinby":          str(a["OWNERID"]),
        "originalowner":        str(a["OWNERID"]),
        "animaltype":           configuration.default_type(dbo),
        "breed1":               a["BREEDID"],
        "breed2":               a["BREEDID"],
        "basecolour":           str(a["BASECOLOURID"]),
        "size":                 configuration.default_size(dbo),
        "internallocation":     configuration.default_location(dbo),
        "dateofbirth":          python2display(l, subtract_years(now(dbo.timezone))),
        "estimateddob":         "1",
    }
    # If we're creating shelter codes manually, we need to put something unique
    # in there for now. Use the id
    if configuration.manual_codes(dbo):
        data["sheltercode"] = "FA" + str(aid)
        data["shortcode"] = "FA" + str(aid)
    nextid, code = animal.insert_animal_from_form(dbo, utils.PostedData(data, l), username)
    return nextid
コード例 #16
0
ファイル: onlineform.py プロジェクト: MoriEdan/sheltermanager
def create_waitinglist(dbo, username, collationid):
    """
    Creates a waitinglist record from the incoming form data with collationid.
    Also, attaches the form to the waiting list as media.
    """
    l = dbo.locale
    fields = get_onlineformincoming_detail(dbo, collationid)
    d = {}
    d["dateputon"] = i18n.python2display(l, i18n.now(dbo.timezone))
    d["urgency"] = "5"
    for f in fields:
        if f["FIELDNAME"] == "species": d["species"] = guess_species(dbo, f["VALUE"])
        if f["FIELDNAME"] == "description": d["description"] = f["VALUE"]
        if f["FIELDNAME"] == "reason": d["reasonforwantingtopart"] = f["VALUE"]
    if not d.has_key("species"): d["species"] = guess_species(dbo, "")
    # Have we got enough info to create the waiting list record? We need a description
    if not d.has_key("description"):
        raise utils.ASMValidationError(i18n._("There is not enough information in the form to create a waiting list record (need a description).", l))
    # We need the person record before we create the waiting list
    collationid, personid, personname = create_person(dbo, username, collationid)
    d["owner"] = personid
    # Create the waiting list
    wlid = waitinglist.insert_waitinglist_from_form(dbo, d, username)
    # Attach the form to the waiting list
    formname = get_onlineformincoming_name(dbo, collationid)
    formhtml = get_onlineformincoming_html(dbo, collationid)
    media.create_document_media(dbo, username, media.WAITINGLIST, wlid, formname, formhtml )
    return (collationid, wlid, utils.padleft(wlid, 6) + " - " + personname)
コード例 #17
0
ファイル: additional.py プロジェクト: magul/asm3
def save_values_for_link(dbo, post, linkid, linktype = "animal"):
    """
    Saves incoming additional field values from a form, clearing any
    existing values first.
    """
    delete_values_for_link(dbo, linkid, linktype)
    af = get_field_definitions(dbo, linktype)
    l = dbo.locale
    for f in af:
        key = "a." + str(f["MANDATORY"]) + "." + str(f["ID"])
        if post.has_key(key):
            val = post[key]
            if f["FIELDTYPE"] == YESNO:
                val = str(post.boolean(key))
            elif f["FIELDTYPE"] == MONEY:
                val = str(post.integer(key))
            elif f["FIELDTYPE"] == DATE:
                if len(val.strip()) > 0 and post.date(key) == None:
                    raise utils.ASMValidationError(_("Additional date field '{0}' contains an invalid date.", l).format(f["FIELDNAME"]))
                val = python2display(dbo.locale, post.date(key))
            sql = db.make_insert_sql("additional", (
                ( "LinkType", db.di(f["LINKTYPE"]) ),
                ( "LinkID", db.di(int(linkid)) ),
                ( "AdditionalFieldID", db.di(f["ID"]) ),
                ( "Value", db.ds(val) ) ))
            try:
                db.execute(dbo, sql)
            except Exception,err:
                al.error("Failed saving additional field: %s" % str(err), "animal.update_animal_from_form", dbo, sys.exc_info())
コード例 #18
0
ファイル: clinic.py プロジェクト: tgage/asm3
def insert_payment_from_appointment(dbo, username, appointmentid, post):
    """
    Creates a payment record from an appointment via the create payment dialog.
    """
    l = dbo.locale
    c = get_appointment(dbo, appointmentid)
    d = {
        "person":
        str(c.OwnerID),
        "animal":
        str(c.AnimalID),
        "type":
        post["paymenttype"],
        "payment":
        post["paymentmethod"],
        "amount":
        str(c.Amount),
        "due":
        post["due"],
        "received":
        post["received"],
        "vat":
        utils.iif(c.IsVAT == 1, "on", ""),
        "vatrate":
        str(c.VATRate),
        "vatamount":
        str(c.VATAmount),
        "comments":
        i18n._("Appointment {0}. {1} on {2} for {3}").format(
            utils.padleft(c.ID, 6), c.OWNERNAME,
            i18n.python2display(l, c.DATETIME), c.ANIMALNAME)
    }
    return financial.insert_donation_from_form(dbo, username,
                                               utils.PostedData(d, l))
コード例 #19
0
def create_animalcontrol(dbo, username, collationid):
    """
    Creates a animal control/incident record from the incoming form data with 
    collationid.
    Also, attaches the form to the incident as media.
    """
    l = dbo.locale
    fields = get_onlineformincoming_detail(dbo, collationid)
    d = {}
    d["incidentdate"] = i18n.python2display(l, i18n.now(dbo.timezone))
    d["incidenttime"] = i18n.format_time_now(dbo.timezone)
    d["calldate"] = d["incidentdate"]
    d["calltime"] = d["incidenttime"]
    d["incidenttype"] = 1
    for f in fields:
        if f["FIELDNAME"] == "callnotes": d["callnotes"] = f["VALUE"]
        if f["FIELDNAME"] == "dispatchaddress": d["dispatchaddress"] = f["VALUE"]
        if f["FIELDNAME"] == "dispatchcity": d["dispatchtown"] = f["VALUE"]
        if f["FIELDNAME"] == "dispatchstate": d["dispatchcounty"] = f["VALUE"]
        if f["FIELDNAME"] == "dispatchzipcode": d["dispatchpostcode"] = f["VALUE"]
    # Have we got enough info to create the animal control record? We need notes and dispatchaddress
    if not d.has_key("callnotes") or not d.has_key("dispatchaddress"):
        raise utils.ASMValidationError(i18n._("There is not enough information in the form to create an incident record (need call notes and dispatch address).", l))
    # We need the person/caller record before we create the incident
    collationid, personid, personname = create_person(dbo, username, collationid)
    d["caller"] = personid
    # Create the incident 
    incidentid = animalcontrol.insert_animalcontrol_from_form(dbo, utils.PostedData(d, dbo.locale), username)
    # Attach the form to the incident
    formname = get_onlineformincoming_name(dbo, collationid)
    formhtml = get_onlineformincoming_html(dbo, collationid)
    media.create_document_media(dbo, username, media.ANIMALCONTROL, incidentid, formname, formhtml )
    return (collationid, incidentid, utils.padleft(incidentid, 6) + " - " + personname)
コード例 #20
0
def email_uncompleted_upto_today(dbo):
    """
    Goes through all system users and emails them their diary for the
    day - unless the option is turned off.
    """
    if not configuration.email_diary_notes(dbo): return
    l = dbo.locale
    try:
        allusers = users.get_users(dbo)
    except Exception as err:
        al.error("failed getting list of users: %s" % str(err),
                 "diary.email_uncompleted_upto_today", dbo)
    # Grab list of diary notes for today
    notes = get_uncompleted_upto_today(dbo)
    # If we don't have any, bail out
    if len(notes) == 0: return
    # Go through all user to see if we have relevant notes for them
    for u in allusers:
        if u.emailaddress and u.emailaddress.strip() != "":
            s = ""
            totalforuser = 0
            for n in notes:
                # Is this note relevant for this user?
                if (n.diaryforname == "*") \
                or (n.diaryforname == u.username) \
                or (u.roles.find(n.diaryforname) != -1):
                    s += i18n.python2display(l, n.diarydatetime) + " "
                    s += n.subject
                    if n.linkinfo is not None and n.linkinfo != "":
                        s += " / " + n.linkinfo
                    s += "\n" + n.note + "\n\n"
                    totalforuser += 1
            if totalforuser > 0:
                al.debug(
                    "got %d notes for user %s" % (totalforuser, u.username),
                    "diary.email_uncompleted_upto_today", dbo)
                utils.send_email(dbo,
                                 configuration.email(dbo),
                                 u.emailaddress,
                                 "",
                                 "",
                                 i18n._("Diary notes for: {0}", l).format(
                                     i18n.python2display(l, dbo.now())),
                                 s,
                                 exceptions=False)
コード例 #21
0
ファイル: csvimport.py プロジェクト: Reeco2014/asm3
def gkd(dbo, m, f, usetoday=False):
    """ reads field f from map m, returning a display date. 
        string is empty if key not present or date is invalid.
        If usetoday is set to True, then today's date is returned
        if the date is blank.
    """
    if f not in m: return ""
    lv = str(m[f])
    # If there's a space, then I guess we have time info - throw it away
    if lv.find(" ") > 0:
        lv = lv[0:lv.find(" ")]
    # Now split it by either / or -
    b = lv.split("/")
    if lv.find("-") != -1:
        b = lv.split("-")
    # We should have three date bits now
    if len(b) != 3:
        # We don't have a valid date, if use today is on return that
        if usetoday:
            return i18n.python2display(dbo.locale, i18n.now(dbo.timezone))
        else:
            return ""
    else:
        try:
            # Which of our 3 bits is the year?
            if utils.cint(b[0]) > 1900:
                # it's Y/M/D
                d = datetime.datetime(utils.cint(b[0]), utils.cint(b[1]),
                                      utils.cint(b[2]))
            elif dbo.locale == "en":
                # Assume it's M/D/Y for US
                d = datetime.datetime(utils.cint(b[2]), utils.cint(b[0]),
                                      utils.cint(b[1]))
            else:
                # Assume it's D/M/Y
                d = datetime.datetime(utils.cint(b[2]), utils.cint(b[1]),
                                      utils.cint(b[0]))
            return i18n.python2display(dbo.locale, d)
        except:
            # We've got an invalid date - return today
            if usetoday:
                return i18n.python2display(dbo.locale, i18n.now(dbo.timezone))
            else:
                return ""
コード例 #22
0
def update_waitinglist_remove(dbo, username, wid):
    """
    Marks a waiting list record as removed
    """
    db.execute(
        dbo,
        "UPDATE animalwaitinglist SET DateRemovedFromList = %s WHERE ID = %d" %
        (db.dd(now(dbo.timezone)), int(wid)))
    audit.edit(
        dbo, username, "animalwaitinglist", "%s: DateRemovedFromList ==> %s" %
        (str(wid), python2display(dbo.locale, now(dbo.timezone))))
コード例 #23
0
ファイル: stock.py プロジェクト: magul/asm3
def get_stock_items(dbo):
    """
    Returns a set of stock items.
    """
    rows = db.query(dbo, "SELECT sv.*, sl.LocationName " \
        "FROM stocklevel sv " \
        "INNER JOIN stocklocation sl ON sl.ID = sv.StockLocationID " \
        "WHERE sv.Balance > 0 " \
        "ORDER BY sv.StockLocationID, sv.Name")
    for r in rows:
        r["ITEMNAME"] = "%s - %s %s %s (%g/%g)" % (r["LOCATIONNAME"], r["NAME"], r["BATCHNUMBER"], 
            python2display(dbo.locale, r["EXPIRY"]), r["BALANCE"], r["TOTAL"])
    return rows
コード例 #24
0
def donation_tags(dbo, p):
    """
    Generates a list of tags from a donation result.
    """
    l = dbo.locale
    tags = { 
        "DONATIONID"            : str(p["ID"]),
        "RECEIPTNUM"            : utils.padleft(p["ID"], 8),
        "DONATIONTYPE"          : p["DONATIONNAME"],
        "DONATIONDATE"          : python2display(l, p["DATE"]),
        "DONATIONDATEDUE"       : python2display(l, p["DATEDUE"]),
        "DONATIONAMOUNT"        : format_currency_no_symbol(l, p["DONATION"]),
        "DONATIONCOMMENTS"      : p["COMMENTS"],
        "DONATIONGIFTAID"       : p["ISGIFTAIDNAME"],
        "DONATIONCREATEDBY"     : p["CREATEDBY"],
        "DONATIONCREATEDBYNAME" : p["CREATEDBY"],
        "DONATIONCREATEDDATE"   : python2display(l, p["CREATEDDATE"]),
        "DONATIONLASTCHANGEDBY" : p["LASTCHANGEDBY"],
        "DONATIONLASTCHANGEDBYNAME" : p["LASTCHANGEDBY"],
        "DONATIONLASTCHANGEDDATE" : python2display(l, p["LASTCHANGEDDATE"])
    }
    return tags
コード例 #25
0
ファイル: onlineform.py プロジェクト: MoriEdan/sheltermanager
def create_foundanimal(dbo, username, collationid):
    """
    Creates a found animal record from the incoming form data with collationid.
    Also, attaches the form to the found animal as media.
    """
    l = dbo.locale
    fields = get_onlineformincoming_detail(dbo, collationid)
    d = {}
    d["datefound"] = i18n.python2display(l, i18n.now(dbo.timezone))
    d["datereported"] = i18n.python2display(l, i18n.now(dbo.timezone))
    for f in fields:
        if f["FIELDNAME"] == "species": d["species"] = guess_species(dbo, f["VALUE"])
        if f["FIELDNAME"] == "sex": d["sex"] = guess_sex(dbo, f["VALUE"])
        if f["FIELDNAME"] == "breed": d["breed"] = guess_breed(dbo, f["VALUE"])
        if f["FIELDNAME"] == "agegroup": d["agegroup"] = guess_agegroup(dbo, f["VALUE"])
        if f["FIELDNAME"] == "color": d["colour"] = guess_colour(dbo, f["VALUE"])
        if f["FIELDNAME"] == "colour": d["colour"] = guess_colour(dbo, f["VALUE"])
        if f["FIELDNAME"] == "description": d["markings"] = f["VALUE"]
        if f["FIELDNAME"] == "areafound": d["areafound"] = f["VALUE"]
        if f["FIELDNAME"] == "areapostcode": d["areapostcode"] = f["VALUE"]
        if f["FIELDNAME"] == "areazipcode": d["areazipcode"] = f["VALUE"]
    if not d.has_key("species"): d["species"] = guess_species(dbo, "")
    if not d.has_key("sex"): d["sex"] = guess_sex(dbo, "")
    if not d.has_key("breed"): d["breed"] = guess_breed(dbo, "")
    if not d.has_key("agegroup"): d["agegroup"] = guess_agegroup(dbo, "")
    if not d.has_key("colour"): d["colour"] = guess_colour(dbo, "")
    # Have we got enough info to create the found animal record? We need a description and areafound
    if not d.has_key("markings") or not d.has_key("areafound"):
        raise utils.ASMValidationError(i18n._("There is not enough information in the form to create a found animal record (need a description and area found).", l))
    # We need the person record before we create the found animal
    collationid, personid, personname = create_person(dbo, username, collationid)
    d["owner"] = personid
    # Create the found animal
    foundanimalid = lostfound.insert_foundanimal_from_form(dbo, d, username)
    # Attach the form to the found animal
    formname = get_onlineformincoming_name(dbo, collationid)
    formhtml = get_onlineformincoming_html(dbo, collationid)
    media.create_document_media(dbo, username, media.FOUNDANIMAL, foundanimalid, formname, formhtml )
    return (collationid, foundanimalid, utils.padleft(foundanimalid, 6) + " - " + personname)
コード例 #26
0
def get_stock_items(dbo):
    """
    Returns a set of stock items.
    """
    rows = dbo.query("SELECT sv.*, sl.LocationName " \
        "FROM stocklevel sv " \
        "INNER JOIN stocklocation sl ON sl.ID = sv.StockLocationID " \
        "WHERE sv.Balance > 0 " \
        "ORDER BY sv.StockLocationID, sv.Name")
    for r in rows:
        r.ITEMNAME = "%s - %s %s %s (%g/%g)" % (
            r.LOCATIONNAME, r.NAME, r.BATCHNUMBER,
            python2display(dbo.locale, r.EXPIRY), r.BALANCE, r.TOTAL)
    return rows
コード例 #27
0
ファイル: mobile.py プロジェクト: MoriEdan/sheltermanager
def page_messages(l, homelink, mess):
    h = []
    h.append(jqm_page_header("messages", _("Messages", l), homelink))
    h.append(jqm_list(jqm_link("#addmessage", _("Add Message", l), "message_new")))
    hm = []
    for m in mess:
        icon = "info"
        if m["PRIORITY"] == 1:
            icon = "alert"
        inner = jqm_h3(python2display(l, m["ADDED"]) + " " + m["CREATEDBY"])
        inner += jqm_p(m["MESSAGE"])
        hm.append(jqm_collapsible(inner, icon))
    h.append(jqm_collapsible_set("\n".join(hm)))
    h.append(jqm_page_footer())
    return h
コード例 #28
0
def page_messages(l, homelink, mess):
    h = []
    h.append(jqm_page_header("messages", _("Messages", l), homelink))
    h.append(jqm_button("#addmessage", _("Add Message", l), "plus"))
    hm = []
    for m in mess:
        icon = "info"
        if m["PRIORITY"] == 1:
            icon = "alert"
        inner = jqm_h3(python2display(l, m["ADDED"]) + " " + m["CREATEDBY"])
        inner += jqm_p(m["MESSAGE"])
        hm.append(jqm_collapsible(inner, icon))
    h.append(jqm_collapsible_set("\n".join(hm)))
    h.append(jqm_page_footer())
    return h
コード例 #29
0
ファイル: mobile.py プロジェクト: MoriEdan/sheltermanager
def page_tests(l, homelink, test, testresults):
    h = []
    h.append(jqm_page_header("test", _("Test", l), homelink))
    group = ""
    tlist = []
    tforms = []
    for t in test:
        required = python2display(l, t["DATEREQUIRED"])
        if group != required:
            group = required
            tlist.append(jqm_list_divider(group))
        pageid = "t" + str(t["ID"])
        tlist.append(
            jqm_listitem_link(
                "#" + pageid,
                "%s - %s (%s)" % (t["ANIMALNAME"], t["SHELTERCODE"], t["TESTNAME"]),
                "vaccination",
                -1,
                "dialog",
            )
        )
        tforms.append(jqm_page_header(pageid, t["TESTNAME"], homelink))
        tforms.append(jqm_table())
        tforms.append(
            jqm_tablerow(
                _("Animal", l),
                jqm_link("mobile_post?posttype=va&id=%d" % t["ANIMALID"], t["SHELTERCODE"] + " " + t["ANIMALNAME"]),
            )
        )
        tforms.append(jqm_tablerow(_("Test", l), required + " " + t["TESTNAME"]))
        tforms.append(jqm_tablerow(_("Comments", l), t["COMMENTS"]))
        tforms.append(jqm_table_end())
        tforms.append(
            jqm_p(
                _("Result", l)
                + ": "
                + '<select class="testresult" data="%s" data-animal="%s">' % (str(t["ID"]), t["ANIMALID"])
                + "<option value="
                "></option>" + jqm_options_testresults(testresults) + "</select>"
            )
        )
        tforms.append(jqm_page_footer())
    h.append(jqm_list("\n".join(tlist), True))
    h.append(jqm_page_footer())
    h.append("\n".join(tforms))
    return h
コード例 #30
0
ファイル: mobile.py プロジェクト: MoriEdan/sheltermanager
def page_medication(l, homelink, med):
    h = []
    h.append(jqm_page_header("med", _("Medicate", l), homelink))
    group = ""
    mlist = []
    mforms = []
    for m in med:
        required = python2display(l, m["DATEREQUIRED"])
        if group != required:
            group = required
            mlist.append(jqm_list_divider(group))
        pageid = "m" + str(m["TREATMENTID"])
        mlist.append(
            jqm_listitem_link(
                "#" + pageid,
                "%s - %s (%s)" % (m["ANIMALNAME"], m["SHELTERCODE"], m["TREATMENTNAME"]),
                "medical",
                -1,
                "dialog",
            )
        )
        mforms.append(jqm_page_header(pageid, m["TREATMENTNAME"], homelink))
        mforms.append(jqm_table())
        mforms.append(
            jqm_tablerow(
                _("Animal", l),
                jqm_link("mobile_post?posttype=va&id=%d" % m["ANIMALID"], m["SHELTERCODE"] + " " + m["ANIMALNAME"]),
            )
        )
        mforms.append(jqm_tablerow(_("Treatment", l), "%s %s<br />%s" % (required, m["TREATMENTNAME"], m["DOSAGE"])))
        mforms.append(jqm_tablerow(_("Comments", l), m["COMMENTS"]))
        mforms.append(jqm_table_end())
        mforms.append(
            jqm_button(
                "mobile_post?posttype=med&id=%s&animalid=%s&medicalid=%s"
                % (str(m["TREATMENTID"]), str(m["ANIMALID"]), str(m["REGIMENID"])),
                _("Medicate", l),
                "check",
            )
        )
        mforms.append(jqm_page_footer())
    h.append(jqm_list("\n".join(mlist), True))
    h.append(jqm_page_footer())
    h.append("\n".join(mforms))
    return h
コード例 #31
0
 def writeJavaScript(self, animals):
     # Remove original owner and other sensitive info from javascript database
     # before saving it
     for a in animals:
         for k in a.iterkeys():
             if k.startswith("ORIGINALOWNER") or k.startswith("BROUGHTINBY") \
                 or k.startswith("RESERVEDOWNER") or k.startswith("CURRENTOWNER") \
                 or k == "DISPLAYLOCATION":
                 a[k] = ""
     self.saveFile(
         os.path.join(self.publishDir,
                      "db.js"), "publishDate='%s';animals=%s;" %
         (i18n.python2display(self.locale, i18n.now(
             self.dbo.timezone)), utils.json(animals)))
     if self.pc.uploadDirectly:
         self.log("Uploading javascript database...")
         self.upload("db.js")
         self.log("Uploaded javascript database.")
コード例 #32
0
ファイル: mobile.py プロジェクト: MoriEdan/sheltermanager
def page_vaccinations(l, homelink, vacc):
    h = []
    h.append(jqm_page_header("vacc", _("Vaccinate", l), homelink))
    group = ""
    vlist = []
    vforms = []
    for v in vacc:
        required = python2display(l, v["DATEREQUIRED"])
        if group != required:
            group = required
            vlist.append(jqm_list_divider(group))
        pageid = "v" + str(v["ID"])
        vlist.append(
            jqm_listitem_link(
                "#" + pageid,
                "%s - %s (%s)" % (v["ANIMALNAME"], v["SHELTERCODE"], v["VACCINATIONTYPE"]),
                "vaccination",
                -1,
                "dialog",
            )
        )
        vforms.append(jqm_page_header(pageid, v["VACCINATIONTYPE"], homelink))
        vforms.append(jqm_table())
        vforms.append(
            jqm_tablerow(
                _("Animal", l),
                jqm_link("mobile_post?posttype=va&id=%d" % v["ANIMALID"], v["SHELTERCODE"] + " " + v["ANIMALNAME"]),
            )
        )
        vforms.append(jqm_tablerow(_("Vaccination", l), required + " " + v["VACCINATIONTYPE"]))
        vforms.append(jqm_tablerow(_("Comments", l), v["COMMENTS"]))
        vforms.append(jqm_table_end())
        vforms.append(
            jqm_button(
                "mobile_post?posttype=vacc&id=%s&animalid=%s" % (str(v["ID"]), str(v["ANIMALID"])),
                _("Vaccinate", l),
                "check",
            )
        )
        vforms.append(jqm_page_footer())
    h.append(jqm_list("\n".join(vlist), True))
    h.append(jqm_page_footer())
    h.append("\n".join(vforms))
    return h
コード例 #33
0
ファイル: lostfound.py プロジェクト: MoriEdan/sheltermanager
def create_waitinglist_from_found(dbo, username, aid):
    """
    Creates a waiting list entry from a found animal with the id given
    """
    a = db.query(dbo, "SELECT * FROM animalfound WHERE ID = %d" % int(aid))[0]
    l = dbo.locale
    data = {
        "dateputon":            python2display(l, now(dbo.timezone)),
        "description":          str(a["DISTFEAT"]),
        "species":              str(a["ANIMALTYPEID"]),
        "comments":             str(a["COMMENTS"]),
        "owner":                str(a["OWNERID"]),
        "breed1":               a["BREEDID"],
        "breed2":               a["BREEDID"],
        "basecolour":           str(a["BASECOLOURID"]),
        "urgency":              str(configuration.waiting_list_default_urgency(dbo))
    }
    nextid = waitinglist.insert_waitinglist_from_form(dbo, data, username)
    return nextid
コード例 #34
0
 def reregistrationPDF(self, fields, sig, realname, orgname, orgaddress,
                       orgtown, orgcounty, orgpostcode):
     """
     Generates a reregistration PDF document containing the authorised user's
     electronic signature.
     """
     gender = fields["petgender"]
     if gender == "M": gender = "Male"
     elif gender == "F": gender = "Female"
     h = "<p align=\"right\"><b>%s</b><br />%s<br />%s, %s<br />%s</p>" % (
         orgname, orgaddress, orgtown, orgcounty, orgpostcode)
     h += "<h2>Change of Registered Owner/Keeper</h2>"
     h += "<table border=\"1\">"
     h += "<tr><td>Chip:</td><td><b>%s</b></td></tr>" % fields["microchip"]
     h += "<tr><td>Implanted:</td><td>%s</td></tr>" % fields["implantdate"]
     h += "<tr><td>Animal:</td><td>%s</td></tr>" % fields["petname"]
     h += "<tr><td>DOB:</td><td>%s</td></tr>" % fields["petdob"]
     h += "<tr><td>Type:</td><td>%s %s %s</td></tr>" % (
         gender, fields["petbreed"], fields["petspecies"])
     h += "<tr><td>Colour:</td><td>%s</td></tr>" % fields["petcolour"]
     h += "<tr><td>Neutered:</td><td>%s</td></tr>" % fields["petneutered"]
     h += "<tr><td>New Owner:</td><td>%s %s %s</td></tr>" % (
         fields["prefix"], fields["firstname"], fields["surname"])
     h += "<tr><td>Address:</td><td>%s<br/>%s<br/>%s %s</td></tr>" % (
         fields["address1"], fields["city"], fields["county"],
         fields["postcode"])
     h += "<tr><td>Telephone:</td><td>H: %s<br/>W: %s<br/>M: %s</td></tr>" % (
         fields["telhome"], fields["telwork"], fields["telmobile"])
     h += "<tr><td>Email:</td><td>%s</td></tr>" % fields["email"]
     h += "</table>"
     h += "<p>I/We confirm that every effort has been made to reunite the animal with its owner/keeper, or that the previous " \
         "owner has relinquished ownership/keepership.</p>\n"
     h += "<p>If the animal was a stray then the animal has been in our care for the minimum required time period before " \
         "rehoming took place.</p>\n"
     h += "<p>Authorised Signature: <br /><img src=\"%s\" /><br />%s</p>\n" % (
         sig, realname)
     h += "<p>Date: %s</p>\n" % i18n.python2display(
         self.dbo.locale, i18n.now(self.dbo.timezone))
     h += "<p>Authorisation: I understand that the information I have given on this form will be retained by PETtrac and " \
         "hereby agree that it may be disclosed to any person or persons who may be involved in securing the welfare of the " \
         "pet above. PETtrac reserves the right to amend any microchip record in the event that we are subsequently " \
         "provided with additional information.</p>\n"
     return utils.html_to_pdf(h)
コード例 #35
0
ファイル: lostfound.py プロジェクト: rutaq/asm3
def create_waitinglist_from_found(dbo, username, aid):
    """
    Creates a waiting list entry from a found animal with the id given
    """
    a = dbo.first_row( dbo.query("SELECT * FROM animalfound WHERE ID = %d" % int(aid)) )
    l = dbo.locale
    data = {
        "dateputon":            python2display(l, now(dbo.timezone)),
        "description":          str(a["DISTFEAT"]),
        "species":              str(a["ANIMALTYPEID"]),
        "comments":             str(a["COMMENTS"]),
        "owner":                str(a["OWNERID"]),
        "breed1":               a["BREEDID"],
        "breed2":               a["BREEDID"],
        "basecolour":           str(a["BASECOLOURID"]),
        "urgency":              str(configuration.waiting_list_default_urgency(dbo))
    }
    nextid = waitinglist.insert_waitinglist_from_form(dbo, utils.PostedData(data, dbo.locale), username)
    return nextid
コード例 #36
0
def insert_reserve_for_animal_name(dbo, username, personid, animalname):
    """
    Creates a reservation for the animal with animalname to personid
    """
    l = dbo.locale
    aid = db.query_int(
        dbo,
        "SELECT ID FROM animal WHERE LOWER(AnimalName) LIKE '%s' ORDER BY ID DESC"
        % animalname.lower())
    # Bail out if an invalid animal name was given - we can't create the reservation
    if aid == 0: return
    move_dict = {
        "person": str(personid),
        "animal": str(aid),
        "reservationdate": i18n.python2display(l, i18n.now(dbo.timezone)),
        "movementdate": "",
        "type": str(NO_MOVEMENT),
        "returncategory": configuration.default_return_reason(dbo)
    }
    return insert_movement_from_form(dbo, username,
                                     utils.PostedData(move_dict, l))
コード例 #37
0
def org_tags(dbo, username):
    """
    Generates a list of tags from the organisation and user info
    """
    u = users.get_users(dbo, username)
    realname = ""
    email = ""
    if len(u) > 0:
        u = u[0]
        realname = u["REALNAME"]
        email = u["EMAILADDRESS"]
    tags = {
        "ORGANISATION"          : configuration.organisation(dbo),
        "ORGANISATIONADDRESS"   : configuration.organisation_address(dbo),
        "ORGANISATIONTELEPHONE" : configuration.organisation_telephone(dbo),
        "DATE"                  : python2display(dbo.locale, now(dbo.timezone)),
        "USERNAME"              : username,
        "USERREALNAME"          : realname,
        "USEREMAILADDRESS"      : email
    }
    return tags
コード例 #38
0
ファイル: mobile.py プロジェクト: MoriEdan/sheltermanager
def page_tests(l, homelink, test, testresults):
    h = []
    h.append(jqm_page_header("test", _("Test", l), homelink))
    group = ""
    tlist = []
    tforms = []
    for t in test:
        required = python2display(l, t["DATEREQUIRED"])
        if group != required:
            group = required
            tlist.append(jqm_list_divider(group))
        pageid = "t" + str(t["ID"])
        tlist.append(
            jqm_listitem_link(
                "#" + pageid, "%s - %s (%s)" %
                (t["ANIMALNAME"], t["SHELTERCODE"], t["TESTNAME"]),
                "vaccination", -1, "dialog"))
        tforms.append(jqm_page_header(pageid, t["TESTNAME"], homelink))
        tforms.append(jqm_table())
        tforms.append(
            jqm_tablerow(
                _("Animal", l),
                jqm_link("mobile_post?posttype=va&id=%d" % t["ANIMALID"],
                         t["SHELTERCODE"] + " " + t["ANIMALNAME"])))
        tforms.append(
            jqm_tablerow(_("Test", l), required + " " + t["TESTNAME"]))
        tforms.append(jqm_tablerow(_("Comments", l), t["COMMENTS"]))
        tforms.append(jqm_table_end())
        tforms.append(
            jqm_p(
                _("Result", l) + ": " +
                "<select class=\"testresult\" data=\"%s\" data-animal=\"%s\">"
                % (str(t["ID"]), t["ANIMALID"]) + "<option value="
                "></option>" + jqm_options_testresults(testresults) +
                "</select>"))
        tforms.append(jqm_page_footer())
    h.append(jqm_list("\n".join(tlist), True))
    h.append(jqm_page_footer())
    h.append("\n".join(tforms))
    return h
コード例 #39
0
ファイル: mobile.py プロジェクト: MoriEdan/sheltermanager
def page_medication(l, homelink, med):
    h = []
    h.append(jqm_page_header("med", _("Medicate", l), homelink))
    group = ""
    mlist = []
    mforms = []
    for m in med:
        required = python2display(l, m["DATEREQUIRED"])
        if group != required:
            group = required
            mlist.append(jqm_list_divider(group))
        pageid = "m" + str(m["TREATMENTID"])
        mlist.append(
            jqm_listitem_link(
                "#" + pageid, "%s - %s (%s)" %
                (m["ANIMALNAME"], m["SHELTERCODE"], m["TREATMENTNAME"]),
                "medical", -1, "dialog"))
        mforms.append(jqm_page_header(pageid, m["TREATMENTNAME"], homelink))
        mforms.append(jqm_table())
        mforms.append(
            jqm_tablerow(
                _("Animal", l),
                jqm_link("mobile_post?posttype=va&id=%d" % m["ANIMALID"],
                         m["SHELTERCODE"] + " " + m["ANIMALNAME"])))
        mforms.append(
            jqm_tablerow(
                _("Treatment", l),
                "%s %s<br />%s" % (required, m["TREATMENTNAME"], m["DOSAGE"])))
        mforms.append(jqm_tablerow(_("Comments", l), m["COMMENTS"]))
        mforms.append(jqm_table_end())
        mforms.append(
            jqm_button(
                "mobile_post?posttype=med&id=%s&animalid=%s&medicalid=%s" %
                (str(m["TREATMENTID"]), str(m["ANIMALID"]), str(
                    m["REGIMENID"])), _("Medicate", l), "check"))
        mforms.append(jqm_page_footer())
    h.append(jqm_list("\n".join(mlist), True))
    h.append(jqm_page_footer())
    h.append("\n".join(mforms))
    return h
コード例 #40
0
ファイル: mobile.py プロジェクト: MoriEdan/sheltermanager
def page_vaccinations(l, homelink, vacc):
    h = []
    h.append(jqm_page_header("vacc", _("Vaccinate", l), homelink))
    group = ""
    vlist = []
    vforms = []
    for v in vacc:
        required = python2display(l, v["DATEREQUIRED"])
        if group != required:
            group = required
            vlist.append(jqm_list_divider(group))
        pageid = "v" + str(v["ID"])
        vlist.append(
            jqm_listitem_link(
                "#" + pageid, "%s - %s (%s)" %
                (v["ANIMALNAME"], v["SHELTERCODE"], v["VACCINATIONTYPE"]),
                "vaccination", -1, "dialog"))
        vforms.append(jqm_page_header(pageid, v["VACCINATIONTYPE"], homelink))
        vforms.append(jqm_table())
        vforms.append(
            jqm_tablerow(
                _("Animal", l),
                jqm_link("mobile_post?posttype=va&id=%d" % v["ANIMALID"],
                         v["SHELTERCODE"] + " " + v["ANIMALNAME"])))
        vforms.append(
            jqm_tablerow(_("Vaccination", l),
                         required + " " + v["VACCINATIONTYPE"]))
        vforms.append(jqm_tablerow(_("Comments", l), v["COMMENTS"]))
        vforms.append(jqm_table_end())
        vforms.append(
            jqm_button(
                "mobile_post?posttype=vacc&id=%s&animalid=%s" %
                (str(v["ID"]), str(v["ANIMALID"])), _("Vaccinate",
                                                      l), "check"))
        vforms.append(jqm_page_footer())
    h.append(jqm_list("\n".join(vlist), True))
    h.append(jqm_page_footer())
    h.append("\n".join(vforms))
    return h
コード例 #41
0
ファイル: mobile.py プロジェクト: MoriEdan/sheltermanager
def page_diary(l, homelink, dia):
    h = []
    h.append(jqm_page_header("diary", _("Diary", l), homelink))
    group = ""
    dlist = []
    dforms = []
    for d in dia:
        fordate = python2display(l, d["DIARYDATETIME"])
        if group != fordate:
            group = fordate
            dlist.append(jqm_list_divider(group))
        pageid = "d" + str(d["ID"])
        dlist.append(
            jqm_listitem_link("#" + pageid,
                              "%s (%s)" % (d["SUBJECT"], d["LINKINFO"]),
                              "diary", -1, "dialog"))
        dforms.append(jqm_page_header(pageid, d["SUBJECT"], homelink))
        dforms.append(jqm_table())
        dforms.append(jqm_tablerow(_("Subject", l), d["SUBJECT"]))
        lt = d["LINKINFO"]
        if d["LINKTYPE"] == diary.ANIMAL:
            lt = jqm_link("mobile_post?posttype=va&id=%d" % d["LINKID"],
                          d["LINKINFO"])
        dforms.append(jqm_tablerow(_("Link", l), lt))
        dforms.append(jqm_tablerow(_("Note", l), d["NOTE"]))
        dforms.append(jqm_table_end())
        dforms.append(
            jqm_button("mobile_post?posttype=dia&on=0&id=%s" % str(d["ID"]),
                       _("Complete", l), "check"))
        dforms.append(
            jqm_p(
                _("Or move this diary on to", l) + ": " +
                "<select class=\"diaryon\" data=\"%s\">" % str(d["ID"]) +
                jqm_options_next_month(l) + "</select>"))
        dforms.append(jqm_page_footer())
    h.append(jqm_list("\n".join(dlist), True))
    h.append(jqm_page_footer())
    h.append("\n".join(dforms))
    return h
コード例 #42
0
ファイル: additional.py プロジェクト: Reeco2014/asm3
def save_values_for_link(dbo, post, linkid, linktype = "animal", setdefaults=False):
    """
    Saves incoming additional field values from a record.
    Clears existing additional field values before saving (this is because forms
        don't send blank values)
    linkid: The link to the parent record
    linktype: The class of parent record
    setdefaults: If True, will set default values for any keys not supplied
        (Should be True for calls from insert_X_from_form methods)
    Keys of either a.MANDATORY.ID can be used (ASM internal forms)
        or keys of the form additionalFIELDNAME (ASM online forms)
    """
    l = dbo.locale

    dbo.delete("additional", "LinkType IN (%s) AND LinkID=%s" % (clause_for_linktype(linktype), linkid))

    for f in get_field_definitions(dbo, linktype):

        key = "a.%s.%s" % (f.mandatory, f.id)
        key2 = "additional%s" % f.fieldname

        if key not in post and key2 not in post:
            if setdefaults and f.DEFAULTVALUE and f.DEFAULTVALUE != "": 
                insert_additional(dbo, f.LINKTYPE, linkid, f.ID, f.DEFAULTVALUE)
            continue

        elif key not in post: key = key2

        val = post[key]
        if f.fieldtype == YESNO:
            val = str(post.boolean(key))
        elif f.fieldtype == MONEY:
            val = str(post.integer(key))
        elif f.fieldtype == DATE:
            if len(val.strip()) > 0 and post.date(key) is None:
                raise utils.ASMValidationError(_("Additional date field '{0}' contains an invalid date.", l).format(f.fieldname))
            val = python2display(dbo.locale, post.date(key))
        insert_additional(dbo, f.LINKTYPE, linkid, f.ID, val)
コード例 #43
0
def create_animal(dbo, username, wlid):
    """
    Creates an animal record from a waiting list entry with the id given
    """
    a = db.query(dbo,
                 "SELECT * FROM animalwaitinglist WHERE ID = %d" % wlid)[0]
    l = dbo.locale
    data = {
        "animalname": _("Waiting List {0}", l).format(wlid),
        "markings": str(a["ANIMALDESCRIPTION"]),
        "reasonforentry": str(a["REASONFORWANTINGTOPART"]),
        "species": str(a["SPECIESID"]),
        "comments": str(a["COMMENTS"]),
        "broughtinby": str(a["OWNERID"]),
        "originalowner": str(a["OWNERID"]),
        "animaltype": configuration.default_type(dbo),
        "breed1": configuration.default_breed(dbo),
        "breed2": configuration.default_breed(dbo),
        "basecolour": configuration.default_colour(dbo),
        "size": configuration.default_size(dbo),
        "internallocation": configuration.default_location(dbo),
        "dateofbirth": python2display(l, subtract_years(now(dbo.timezone))),
        "estimateddob": "1"
    }
    # If we're creating shelter codes manually, we need to put something unique
    # in there for now. Use the id
    if configuration.manual_codes(dbo):
        data["sheltercode"] = "WL" + str(wlid)
        data["shortcode"] = "WL" + str(wlid)
    nextid, code = animal.insert_animal_from_form(dbo, data, username)
    # Now that we've created our animal, we should remove this entry from the waiting list
    db.execute(dbo, "UPDATE animalwaitinglist SET DateRemovedFromList = %s, ReasonForRemoval = %s " \
        "WHERE ID = %d" % (
        db.dd(now(dbo.timezone)),
        db.ds(_("Moved to animal record {0}", l).format(code)),
        wlid))
    return nextid
コード例 #44
0
ファイル: mobile.py プロジェクト: MoriEdan/sheltermanager
def page_diary(l, homelink, dia):
    h = []
    h.append(jqm_page_header("diary", _("Diary", l), homelink))
    group = ""
    dlist = []
    dforms = []
    for d in dia:
        fordate = python2display(l, d["DIARYDATETIME"])
        if group != fordate:
            group = fordate
            dlist.append(jqm_list_divider(group))
        pageid = "d" + str(d["ID"])
        dlist.append(jqm_listitem_link("#" + pageid, "%s (%s)" % (d["SUBJECT"], d["LINKINFO"]), "diary", -1, "dialog"))
        dforms.append(jqm_page_header(pageid, d["SUBJECT"], homelink))
        dforms.append(jqm_table())
        dforms.append(jqm_tablerow(_("Subject", l), d["SUBJECT"]))
        lt = d["LINKINFO"]
        if d["LINKTYPE"] == diary.ANIMAL:
            lt = jqm_link("mobile_post?posttype=va&id=%d" % d["LINKID"], d["LINKINFO"])
        dforms.append(jqm_tablerow(_("Link", l), lt))
        dforms.append(jqm_tablerow(_("Note", l), d["NOTE"]))
        dforms.append(jqm_table_end())
        dforms.append(jqm_button("mobile_post?posttype=dia&on=0&id=%s" % str(d["ID"]), _("Complete", l), "check"))
        dforms.append(
            jqm_p(
                _("Or move this diary on to", l)
                + ": "
                + '<select class="diaryon" data="%s">' % str(d["ID"])
                + jqm_options_next_month(l)
                + "</select>"
            )
        )
        dforms.append(jqm_page_footer())
    h.append(jqm_list("\n".join(dlist), True))
    h.append(jqm_page_footer())
    h.append("\n".join(dforms))
    return h
コード例 #45
0
def create_animal(dbo, username, wlid):
    """
    Creates an animal record from a waiting list entry with the id given
    """
    a = db.query(dbo, "SELECT * FROM animalwaitinglist WHERE ID = %d" % wlid)[0]
    l = dbo.locale
    data = {
        "animalname":           _("Waiting List {0}", l).format(wlid),
        "markings":             str(a["ANIMALDESCRIPTION"]),
        "reasonforentry":       str(a["REASONFORWANTINGTOPART"]),
        "species":              str(a["SPECIESID"]),
        "comments":             str(a["COMMENTS"]),
        "broughtinby":          str(a["OWNERID"]),
        "originalowner":        str(a["OWNERID"]),
        "animaltype":           configuration.default_type(dbo),
        "breed1":               configuration.default_breed(dbo),
        "breed2":               configuration.default_breed(dbo),
        "basecolour":           configuration.default_colour(dbo),
        "size":                 configuration.default_size(dbo),
        "internallocation":     configuration.default_location(dbo),
        "dateofbirth":          python2display(l, subtract_years(now(dbo.timezone))),
        "estimateddob":         "1"
    }
    # If we're creating shelter codes manually, we need to put something unique
    # in there for now. Use the id
    if configuration.manual_codes(dbo):
        data["sheltercode"] = "WL" + str(wlid)
        data["shortcode"] = "WL" + str(wlid)
    nextid, code = animal.insert_animal_from_form(dbo, data, username)
    # Now that we've created our animal, we should remove this entry from the waiting list
    db.execute(dbo, "UPDATE animalwaitinglist SET DateRemovedFromList = %s, ReasonForRemoval = %s " \
        "WHERE ID = %d" % ( 
        db.dd(now(dbo.timezone)), 
        db.ds(_("Moved to animal record {0}", l).format(code)),
        wlid))
    return nextid
コード例 #46
0
 def substituteHFTag(self, searchin, page, user, title=""):
     """
     Substitutes special header and footer tokens in searchin. page
     contains the current page number.
     """
     output = searchin
     nav = self.navbar.replace(
         "<a href=\"%d.%s\">%d</a>" % (page, self.pc.extension, page),
         str(page))
     dateportion = i18n.python2display(self.locale,
                                       i18n.now(self.dbo.timezone))
     timeportion = i18n.format_date("%H:%M:%S", i18n.now(self.dbo.timezone))
     if page != -1:
         output = output.replace("$$NAV$$", nav)
     else:
         output = output.replace("$$NAV$$", "")
     output = output.replace("$$TITLE$$", title)
     output = output.replace("$$TOTAL$$", str(self.totalAnimals))
     output = output.replace("$$DATE$$", dateportion)
     output = output.replace("$$TIME$$", timeportion)
     output = output.replace("$$DATETIME$$",
                             "%s %s" % (dateportion, timeportion))
     output = output.replace("$$VERSION$$", i18n.get_version())
     output = output.replace("$$REGISTEREDTO$$",
                             configuration.organisation(self.dbo))
     output = output.replace(
         "$$USER$$",
         "%s (%s)" % (user, users.get_real_name(self.dbo, user)))
     output = output.replace("$$ORGNAME$$",
                             configuration.organisation(self.dbo))
     output = output.replace("$$ORGADDRESS$$",
                             configuration.organisation_address(self.dbo))
     output = output.replace("$$ORGTEL$$",
                             configuration.organisation_telephone(self.dbo))
     output = output.replace("$$ORGEMAIL$$", configuration.email(self.dbo))
     return output
コード例 #47
0
ファイル: utils.py プロジェクト: tgage/asm3
def csv(l, rows, cols=None, includeheader=True):
    """
    Creates a CSV file from a set of resultset rows. If cols has been 
    supplied as a list of strings, fields will be output in that
    order.
    """
    if rows is None or len(rows) == 0: return ""
    strio = StringIO()
    out = UnicodeCSVWriter(strio)
    if cols is None:
        cols = []
        for k, v in rows[0].iteritems():
            cols.append(k)
        cols = sorted(cols)
    if includeheader:
        out.writerow(cols)
    for r in rows:
        rd = []
        for c in cols:
            if is_currency(c):
                rd.append(decode_html(format_currency_no_symbol(l, r[c])))
            elif is_date(r[c]):
                timeportion = "00:00:00"
                dateportion = ""
                try:
                    dateportion = python2display(l, r[c])
                    timeportion = format_time(r[c])
                except:
                    pass  # Don't stop the show for bad dates/times
                if timeportion != "00:00:00":  # include time if non-midnight
                    dateportion = "%s %s" % (dateportion, timeportion)
                rd.append(decode_html(dateportion))
            else:
                rd.append(decode_html(r[c]))
        out.writerow(rd)
    return strio.getvalue()
コード例 #48
0
def update_waitinglist_remove(dbo, username, wid):
    """
    Marks a waiting list record as removed
    """
    db.execute(dbo, "UPDATE animalwaitinglist SET DateRemovedFromList = %s WHERE ID = %d" % ( db.dd(now(dbo.timezone)), int(wid) ))
    audit.edit(dbo, username, "animalwaitinglist", "%s: DateRemovedFromList ==> %s" % ( str(wid), python2display(dbo.locale, now(dbo.timezone))))
コード例 #49
0
ファイル: smarttag.py プロジェクト: rutaq/asm3
    def run(self):

        if self.isPublisherExecuting(): return
        self.updatePublisherProgress(0)
        self.setLastError("")
        self.setStartPublishing()

        shelterid = configuration.smarttag_accountid(self.dbo)
        if shelterid == "":
            self.setLastError("No SmartTag Account id has been set.")
            self.cleanup()
            return

        animals = get_microchip_data(
            self.dbo,
            ["a.SmartTag = 1 AND a.SmartTagNumber <> ''"] + SMARTTAG_PREFIXES,
            "smarttag")
        if len(animals) == 0:
            self.setLastError("No animals found to publish.")
            self.cleanup(save_log=False)
            return

        if not self.openFTPSocket():
            self.setLastError("Failed to open FTP socket.")
            if self.logSearch("530 Login") != -1:
                self.log(
                    "Found 530 Login incorrect: disabling SmartTag publisher.")
                configuration.publishers_enabled_disable(self.dbo, "st")
            self.cleanup()
            return

        # SmartTag want data files called shelterid_mmddyyyy_HHMMSS.csv in a folder
        # called shelterid_mmddyyyy_HHMMSS
        dateportion = i18n.format_date("%m%d%Y_%H%M%S",
                                       i18n.now(self.dbo.timezone))
        folder = "%s_%s" % (shelterid, dateportion)
        outputfile = "%s_%s.csv" % (shelterid, dateportion)
        self.mkdir(folder)
        self.chdir(folder)

        csv = []

        anCount = 0
        for an in animals:
            try:
                line = []
                anCount += 1
                self.log("Processing: %s: %s (%d of %d)" %
                         (an["SHELTERCODE"], an["ANIMALNAME"], anCount,
                          len(animals)))
                self.updatePublisherProgress(
                    self.getProgress(anCount, len(animals)))

                # If the user cancelled, stop now
                if self.shouldStopPublishing():
                    self.log("User cancelled publish. Stopping.")
                    self.resetPublisherProgress()
                    self.cleanup()
                    return

                # Upload one image for this animal with the name shelterid_animalid-1.jpg
                self.uploadImage(an, an["WEBSITEMEDIANAME"],
                                 "%s_%d-1.jpg" % (shelterid, an["ID"]))
                # accountid
                line.append("\"%s\"" % shelterid)
                # sourcesystem
                line.append("\"ASM\"")
                # sourcesystemanimalkey (corresponds to image name)
                line.append("\"%d\"" % an["ID"])
                # sourcesystemownerkey
                line.append("\"%s\"" % str(an["CURRENTOWNERID"]))
                # signupidassigned, signuptype
                if self.stIsSmartTagPrefix(an["IDENTICHIPNUMBER"]):
                    # if we have a smarttag microchip number, use that instead of the tag
                    # since it's unlikely someone will want both
                    line.append("\"%s\"" % an["IDENTICHIPNUMBER"])
                    line.append("\"IDTAG-LIFETIME\"")
                else:
                    line.append("\"%s\"" % an["SMARTTAGNUMBER"])
                    sttype = "IDTAG-ANNUAL"
                    if an["SMARTTAGTYPE"] == 1: sttype = "IDTAG-5 YEAR"
                    if an["SMARTTAGTYPE"] == 2: sttype = "IDTAG-LIFETIME"
                    line.append("\"%s\"" % sttype)
                # signupeffectivedate
                line.append(
                    "\"" +
                    i18n.python2display(self.locale, an["SMARTTAGDATE"]) +
                    "\"")
                # signupbatchpostdt - only used by resending mechanism and we don't do that
                line.append("\"\"")
                # feecharged
                line.append("\"\"")
                # feecollected
                line.append("\"\"")
                # owner related stuff
                address = an["CURRENTOWNERADDRESS"]
                houseno = utils.address_house_number(address)
                streetname = utils.address_street_name(address)
                # ownerfname
                line.append("\"%s\"" % an["CURRENTOWNERFORENAMES"])
                # ownermname
                line.append("\"\"")
                #ownerlname
                line.append("\"%s\"" % an["CURRENTOWNERSURNAME"])
                # addressstreetnumber
                line.append("\"%s\"" % houseno)
                # addressstreetdir
                line.append("\"\"")
                # addressstreetname
                line.append("\"%s\"" % streetname)
                # addressstreettype
                line.append("\"\"")
                # addresscity
                line.append("\"%s\"" % an["CURRENTOWNERTOWN"])
                # addressstate
                line.append("\"%s\"" % an["CURRENTOWNERCOUNTY"])
                # addresspostal
                line.append("\"%s\"" % an["CURRENTOWNERPOSTCODE"])
                # addressctry
                line.append("\"USA\"")
                # owneremail
                line.append("\"%s\"" % an["CURRENTOWNEREMAILADDRESS"])
                # owneremail2
                line.append("\"\"")
                # owneremail3
                line.append("\"\"")
                # ownerhomephone
                line.append("\"%s\"" % an["CURRENTOWNERHOMETELEPHONE"])
                # ownerworkphone
                line.append("\"%s\"" % an["CURRENTOWNERWORKTELEPHONE"])
                # ownerthirdphone
                line.append("\"%s\"" % an["CURRENTOWNERMOBILETELEPHONE"])
                # petname
                line.append("\"%s\"" % an["ANIMALNAME"].replace("\"", "\"\""))
                # species
                line.append("\"%s\"" % an["SPECIESNAME"])
                # primarybreed
                line.append("\"%s\"" % an["BREEDNAME1"])
                # crossbreed (second breed)
                if an["CROSSBREED"] == 1:
                    line.append("\"%s\"" % an["BREEDNAME2"])
                else:
                    line.append("\"\"")
                # purebred
                line.append("\"%s\"" % self.stYesNo(an["CROSSBREED"] == 0))
                # gender
                line.append("\"%s\"" % an["SEXNAME"])
                # sterilized
                line.append("\"%s\"" % self.stYesNo(an["NEUTERED"] == 1))
                # primarycolor
                line.append("\"%s\"" % an["BASECOLOURNAME"])
                # secondcolor
                line.append("\"\"")
                # sizecategory
                line.append("\"%s\"" % an["SIZENAME"])
                # agecategory
                line.append("\"%s\"" % an["AGEGROUP"])
                # declawed
                line.append("\"%s\"" % self.stYesNo(an["DECLAWED"] == 1))
                # animalstatus (one of DECEASED, ADOPTED or NOT ADOPTED)
                if an["DECEASEDDATE"] is not None:
                    line.append("\"DECEASED\"")
                elif an["ACTIVEMOVEMENTTYPE"] == 1 and an[
                        "ACTIVEMOVEMENTDATE"] is not None:
                    line.append("\"ADOPTED\"")
                else:
                    line.append("\"NOT ADOPTED\"")
                # Add to our CSV file
                csv.append(",".join(line))
                # Mark success in the log
                self.logSuccess("Processed: %s: %s (%d of %d)" %
                                (an["SHELTERCODE"], an["ANIMALNAME"], anCount,
                                 len(animals)))
            except Exception as err:
                self.logError(
                    "Failed processing animal: %s, %s" %
                    (str(an["SHELTERCODE"]), err), sys.exc_info())

        # Mark published
        self.markAnimalsPublished(animals)

        header = "accountid,sourcesystem,sourcesystemanimalkey," \
            "sourcesystemownerkey,signupidassigned,signuptype,signupeffectivedate," \
            "signupbatchpostdt,feecharged,feecollected,ownerfname,ownermname," \
            "ownerlname,addressstreetnumber,addressstreetdir,addressstreetname," \
            "addressstreettype,addresscity,addressstate,addresspostal,addressctry," \
            "owneremail,owneremail2,owneremail3,ownerhomephone,ownerworkphone," \
            "ownerthirdphone,petname,species,primarybreed,crossbreed,purebred,gender," \
            "sterilized,primarycolor,secondcolor,sizecategory,agecategory,declawed," \
            "animalstatus\n"
        self.saveFile(os.path.join(self.publishDir, outputfile),
                      header + "\n".join(csv))
        self.log("Uploading datafile %s" % outputfile)
        self.upload(outputfile)
        self.log("Uploaded %s" % outputfile)
        self.log("-- FILE DATA --")
        self.log(header + "\n".join(csv))
        self.cleanup()
コード例 #50
0
def person_tags(dbo, p):
    """
    Generates a list of tags from a person result (the deep type from
    calling person.get_person)
    """
    l = dbo.locale
    tags = { 
        "OWNERID"               : str(p["ID"]),
        "OWNERCODE"             : p["OWNERCODE"],
        "OWNERTITLE"            : p["OWNERTITLE"],
        "TITLE"                 : p["OWNERTITLE"],
        "OWNERINITIALS"         : p["OWNERINITIALS"],
        "INITIALS"              : p["OWNERINITIALS"],
        "OWNERFORENAMES"        : p["OWNERFORENAMES"],
        "FORENAMES"             : p["OWNERFORENAMES"],
        "OWNERFIRSTNAMES"       : p["OWNERFORENAMES"],
        "FIRSTNAMES"            : p["OWNERFORENAMES"],
        "OWNERSURNAME"          : p["OWNERSURNAME"],
        "SURNAME"               : p["OWNERSURNAME"],
        "OWNERLASTNAME"         : p["OWNERSURNAME"],
        "LASTNAME"              : p["OWNERSURNAME"],
        "OWNERNAME"             : p["OWNERNAME"],
        "NAME"                  : p["OWNERNAME"],
        "OWNERADDRESS"          : p["OWNERADDRESS"],
        "ADDRESS"               : p["OWNERADDRESS"],
        "OWNERTOWN"             : p["OWNERTOWN"],
        "TOWN"                  : p["OWNERTOWN"],
        "OWNERCOUNTY"           : p["OWNERCOUNTY"],
        "COUNTY"                : p["OWNERCOUNTY"],
        "OWNERCITY"             : p["OWNERTOWN"],
        "CITY"                  : p["OWNERTOWN"],
        "OWNERSTATE"            : p["OWNERCOUNTY"],
        "STATE"                 : p["OWNERCOUNTY"],
        "OWNERPOSTCODE"         : p["OWNERPOSTCODE"],
        "POSTCODE"              : p["OWNERPOSTCODE"],
        "OWNERZIPCODE"          : p["OWNERPOSTCODE"],
        "ZIPCODE"               : p["OWNERPOSTCODE"],
        "HOMETELEPHONE"         : p["HOMETELEPHONE"],
        "WORKTELEPHONE"         : p["WORKTELEPHONE"],
        "MOBILETELEPHONE"       : p["MOBILETELEPHONE"],
        "CELLTELEPHONE"         : p["MOBILETELEPHONE"],
        "EMAILADDRESS"          : p["EMAILADDRESS"],
        "OWNERCOMMENTS"         : p["COMMENTS"],
        "COMMENTS"              : p["COMMENTS"],
        "OWNERCREATEDBY"        : p["CREATEDBY"],
        "OWNERCREATEDBYNAME"    : p["CREATEDBY"],
        "OWNERCREATEDDATE"      : python2display(l, p["CREATEDDATE"]),
        "OWNERLASTCHANGEDBY"    : p["LASTCHANGEDBY"],
        "OWNERLASTCHANGEDBYNAME" : p["LASTCHANGEDBY"],
        "OWNERLASTCHANGEDDATE"  : python2display(l, p["LASTCHANGEDDATE"]),
        "IDCHECK"               : (p["IDCHECK"] == 1 and _("Yes", l) or _("No", l)),
        "MEMBERSHIPNUMBER"      : p["MEMBERSHIPNUMBER"],
        "MEMBERSHIPEXPIRYDATE"  : python2display(l, p["MEMBERSHIPEXPIRYDATE"])
    }

    # Additional fields
    add = additional.get_additional_fields(dbo, int(p["ID"]), "person")
    for af in add:
        val = af["VALUE"]
        if af["FIELDTYPE"] == additional.YESNO:
            val = additional_yesno(l, af)
        tags[af["FIELDNAME"].upper()] = val

    return tags
コード例 #51
0
ファイル: diary.py プロジェクト: MoriEdan/sheltermanager
        al.error("failed getting list of users: %s" % str(err), "diary.email_uncompleted_upto_today", dbo)
    # Grab list of diary notes for today
    notes = get_uncompleted_upto_today(dbo)
    # If we don't have any, bail out
    if len(notes) == 0: return
    # Go through all user to see if we have relevant notes for them
    for u in allusers:
        if u["EMAILADDRESS"] is not None and u["EMAILADDRESS"].strip() != "":
            s = ""
            totalforuser = 0
            for n in notes:
                # Is this note relevant for this user?
                if (n["DIARYFORNAME"] == i18n._("(all)", l) or n["DIARYFORNAME"] == i18n._("(everyone)", l)) \
                or (n["DIARYFORNAME"] == u["USERNAME"]) \
                or (u["ROLES"].find(n["DIARYFORNAME"]) != -1):
                    s += i18n.python2display(l, n["DIARYDATETIME"]) + " "
                    s += n["SUBJECT"]
                    if n["LINKINFO"] is not None and n["LINKINFO"] != "": s += " / " + n["LINKINFO"]
                    s += "\n" + n["NOTE"] + "\n\n"
                    totalforuser += 1
            if totalforuser > 0:
                al.debug("got %d notes for user %s" % (totalforuser, u["USERNAME"]), "diary.email_uncompleted_upto_today", dbo)
                utils.send_email(dbo, "*****@*****.**", u["EMAILADDRESS"], "", 
                    i18n._("Diary notes for: {0}", l).format(i18n.python2display(l, i18n.now(dbo.timezone))), s)

def user_role_where_clause(dbo, user = ""):
    """
    Returns a suitable where clause for filtering diary notes
    to the given user or any roles the user is in. If user is
    blank, the where clause return is empty.
    """
コード例 #52
0
ファイル: mobile.py プロジェクト: MoriEdan/sheltermanager
def handler_viewanimal(l, a, af, homelink, post):
    """
    Generate the view animal mobile page.
    l:  The locale
    a:  An animal record
    af: Additional fields for the animal record
    homelink: Link to the home menu
    post: The posted values
    """

    def table():
        return "<table style='width: 100%; border-bottom: 1px solid black;'>"

    def table_end():
        return "</table>"

    def tr(label, value, value2=""):
        if value is None or str(value).startswith("None "):
            value = ""
        if value2 is None or str(value2).startswith("None"):
            value2 = ""
        if value2 is not None and value2 != "":
            value2 = "<td>%s</td>" % value2
        return "<tr><td style='font-weight: bold; width: 150px'>%s</td><td>%s</td>%s</tr>" % (label, value, value2)

    h = []
    h.append(header(l))
    h.append(jqm_page_header("", "%s - %s" % (a["CODE"], a["ANIMALNAME"]), homelink))
    h.append(table())
    h.append("<td><img src='%s' class='asm-thumbnail' /></td>" % html.thumbnail_img_src(a, "animalthumb"))
    h.append("<td><h2 style='margin: 2px;'>%s - %s</h2>" % (a["CODE"], a["ANIMALNAME"]))
    h.append("%s %s %s</td>" % (a["SEXNAME"], a["BREEDNAME"], a["SPECIESNAME"]))
    h.append("</tr></table>")
    h.append(table())
    uploadstatus = ""
    if post["success"] == "true":
        uploadstatus = _("Photo successfully uploaded.", l)
    h.append(
        """
        <tr><td style='font-weight: bold; width: 150px;'>%s</td>
        <td>
        <form data-ajax="false" action="mobile_post" method="post" enctype="multipart/form-data">
        <input type="hidden" name="animalid" value="%d" />
        <input type="hidden" name="posttype" value="uai" />
        <input type="hidden" name="comments" value="" />
        <input type="hidden" name="base64image" value="" />
        <input type="file" data-role='none' name="filechooser" id="fc%d" />
        <span class=".tipios6" style="display: none">%s</span>
        <input id='sfc%d' type='submit' data-icon='arrow-u' data-inline='true' data-mini='true' value='%s' />
        </form>
        <span class="tip">%s</span>
        </td></tr>"""
        % (
            _("Upload Photo", l),
            a["ID"],
            a["ID"],
            _("You will need to upgrade to iOS 6 or higher to upload files.", l),
            a["ID"],
            _("Send", l),
            uploadstatus,
        )
    )
    h.append(table())
    h.append(tr(_("Type", l), a["ANIMALTYPENAME"]))
    h.append(tr(_("Location", l), a["DISPLAYLOCATIONNAME"]))
    h.append(tr(_("Color", l), a["BASECOLOURNAME"]))
    h.append(tr(_("Coat Type", l), a["COATTYPENAME"]))
    h.append(tr(_("Size", l), a["SIZENAME"]))
    h.append(tr(_("DOB", l), python2display(l, a["DATEOFBIRTH"]), a["ANIMALAGE"]))
    h.append(table_end())
    h.append(table())
    h.append(tr(_("Markings", l), a["MARKINGS"]))
    h.append(tr(_("Hidden Comments", l), a["HIDDENANIMALDETAILS"]))
    h.append(tr(_("Comments", l), a["ANIMALCOMMENTS"]))
    h.append(table_end())
    h.append(table())
    h.append(tr(_("Cats", l), a["ISGOODWITHCATSNAME"]))
    h.append(tr(_("Dogs", l), a["ISGOODWITHDOGSNAME"]))
    h.append(tr(_("Children", l), a["ISGOODWITHCHILDRENNAME"]))
    h.append(tr(_("Housetrained", l), a["ISHOUSETRAINEDNAME"]))
    h.append(table_end())
    h.append(table())
    h.append(tr(_("Original Owner", l), a["ORIGINALOWNERNAME"]))
    h.append(tr(_("Brought In By", l), a["BROUGHTINBYOWNERNAME"]))
    h.append(tr(_("Date Brought In", l), python2display(l, a["DATEBROUGHTIN"])))
    h.append(
        tr(
            _("Bonded With", l),
            "%s %s %s %s"
            % (a["BONDEDANIMAL1CODE"], a["BONDEDANIMAL1NAME"], a["BONDEDANIMAL2CODE"], a["BONDEDANIMAL2NAME"]),
        )
    )
    h.append(tr(_("Transfer?", l), a["ISTRANSFERNAME"] == 1))
    h.append(tr(_("Entry Category", l), a["ENTRYREASONNAME"]))
    h.append(tr(_("Entry Reason", l), a["REASONFORENTRY"]))
    h.append(table_end())
    h.append(table())
    h.append(tr(_("Microchipped", l), python2display(l, a["IDENTICHIPDATE"]), a["IDENTICHIPNUMBER"]))
    h.append(tr(_("Tattoo", l), python2display(l, a["TATTOODATE"]), a["TATTOONUMBER"]))
    h.append(tr(_("Neutered", l), python2display(l, a["NEUTEREDDATE"])))
    h.append(tr(_("Declawed", l), a["DECLAWEDNAME"]))
    h.append(tr(_("Heartworm Tested", l), python2display(l, a["HEARTWORMTESTDATE"]), a["HEARTWORMTESTRESULTNAME"]))
    h.append(
        tr(
            _("FIV/L Tested", l),
            python2display(l, a["COMBITESTDATE"]),
            "%s %s" % (a["COMBITESTRESULTNAME"], a["FLVRESULTNAME"]),
        )
    )
    h.append(tr(_("Health Problems", l), a["HEALTHPROBLEMS"]))
    h.append(tr(_("Rabies Tag", l), a["RABIESTAG"]))
    h.append(tr(_("Special Needs", l), a["HASSPECIALNEEDSNAME"]))
    h.append(tr(_("Current Vet", l), a["CURRENTVETNAME"], a["CURRENTVETWORKTELEPHONE"]))
    h.append(table_end())
    if len(af) > 0:
        h.append(table())
        for d in af:
            h.append(tr(d["FIELDLABEL"], d["VALUE"]))
        h.append(table_end())
    h.append(
        """
    <script type="text/javascript">
        // If this is an idevice and the file upload box is
        // disabled, it needs upgrading to iOS6 or better.
        if (is_idevice && $("#fc%d").attr("disabled")) {
            $(".tipios6").show();
        }
    </script>
    """
        % (a["ID"])
    )
    h.append(jqm_page_footer())
    h.append("</body></html>")
    return "\n".join(h)
コード例 #53
0
def animal_tags(dbo, a):
    """
    Generates a list of tags from an animal result (the deep type from
    calling animal.get_animal)
    """
    l = dbo.locale
    displaydob = python2display(l, a["DATEOFBIRTH"])
    displayage = a["ANIMALAGE"]
    estimate = ""
    if a["ESTIMATEDDOB"] == 1: 
        displaydob = a["AGEGROUP"]
        displayage = a["AGEGROUP"]
        estimate = _("estimate", l)

    tags = { 
        "ANIMALNAME"            : a["ANIMALNAME"],
        "ANIMALTYPENAME"        : a["ANIMALTYPENAME"],
        "BASECOLOURNAME"        : a["BASECOLOURNAME"],
        "BASECOLORNAME"         : a["BASECOLOURNAME"],
        "BREEDNAME"             : a["BREEDNAME"],
        "INTERNALLOCATION"      : a["SHELTERLOCATIONNAME"],
        "LOCATIONUNIT"          : a["SHELTERLOCATIONUNIT"],
        "COATTYPE"              : a["COATTYPENAME"],
        "HEALTHPROBLEMS"        : a["HEALTHPROBLEMS"],
        "ANIMALCREATEDBY"       : a["CREATEDBY"],
        "ANIMALCREATEDDATE"     : python2display(l, a["CREATEDDATE"]),
        "DATEBROUGHTIN"         : python2display(l, a["DATEBROUGHTIN"]),
        "DATEOFBIRTH"           : python2display(l, a["DATEOFBIRTH"]),
        "AGEGROUP"              : a["AGEGROUP"],
        "DISPLAYDOB"            : displaydob,
        "DISPLAYAGE"            : displayage,
        "ESTIMATEDDOB"          : estimate,
        "ANIMALID"              : str(a["ID"]),
        "IDENTICHIPNUMBER"      : a["IDENTICHIPNUMBER"],
        "IDENTICHIPPED"         : a["IDENTICHIPPEDNAME"],
        "IDENTICHIPPEDDATE"     : python2display(l, a["IDENTICHIPDATE"]),
        "MICROCHIPNUMBER"       : a["IDENTICHIPNUMBER"],
        "MICROCHIPPED"          : a["IDENTICHIPPEDNAME"],
        "MICROCHIPDATE"         : python2display(l, a["IDENTICHIPDATE"]),
        "TATTOO"                : a["TATTOONAME"],
        "TATTOODATE"            : python2display(l, a["TATTOODATE"]),
        "TATTOONUMBER"          : a["TATTOONUMBER"],
        "COMBITESTED"           : a["COMBITESTEDNAME"],
        "FIVLTESTED"            : a["COMBITESTEDNAME"],
        "COMBITESTDATE"         : python2display(l, a["COMBITESTDATE"]),
        "FIVLTESTDATE"          : python2display(l, a["COMBITESTDATE"]),
        "COMBITESTRESULT"       : a["COMBITESTRESULTNAME"],
        "FIVTESTRESULT"         : a["COMBITESTRESULTNAME"],
        "FIVRESULT"             : a["COMBITESTRESULTNAME"],
        "FLVTESTRESULT"         : a["FLVRESULTNAME"],
        "FLVRESULT"             : a["FLVRESULTNAME"],
        "HEARTWORMTESTED"       : a["HEARTWORMTESTEDNAME"],
        "HEARTWORMTESTDATE"     : python2display(l, a["HEARTWORMTESTDATE"]),
        "HEARTWORMTESTRESULT"   : a["HEARTWORMTESTRESULTNAME"],
        "HIDDENANIMALDETAILS"   : a["HIDDENANIMALDETAILS"],
        "ANIMALLASTCHANGEDBY"   : a["LASTCHANGEDBY"],
        "ANIMALLASTCHANGEDDATE" : python2display(l, a["LASTCHANGEDDATE"]),
        "MARKINGS"              : a["MARKINGS"],
        "DECLAWED"              : a["DECLAWEDNAME"],
        "RABIESTAG"             : a["RABIESTAG"],
        "GOODWITHCATS"          : a["ISGOODWITHCATSNAME"],
        "GOODWITHDOGS"          : a["ISGOODWITHDOGSNAME"],
        "GOODWITHCHILDREN"      : a["ISGOODWITHCHILDRENNAME"],
        "HOUSETRAINED"          : a["ISHOUSETRAINEDNAME"],
        "NAMEOFPERSONBROUGHTANIMALIN" : a["BROUGHTINBYOWNERNAME"],
        "ADDRESSOFPERSONBROUGHTANIMALIN" : a["BROUGHTINBYOWNERADDRESS"],
        "TOWNOFPERSONBROUGHTANIMALIN" : a["BROUGHTINBYOWNERTOWN"],
        "COUNTYOFPERSONBROUGHTANIMALIN": a["BROUGHTINBYOWNERCOUNTY"],
        "POSTCODEOFPERSONBROUGHTIN": a["BROUGHTINBYOWNERPOSTCODE"],
        "CITYOFPERSONBROUGHTANIMALIN" : a["BROUGHTINBYOWNERTOWN"],
        "STATEOFPERSONBROUGHTANIMALIN": a["BROUGHTINBYOWNERCOUNTY"],
        "ZIPCODEOFPERSONBROUGHTIN": a["BROUGHTINBYOWNERPOSTCODE"],
        "BROUGHTINBYNAME"     : a["BROUGHTINBYOWNERNAME"],
        "BROUGHTINBYADDRESS"  : a["BROUGHTINBYOWNERADDRESS"],
        "BROUGHTINBYTOWN"     : a["BROUGHTINBYOWNERTOWN"],
        "BROUGHTINBYCOUNTY"   : a["BROUGHTINBYOWNERCOUNTY"],
        "BROUGHTINBYPOSTCODE" : a["BROUGHTINBYOWNERPOSTCODE"],
        "BROUGHTINBYCITY"     : a["BROUGHTINBYOWNERTOWN"],
        "BROUGHTINBYSTATE"    : a["BROUGHTINBYOWNERCOUNTY"],
        "BROUGHTINBYZIPCODE"  : a["BROUGHTINBYOWNERPOSTCODE"],
        "BROUGHTINBYHOMEPHONE" : a["BROUGHTINBYHOMETELEPHONE"],
        "BROUGHTINBYPHONE"    : a["BROUGHTINBYHOMETELEPHONE"],
        "BROUGHTINBYWORKPHONE" : a["BROUGHTINBYWORKTELEPHONE"],
        "BROUGHTINBYMOBILEPHONE" : a["BROUGHTINBYMOBILETELEPHONE"],
        "BROUGHTINBYCELLPHONE" : a["BROUGHTINBYMOBILETELEPHONE"],
        "BROUGHTINBYEMAIL"    : a["BROUGHTINBYEMAILADDRESS"],
        "NAMEOFOWNERSVET"       : a["OWNERSVETNAME"],
        "NAMEOFCURRENTVET"      : a["CURRENTVETNAME"],
        "HASSPECIALNEEDS"       : a["HASSPECIALNEEDSNAME"],
        "NEUTERED"              : a["NEUTEREDNAME"],
        "FIXED"                 : a["NEUTEREDNAME"],
        "ALTERED"               : a["NEUTEREDNAME"],
        "NEUTEREDDATE"          : python2display(l, a["NEUTEREDDATE"]),
        "FIXEDDATE"             : python2display(l, a["NEUTEREDDATE"]),
        "ALTEREDDATE"           : python2display(l, a["NEUTEREDDATE"]),
        "ORIGINALOWNERNAME"     : a["ORIGINALOWNERNAME"],
        "ORIGINALOWNERADDRESS"  : a["ORIGINALOWNERADDRESS"],
        "ORIGINALOWNERTOWN"     : a["ORIGINALOWNERTOWN"],
        "ORIGINALOWNERCOUNTY"   : a["ORIGINALOWNERCOUNTY"],
        "ORIGINALOWNERPOSTCODE" : a["ORIGINALOWNERPOSTCODE"],
        "ORIGINALOWNERCITY"     : a["ORIGINALOWNERTOWN"],
        "ORIGINALOWNERSTATE"    : a["ORIGINALOWNERCOUNTY"],
        "ORIGINALOWNERZIPCODE"  : a["ORIGINALOWNERPOSTCODE"],
        "ORIGINALOWNERHOMEPHONE" : a["ORIGINALOWNERHOMETELEPHONE"],
        "ORIGINALOWNERPHONE"    : a["ORIGINALOWNERHOMETELEPHONE"],
        "ORIGINALOWNERWORKPHONE" : a["ORIGINALOWNERWORKTELEPHONE"],
        "ORIGINALOWNERMOBILEPHONE" : a["ORIGINALOWNERMOBILETELEPHONE"],
        "ORIGINALOWNERCELLPHONE" : a["ORIGINALOWNERMOBILETELEPHONE"],
        "ORIGINALOWNEREMAIL"    : a["ORIGINALOWNEREMAILADDRESS"],
        "CURRENTOWNERNAME"     : a["CURRENTOWNERNAME"],
        "CURRENTOWNERADDRESS"  : a["CURRENTOWNERADDRESS"],
        "CURRENTOWNERTOWN"     : a["CURRENTOWNERTOWN"],
        "CURRENTOWNERCOUNTY"   : a["CURRENTOWNERCOUNTY"],
        "CURRENTOWNERPOSTCODE" : a["CURRENTOWNERPOSTCODE"],
        "CURRENTOWNERCITY"     : a["CURRENTOWNERTOWN"],
        "CURRENTOWNERSTATE"    : a["CURRENTOWNERCOUNTY"],
        "CURRENTOWNERZIPCODE"  : a["CURRENTOWNERPOSTCODE"],
        "CURRENTOWNERHOMEPHONE" : a["CURRENTOWNERHOMETELEPHONE"],
        "CURRENTOWNERPHONE"    : a["CURRENTOWNERHOMETELEPHONE"],
        "CURRENTOWNERWORKPHONE" : a["CURRENTOWNERWORKTELEPHONE"],
        "CURRENTOWNERMOBILEPHONE" : a["CURRENTOWNERMOBILETELEPHONE"],
        "CURRENTOWNERCELLPHONE" : a["CURRENTOWNERMOBILETELEPHONE"],
        "CURRENTOWNEREMAIL"     : a["CURRENTOWNEREMAILADDRESS"],
        "CURRENTVETNAME"        : a["CURRENTVETNAME"],
        "CURRENTVETADDRESS"     : a["CURRENTVETADDRESS"],
        "CURRENTVETTOWN"        : a["CURRENTVETTOWN"],
        "CURRENTVETCOUNTY"      : a["CURRENTVETCOUNTY"],
        "CURRENTVETPOSTCODE"    : a["CURRENTVETPOSTCODE"],
        "CURRENTVETCITY"        : a["CURRENTVETTOWN"],
        "CURRENTVETSTATE"       : a["CURRENTVETCOUNTY"],
        "CURRENTVETZIPCODE"     : a["CURRENTVETPOSTCODE"],
        "CURRENTVETPHONE"       : a["CURRENTVETWORKTELEPHONE"],
        "OWNERSVETNAME"         : a["OWNERSVETNAME"],
        "OWNERSVETADDRESS"      : a["OWNERSVETADDRESS"],
        "OWNERSVETTOWN"         : a["OWNERSVETTOWN"],
        "OWNERSVETCOUNTY"       : a["OWNERSVETCOUNTY"],
        "OWNERSVETPOSTCODE"     : a["OWNERSVETPOSTCODE"],
        "OWNERSVETCITY"         : a["OWNERSVETTOWN"],
        "OWNERSVETSTATE"        : a["OWNERSVETCOUNTY"],
        "OWNERSVETZIPCODE"      : a["OWNERSVETPOSTCODE"],
        "OWNERSVETPHONE"        : a["OWNERSVETWORKTELEPHONE"],
        "RESERVEDOWNERNAME"     : a["RESERVEDOWNERNAME"],
        "RESERVEDOWNERADDRESS"  : a["RESERVEDOWNERADDRESS"],
        "RESERVEDOWNERTOWN"     : a["RESERVEDOWNERTOWN"],
        "RESERVEDOWNERCOUNTY"   : a["RESERVEDOWNERCOUNTY"],
        "RESERVEDOWNERPOSTCODE" : a["RESERVEDOWNERPOSTCODE"],
        "RESERVEDOWNERCITY"     : a["RESERVEDOWNERTOWN"],
        "RESERVEDOWNERSTATE"    : a["RESERVEDOWNERCOUNTY"],
        "RESERVEDOWNERZIPCODE"  : a["RESERVEDOWNERPOSTCODE"],
        "RESERVEDOWNERHOMEPHONE" : a["RESERVEDOWNERHOMETELEPHONE"],
        "RESERVEDOWNERPHONE"    : a["RESERVEDOWNERHOMETELEPHONE"],
        "RESERVEDOWNERWORKPHONE" : a["RESERVEDOWNERWORKTELEPHONE"],
        "RESERVEDOWNERMOBILEPHONE" : a["RESERVEDOWNERMOBILETELEPHONE"],
        "RESERVEDOWNERCELLPHONE" : a["RESERVEDOWNERMOBILETELEPHONE"],
        "RESERVEDOWNEREMAIL"    : a["RESERVEDOWNEREMAILADDRESS"],
        "ENTRYCATEGORY"         : a["ENTRYREASONNAME"],
        "REASONFORENTRY"        : a["REASONFORENTRY"],
        "REASONNOTBROUGHTBYOWNER" : a["REASONNO"],
        "SEX"                   : a["SEXNAME"],
        "SIZE"                  : a["SIZENAME"],
        "SPECIESNAME"           : a["SPECIESNAME"],
        "ANIMALCOMMENTS"        : a["ANIMALCOMMENTS"],
        "SHELTERCODE"           : a["SHELTERCODE"],
        "AGE"                   : a["ANIMALAGE"],
        "ACCEPTANCENUMBER"      : a["ACCEPTANCENUMBER"],
        "LITTERID"              : a["ACCEPTANCENUMBER"],
        "DECEASEDDATE"          : python2display(l, a["DECEASEDDATE"]),
        "DECEASEDNOTES"         : a["PTSREASON"],
        "DECEASEDCATEGORY"      : a["PTSREASONNAME"],
        "SHORTSHELTERCODE"      : a["SHORTCODE"],
        "MOSTRECENTENTRY"       : python2display(l, a["MOSTRECENTENTRYDATE"]),
        "TIMEONSHELTER"         : a["TIMEONSHELTER"],
        "WEBMEDIAFILENAME"      : a["WEBSITEMEDIANAME"],
        "WEBSITEMEDIANAME"      : a["WEBSITEMEDIANAME"],
        "WEBSITEVIDEOURL"       : a["WEBSITEVIDEOURL"],
        "WEBSITEVIDEONOTES"     : a["WEBSITEVIDEONOTES"],
        "WEBMEDIANOTES"         : a["WEBSITEMEDIANOTES"],
        "WEBSITEMEDIANOTES"     : a["WEBSITEMEDIANOTES"],
        "DOCUMENTIMGLINK"       : "<img height=\"200\" src=\"" + html.img_src(a, "animal") + "\" >",
        "DOCUMENTIMGTHUMBLINK"  : "<img src=\"" + html.thumbnail_img_src(a, "animalthumb") + "\" />",
        "DOCUMENTQRLINK"        : "<img src=\"http://chart.apis.google.com/chart?cht=qr&chl=%s&chs=150x150\" />" % (BASE_URL + "/animal?id=%s" % a["ID"]),
        "ANIMALONSHELTER"       : yes_no(l, a["ARCHIVED"] == 0),
        "ANIMALISRESERVED"      : yes_no(l, a["HASACTIVERESERVE"] == 1),
        "ADOPTIONID"            : a["ACTIVEMOVEMENTADOPTIONNUMBER"],
        "ADOPTIONNUMBER"        : a["ACTIVEMOVEMENTADOPTIONNUMBER"],
        "INSURANCENUMBER"       : a["ACTIVEMOVEMENTINSURANCENUMBER"],
        "RESERVATIONDATE"       : python2display(l, a["ACTIVEMOVEMENTRESERVATIONDATE"]),
        "RETURNDATE"            : python2display(l, a["ACTIVEMOVEMENTRETURNDATE"]),
        "ADOPTIONDATE"          : python2display(l, a["ACTIVEMOVEMENTDATE"]),
        "FOSTEREDDATE"          : python2display(l, a["ACTIVEMOVEMENTDATE"]),
        "TRANSFERDATE"          : python2display(l, a["ACTIVEMOVEMENTDATE"]),
        "MOVEMENTDATE"          : python2display(l, a["ACTIVEMOVEMENTDATE"]),
        "MOVEMENTTYPE"          : a["ACTIVEMOVEMENTTYPENAME"],
        "ADOPTIONDONATION"      : format_currency_no_symbol(l, a["ACTIVEMOVEMENTDONATION"]),
        "ADOPTIONCREATEDBY"     : a["ACTIVEMOVEMENTCREATEDBY"],
        "ADOPTIONCREATEDBYNAME" : a["ACTIVEMOVEMENTCREATEDBYNAME"],
        "ADOPTIONCREATEDDATE"   : python2display(l, a["ACTIVEMOVEMENTCREATEDDATE"]),
        "ADOPTIONLASTCHANGEDBY" : a["ACTIVEMOVEMENTLASTCHANGEDBY"],
        "ADOPTIONLASTCHANGEDDATE" : python2display(l, a["ACTIVEMOVEMENTLASTCHANGEDDATE"])
    }

    # Set original owner to be current owner on non-shelter animals
    if a["NONSHELTERANIMAL"] == 1 and a["ORIGINALOWNERNAME"] is not None and a["ORIGINALOWNERNAME"] != "":
        tags["CURRENTOWNERNAME"] = a["ORIGINALOWNERNAME"]
        tags["CURRENTOWNERADDRESS"] = a["ORIGINALOWNERADDRESS"]
        tags["CURRENTOWNERTOWN"] = a["ORIGINALOWNERTOWN"]
        tags["CURRENTOWNERCOUNTY"] = a["ORIGINALOWNERCOUNTY"]
        tags["CURRENTOWNERPOSTCODE"] = a["ORIGINALOWNERPOSTCODE"]
        tags["CURRENTOWNERCITY"] = a["ORIGINALOWNERTOWN"]
        tags["CURRENTOWNERSTATE"] = a["ORIGINALOWNERCOUNTY"]
        tags["CURRENTOWNERZIPCODE"] = a["ORIGINALOWNERPOSTCODE"]
        tags["CURRENTOWNERHOMEPHONE"] = a["ORIGINALOWNERHOMETELEPHONE"]
        tags["CURRENTOWNERPHONE"] = a["ORIGINALOWNERHOMETELEPHONE"]
        tags["CURRENTOWNERWORKPHONE"] = a["ORIGINALOWNERWORKTELEPHONE"]
        tags["CURRENTOWNERMOBILEPHONE"] = a["ORIGINALOWNERMOBILETELEPHONE"]
        tags["CURRENTOWNERCELLPHONE"] = a["ORIGINALOWNERMOBILETELEPHONE"]
        tags["CURRENTOWNEREMAIL"] = a["ORIGINALOWNEREMAILADDRESS"]

    # If the animal doesn't have a current owner, but does have an open
    # movement with a future date on it, look up the owner and use that 
    # instead so that we can still generate paperwork for future adoptions.
    if a["CURRENTOWNERID"] is None or a["CURRENTOWNERID"] == 0:
        latest = animal.get_latest_movement(dbo, a["ID"])
        if latest is not None:
            p = person.get_person(dbo, latest["OWNERID"])
            if p is not None:
                tags["CURRENTOWNERNAME"] = p["OWNERNAME"]
                tags["CURRENTOWNERADDRESS"] = p["OWNERADDRESS"]
                tags["CURRENTOWNERTOWN"] = p["OWNERTOWN"]
                tags["CURRENTOWNERCOUNTY"] = p["OWNERCOUNTY"]
                tags["CURRENTOWNERPOSTCODE"] = p["OWNERPOSTCODE"]
                tags["CURRENTOWNERCITY"] = p["OWNERTOWN"]
                tags["CURRENTOWNERSTATE"] = p["OWNERCOUNTY"]
                tags["CURRENTOWNERZIPCODE"] = p["OWNERPOSTCODE"]
                tags["CURRENTOWNERHOMEPHONE"] = p["HOMETELEPHONE"]
                tags["CURRENTOWNERPHONE"] = p["HOMETELEPHONE"]
                tags["CURRENTOWNERWORKPHONE"] = p["WORKTELEPHONE"]
                tags["CURRENTOWNERMOBILEPHONE"] = p["MOBILETELEPHONE"]
                tags["CURRENTOWNERCELLPHONE"] = p["MOBILETELEPHONE"]
                tags["CURRENTOWNEREMAIL"] = p["EMAILADDRESS"]

    # Additional fields
    add = additional.get_additional_fields(dbo, int(a["ID"]), "animal")
    for af in add:
        val = af["VALUE"]
        if af["FIELDTYPE"] == additional.YESNO:
            val = additional_yesno(l, af)
        if af["FIELDTYPE"] == additional.MONEY:
            val = format_currency_no_symbol(l, af["VALUE"])
        tags[af["FIELDNAME"].upper()] = val

    include_incomplete = configuration.include_incomplete_medical_doc(dbo)
    
    # Vaccinations
    vaccasc = medical.get_vaccinations(dbo, int(a["ID"]), not include_incomplete)
    vaccdesc = medical.get_vaccinations(dbo, int(a["ID"]), not include_incomplete, medical.DESCENDING_REQUIRED)
    for idx in range(1, 101):
        tags["VACCINATIONNAME" + str(idx)] = ""
        tags["VACCINATIONREQUIRED" + str(idx)] = ""
        tags["VACCINATIONGIVEN" + str(idx)] = ""
        tags["VACCINATIONCOMMENTS" + str(idx)] = ""
        tags["VACCINATIONDESCRIPTION" + str(idx)] = ""
        tags["VACCINATIONNAMELAST" + str(idx)] = ""
        tags["VACCINATIONREQUIREDLAST" + str(idx)] = ""
        tags["VACCINATIONGIVENLAST" + str(idx)] = ""
        tags["VACCINATIONCOMMENTSLAST" + str(idx)] = ""
        tags["VACCINATIONDESCRIPTIONLAST" + str(idx)] = ""
    idx = 1
    for v in vaccasc:
        tags["VACCINATIONNAME" + str(idx)] = v["VACCINATIONTYPE"]
        tags["VACCINATIONREQUIRED" + str(idx)] = python2display(l, v["DATEREQUIRED"])
        tags["VACCINATIONGIVEN" + str(idx)] = python2display(l, v["DATEOFVACCINATION"])
        tags["VACCINATIONCOMMENTS" + str(idx)] = v["COMMENTS"]
        tags["VACCINATIONDESCRIPTION" + str(idx)] = v["VACCINATIONDESCRIPTION"]
        idx += 1
    idx = 1
    uniquetypes = {}
    recentgiven = {}
    for v in vaccdesc:
        tags["VACCINATIONNAMELAST" + str(idx)] = v["VACCINATIONTYPE"]
        tags["VACCINATIONREQUIREDLAST" + str(idx)] = python2display(l, v["DATEREQUIRED"])
        tags["VACCINATIONGIVENLAST" + str(idx)] = python2display(l, v["DATEOFVACCINATION"])
        tags["VACCINATIONCOMMENTSLAST" + str(idx)] = v["COMMENTS"]
        tags["VACCINATIONDESCRIPTIONLAST" + str(idx)] = v["VACCINATIONDESCRIPTION"]
        idx += 1
        # If this is the first of this type of vacc we've seen, make
        # some keys based on its name.
        if not uniquetypes.has_key(v["VACCINATIONTYPE"]):
            vname = v["VACCINATIONTYPE"].upper().replace(" ", "").replace("/", "")
            uniquetypes[v["VACCINATIONTYPE"]] = v
            tags["VACCINATIONNAME" + vname] = v["VACCINATIONTYPE"]
            tags["VACCINATIONREQUIRED" + vname] = python2display(l, v["DATEREQUIRED"])
            tags["VACCINATIONGIVEN" + vname] = python2display(l, v["DATEOFVACCINATION"])
            tags["VACCINATIONCOMMENTS" + vname] = v["COMMENTS"]
            tags["VACCINATIONDESCRIPTION" + vname] = v["VACCINATIONDESCRIPTION"]
        # If this is the first of this type of vacc we've seen that's been given
        # make some keys based on its name
        if not recentgiven.has_key(v["VACCINATIONTYPE"]) and v["DATEOFVACCINATION"] is not None:
            vname = v["VACCINATIONTYPE"].upper().replace(" ", "").replace("/", "")
            recentgiven[v["VACCINATIONTYPE"]] = v
            tags["VACCINATIONNAMERECENT" + vname] = v["VACCINATIONTYPE"]
            tags["VACCINATIONREQUIREDRECENT" + vname] = python2display(l, v["DATEREQUIRED"])
            tags["VACCINATIONGIVENRECENT" + vname] = python2display(l, v["DATEOFVACCINATION"])
            tags["VACCINATIONCOMMENTSRECENT" + vname] = v["COMMENTS"]
            tags["VACCINATIONDESCRIPTIONRECENT" + vname] = v["VACCINATIONDESCRIPTION"]

    # Tests
    testasc = medical.get_tests(dbo, int(a["ID"]), not include_incomplete)
    testdesc = medical.get_tests(dbo, int(a["ID"]), not include_incomplete, medical.DESCENDING_REQUIRED)
    for idx in range(1, 101):
        tags["TESTNAME" + str(idx)] = ""
        tags["TESTRESULT" + str(idx)] = ""
        tags["TESTREQUIRED" + str(idx)] = ""
        tags["TESTGIVEN" + str(idx)] = ""
        tags["TESTCOMMENTS" + str(idx)] = ""
        tags["TESTDESCRIPTION" + str(idx)] = ""
        tags["TESTNAMELAST" + str(idx)] = ""
        tags["TESTREQUIREDLAST" + str(idx)] = ""
        tags["TESTGIVENLAST" + str(idx)] = ""
        tags["TESTCOMMENTSLAST" + str(idx)] = ""
        tags["TESTDESCRIPTIONLAST" + str(idx)] = ""
    idx = 1
    for t in testasc:
        tags["TESTNAME" + str(idx)] = t["TESTNAME"]
        tags["TESTRESULT" + str(idx)] = t["RESULTNAME"]
        tags["TESTREQUIRED" + str(idx)] = python2display(l, t["DATEREQUIRED"])
        tags["TESTGIVEN" + str(idx)] = python2display(l, t["DATEOFTEST"])
        tags["TESTCOMMENTS" + str(idx)] = t["COMMENTS"]
        tags["TESTDESCRIPTION" + str(idx)] = t["TESTDESCRIPTION"]
        idx += 1
    idx = 1
    uniquetypes = {}
    recentgiven = {}
    for t in testdesc:
        tags["TESTNAMELAST" + str(idx)] = t["TESTNAME"]
        tags["TESTRESULTLAST" + str(idx)] = t["RESULTNAME"]
        tags["TESTREQUIREDLAST" + str(idx)] = python2display(l, t["DATEREQUIRED"])
        tags["TESTGIVENLAST" + str(idx)] = python2display(l, t["DATEOFTEST"])
        tags["TESTCOMMENTSLAST" + str(idx)] = t["COMMENTS"]
        tags["TESTDESCRIPTIONLAST" + str(idx)] = t["TESTDESCRIPTION"]
        idx += 1
        # If this is the first of this type of test we've seen, make
        # some keys based on its name.
        if not uniquetypes.has_key(t["TESTNAME"]):
            tname = t["TESTNAME"].upper().replace(" ", "").replace("/", "")
            uniquetypes[t["TESTNAME"]] = t
            tags["TESTNAME" + tname] = t["TESTNAME"]
            tags["TESTRESULT" + tname] = t["RESULTNAME"]
            tags["TESTREQUIRED" + tname] = python2display(l, t["DATEREQUIRED"])
            tags["TESTGIVEN" + tname] = python2display(l, t["DATEOFTEST"])
            tags["TESTCOMMENTS" + tname] = t["COMMENTS"]
            tags["TESTDESCRIPTION" + tname] = t["TESTDESCRIPTION"]
        # If this is the first of this type of test we've seen that's been given
        # make some keys based on its name
        if not recentgiven.has_key(t["TESTNAME"]) and t["DATEOFTEST"] is not None:
            tname = t["TESTNAME"].upper().replace(" ", "").replace("/", "")
            recentgiven[t["TESTNAME"]] = t
            tags["TESTNAMERECENT" + tname] = t["TESTNAME"]
            tags["TESTRESULTRECENT" + tname] = t["RESULTNAME"]
            tags["TESTREQUIREDRECENT" + tname] = python2display(l, t["DATEREQUIRED"])
            tags["TESTGIVENRECENT" + tname] = python2display(l, t["DATEOFTEST"])
            tags["TESTCOMMENTSRECENT" + tname] = t["COMMENTS"]
            tags["TESTDESCRIPTIONRECENT" + tname] = t["TESTDESCRIPTION"]

    # Medical
    medasc = medical.get_regimens(dbo, int(a["ID"]), not include_incomplete)
    meddesc = medical.get_regimens(dbo, int(a["ID"]), not include_incomplete, medical.DESCENDING_REQUIRED)
    for idx in range(1, 101):
        tags["MEDICALNAME" + str(idx)] = ""
        tags["MEDICALCOMMENTS" + str(idx)] = ""
        tags["MEDICALFREQUENCY" + str(idx)] = ""
        tags["MEDICALNUMBEROFTREATMENTS" + str(idx)] = ""
        tags["MEDICALSTATUS" + str(idx)] = ""
        tags["MEDICALDOSAGE" + str(idx)] = ""
        tags["MEDICALSTARTDATE" + str(idx)] = ""
        tags["MEDICALTREATMENTSGIVEN" + str(idx)] = ""
        tags["MEDICALTREATMENTSREMAINING" + str(idx)] = ""
        tags["MEDICALNAMELAST" + str(idx)] = ""
        tags["MEDICALCOMMENTSLAST" + str(idx)] = ""
        tags["MEDICALFREQUENCYLAST" + str(idx)] = ""
        tags["MEDICALNUMBEROFTREATMENTSLAST" + str(idx)] = ""
        tags["MEDICALSTATUSLAST" + str(idx)] = ""
        tags["MEDICALDOSAGELAST" + str(idx)] = ""
        tags["MEDICALSTARTDATELAST" + str(idx)] = ""
        tags["MEDICALTREATMENTSGIVENLAST" + str(idx)] = ""
        tags["MEDICALTREATMENTSREMAININGLAST" + str(idx)] = ""
    idx = 1
    for m in medasc:
        tags["MEDICALNAME" + str(idx)] = m["TREATMENTNAME"]
        tags["MEDICALCOMMENTS" + str(idx)] = m["COMMENTS"]
        tags["MEDICALFREQUENCY" + str(idx)] = m["NAMEDFREQUENCY"]
        tags["MEDICALNUMBEROFTREATMENTS" + str(idx)] = m["NAMEDNUMBEROFTREATMENTS"]
        tags["MEDICALSTATUS" + str(idx)] = m["NAMEDSTATUS"]
        tags["MEDICALDOSAGE" + str(idx)] = m["DOSAGE"]
        tags["MEDICALSTARTDATE" + str(idx)] = python2display(l, m["STARTDATE"])
        tags["MEDICALTREATMENTSGIVEN" + str(idx)] = str(m["TREATMENTSGIVEN"])
        tags["MEDICALTREATMENTSREMAINING" + str(idx)] = str(m["TREATMENTSREMAINING"])
        idx += 1
    idx = 1
    uniquetypes = {}
    recentgiven = {}
    for m in meddesc:
        tags["MEDICALNAMELAST" + str(idx)] = m["TREATMENTNAME"]
        tags["MEDICALCOMMENTSLAST" + str(idx)] = m["COMMENTS"]
        tags["MEDICALFREQUENCYLAST" + str(idx)] = m["NAMEDFREQUENCY"]
        tags["MEDICALNUMBEROFTREATMENTSLAST" + str(idx)] = m["NAMEDNUMBEROFTREATMENTS"]
        tags["MEDICALSTATUSLAST" + str(idx)] = m["NAMEDSTATUS"]
        tags["MEDICALDOSAGELAST" + str(idx)] = m["DOSAGE"]
        tags["MEDICALSTARTDATELAST" + str(idx)] = python2display(l, m["STARTDATE"])
        tags["MEDICALTREATMENTSGIVENLAST" + str(idx)] = str(m["TREATMENTSGIVEN"])
        tags["MEDICALTREATMENTSREMAININGLAST" + str(idx)] = str(m["TREATMENTSREMAINING"])
        idx += 1
        # If this is the first of this type of med we've seen, make
        # some keys based on its name.
        if not uniquetypes.has_key(m["TREATMENTNAME"]):
            tname = m["TREATMENTNAME"].upper().replace(" ", "").replace("/", "")
            uniquetypes[m["TREATMENTNAME"]] = m
            tags["MEDICALNAME" + tname] = m["TREATMENTNAME"]
            tags["MEDICALCOMMENTS" + tname] = m["COMMENTS"]
            tags["MEDICALFREQUENCY" + tname] = m["NAMEDFREQUENCY"]
            tags["MEDICALNUMBEROFTREATMENTS" + tname] = m["NAMEDNUMBEROFTREATMENTS"]
            tags["MEDICALSTATUS" + tname] = m["NAMEDSTATUS"]
            tags["MEDICALDOSAGE" + tname] = m["DOSAGE"]
            tags["MEDICALSTARTDATE" + tname] = python2display(l, m["STARTDATE"])
            tags["MEDICALTREATMENTSGIVEN" + tname] = str(m["TREATMENTSGIVEN"])
            tags["MEDICALTREATMENTSREMAINING" + tname] = str(m["TREATMENTSREMAINING"])
        # If this is the first of this type of med we've seen that's complete
        if not recentgiven.has_key(m["TREATMENTNAME"]) and m["STATUS"] == 2:
            tname = m["TREATMENTNAME"].upper().replace(" ", "").replace("/", "")
            recentgiven[m["TREATMENTNAME"]] = m
            tags["MEDICALNAMERECENT" + tname] = m["TREATMENTNAME"]
            tags["MEDICALCOMMENTSRECENT" + tname] = m["COMMENTS"]
            tags["MEDICALFREQUENCYRECENT" + tname] = m["NAMEDFREQUENCY"]
            tags["MEDICALNUMBEROFTREATMENTSRECENT" + tname] = m["NAMEDNUMBEROFTREATMENTS"]
            tags["MEDICALSTATUSRECENT" + tname] = m["NAMEDSTATUS"]
            tags["MEDICALDOSAGERECENT" + tname] = m["DOSAGE"]
            tags["MEDICALSTARTDATERECENT" + tname] = python2display(l, m["STARTDATE"])
            tags["MEDICALTREATMENTSGIVENRECENT" + tname] = str(m["TREATMENTSGIVEN"])
            tags["MEDICALTREATMENTSREMAININGRECENT" + tname] = str(m["TREATMENTSREMAINING"])

    # Diet
    dietasc = animal.get_diets(dbo, int(a["ID"]))
    dietdesc = animal.get_diets(dbo, int(a["ID"]), animal.DESCENDING)
    for idx in range(1, 101):
        tags["DIETNAME" + str(idx)] = ""
        tags["DIETDESCRIPTION" + str(idx)] = ""
        tags["DIETDATESTARTED" + str(idx)] = ""
        tags["DIETCOMMENTS" + str(idx)] = ""
        tags["DIETNAMELAST" + str(idx)] = ""
        tags["DIETDESCRIPTIONLAST" + str(idx)] = ""
        tags["DIETDATESTARTEDLAST" + str(idx)] = ""
        tags["DIETCOMMENTSLAST" + str(idx)] = ""
    idx = 1
    for d in dietasc:
        tags["DIETNAME" + str(idx)] = d["DIETNAME"]
        tags["DIETDESCRIPTION" + str(idx)] = d["DIETDESCRIPTION"]
        tags["DIETDATESTARTED" + str(idx)] = python2display(l, d["DATESTARTED"])
        tags["DIETCOMMENTS" + str(idx)] = d["COMMENTS"]
        idx += 1
    idx = 1
    for d in dietdesc:
        tags["DIETNAMELAST" + str(idx)] = d["DIETNAME"]
        tags["DIETDESCRIPTIONLAST" + str(idx)] = d["DIETDESCRIPTION"]
        tags["DIETDATESTARTEDLAST" + str(idx)] = python2display(l, d["DATESTARTED"])
        tags["DIETCOMMENTSLAST" + str(idx)] = d["COMMENTS"]
        idx += 1

    # Donations
    donasc = financial.get_animal_donations(dbo, int(a["ID"]))
    dondesc = financial.get_animal_donations(dbo, int(a["ID"]), financial.DESCENDING)
    for idx in range(1, 101):
        tags["RECEIPTNUM" + str(idx)] = ""
        tags["DONATIONTYPE" + str(idx)] = ""
        tags["DONATIONDATE" + str(idx)] = ""
        tags["DONATIONDATEDUE" + str(idx)] = ""
        tags["DONATIONAMOUNT" + str(idx)] = ""
        tags["DONATIONCOMMENTS" + str(idx)] = ""
        tags["DONATIONGIFTAID" + str(idx)] = ""
        tags["RECEIPTNUMLAST" + str(idx)] = ""
        tags["DONATIONTYPELAST" + str(idx)] = ""
        tags["DONATIONDATELAST" + str(idx)] = ""
        tags["DONATIONDATEDUELAST" + str(idx)] = ""
        tags["DONATIONAMOUNTLAST" + str(idx)] = ""
        tags["DONATIONCOMMENTSLAST" + str(idx)] = ""
        tags["DONATIONGIFTAIDLAST" + str(idx)] = ""
    idx = 1
    for d in donasc:
        tags["RECEIPTNUM" + str(idx)] = utils.padleft(d["ID"], 8)
        tags["DONATIONTYPE" + str(idx)] = d["DONATIONNAME"]
        tags["DONATIONDATE" + str(idx)] = python2display(l, d["DATE"])
        tags["DONATIONDATEDUE" + str(idx)] = python2display(l, d["DATEDUE"])
        tags["DONATIONAMOUNT" + str(idx)] = format_currency_no_symbol(l, d["DONATION"])
        tags["DONATIONCOMMENTS" + str(idx)] = d["COMMENTS"]
        tags["DONATIONGIFTAID" + str(idx)] = d["ISGIFTAID"] == 1 and _("Yes", l) or _("No", l)
    idx = 1
    uniquetypes = {}
    recentrec = {}
    for d in dondesc:
        tags["RECEIPTNUMLAST" + str(idx)] = utils.padleft(d["ID"], 8)
        tags["DONATIONTYPELAST" + str(idx)] = d["DONATIONNAME"]
        tags["DONATIONDATELAST" + str(idx)] = python2display(l, d["DATE"])
        tags["DONATIONDATEDUELAST" + str(idx)] = python2display(l, d["DATEDUE"])
        tags["DONATIONAMOUNTLAST" + str(idx)] = format_currency_no_symbol(l, d["DONATION"])
        tags["DONATIONCOMMENTSLAST" + str(idx)] = d["COMMENTS"]
        tags["DONATIONGIFTAIDLAST" + str(idx)] = d["ISGIFTAID"] == 1 and _("Yes", l) or _("No", l)
        idx += 1
        # If this is the first of this type of donation we've seen, make
        # some keys based on its name.
        if not uniquetypes.has_key(d["DONATIONNAME"]):
            dname = d["DONATIONNAME"].upper().replace(" ", "").replace("/", "")
            uniquetypes[d["DONATIONNAME"]] = d
            tags["RECEIPTNUM" + dname] = utils.padleft(d["ID"], 8)
            tags["DONATIONTYPE" + dname] = d["DONATIONNAME"]
            tags["DONATIONDATE" + dname] = python2display(l, d["DATE"])
            tags["DONATIONDATEDUE" + dname] = python2display(l, d["DATEDUE"])
            tags["DONATIONAMOUNT" + dname] = format_currency_no_symbol(l, d["DONATION"])
            tags["DONATIONCOMMENTS" + dname] = d["COMMENTS"]
            tags["DONATIONGIFTAID" + dname] = d["ISGIFTAID"] == 1 and _("Yes", l) or _("No", l)
        # If this is the first of this type of donation we've seen that's received
        if not recentrec.has_key(d["DONATIONNAME"]) and d["DATE"] is not None:
            dname = d["DONATIONNAME"].upper().replace(" ", "").replace("/", "")
            recentrec[d["DONATIONNAME"]] = d
            tags["RECEIPTNUMRECENT" + dname] = utils.padleft(d["ID"], 8)
            tags["DONATIONTYPERECENT" + dname] = d["DONATIONNAME"]
            tags["DONATIONDATERECENT" + dname] = python2display(l, d["DATE"])
            tags["DONATIONDATEDUERECENT" + dname] = python2display(l, d["DATEDUE"])
            tags["DONATIONAMOUNTRECENT" + dname] = format_currency_no_symbol(l, d["DONATION"])
            tags["DONATIONCOMMENTSRECENT" + dname] = d["COMMENTS"]
            tags["DONATIONGIFTAIDRECENT" + dname] = d["ISGIFTAID"] == 1 and _("Yes", l) or _("No", l)

    # Logs
    logasc = log.get_logs(dbo, log.ANIMAL, int(a["ID"]), 0, log.ASCENDING)
    logdesc = log.get_logs(dbo, log.ANIMAL, int(a["ID"]), 0, log.DESCENDING)
    for idx in range(1, 101):
        tags["LOGNAME" + str(idx)] = ""
        tags["LOGDATE" + str(idx)] = ""
        tags["LOGCOMMENTS" + str(idx)] = ""
        tags["LOGNAMELAST" + str(idx)] = ""
        tags["LOGDATELAST" + str(idx)] = ""
        tags["LOGCOMMENTSLAST" + str(idx)] = ""
    idx = 1
    for o in logasc:
        tags["LOGNAME" + str(idx)] = o["LOGTYPENAME"]
        tags["LOGDATE" + str(idx)] = python2display(l, o["DATE"])
        tags["LOGCOMMENTS" + str(idx)] = o["COMMENTS"]
        idx += 1
    idx = 1
    uniquetypes = {}
    recentgiven = {}
    for o in logdesc:
        tags["LOGNAMELAST" + str(idx)] = o["LOGTYPENAME"]
        tags["LOGDATELAST" + str(idx)] = python2display(l, o["DATE"])
        tags["LOGCOMMENTSLAST" + str(idx)] = o["COMMENTS"]
        idx += 1
        uniquetypes = {}
        recentrec = {}
        # If this is the first of this type of log we've seen, make
        # some keys based on its name.
        if not uniquetypes.has_key(o["LOGTYPENAME"]):
            lname = o["LOGTYPENAME"].upper().replace(" ", "").replace("/", "")
            uniquetypes[o["LOGTYPENAME"]] = o
            tags["LOGNAME" + lname] = o["LOGTYPENAME"]
            tags["LOGDATE" + lname] = python2display(l, o["DATE"])
            tags["LOGCOMMENTS" + lname] = o["COMMENTS"]
            tags["LOGNAMERECENT" + lname] = o["LOGTYPENAME"]
            tags["LOGDATERECENT" + lname] = python2display(l, o["DATE"])
            tags["LOGCOMMENTSRECENT" + lname] = o["COMMENTS"]

    return tags
コード例 #54
0
ファイル: movement.py プロジェクト: MoriEdan/sheltermanager
def insert_adoption_from_form(dbo, username, data, creating = []):
    """
    Inserts a movement from the workflow adopt an animal screen.
    Returns the new movement id
    creating is an ongoing list of animals we're already going to
    create adoptions for. It prevents a never ending recursive loop
    of animal1 being bonded to animal2 that's bonded to animal1, etc.
    """
    l = dbo.locale
    # Validate that we have a movement date before doing anthing
    if None == utils.df_kd(data, "movementdate", l):
        raise utils.ASMValidationError(i18n._("Adoption movements must have a valid adoption date.", l))
    # Get the animal record for this adoption
    a = animal.get_animal(dbo, utils.df_ki(data, "animal"))
    if a is None:
        raise utils.ASMValidationError("Adoption POST has an invalid animal ID: %d" % utils.df_ki(data, "animal"))
    al.debug("Creating adoption for %d (%s - %s)" % (a["ID"], a["SHELTERCODE"], a["ANIMALNAME"]), "movement.insert_adoption_from_form", dbo)
    creating.append(a["ID"])
    # If the animal is bonded to other animals, we call this function
    # again with a copy of the data and the bonded animal substituted
    # so we can create their adoption records too.
    if a["BONDEDANIMALID"] is not None and a["BONDEDANIMALID"] != 0 and a["BONDEDANIMALID"] not in creating:
        al.debug("Found bond to animal %d, creating adoption..." % a["BONDEDANIMALID"], "movement.insert_adoption_from_form", dbo)
        newdata = dict(data)
        newdata["animal"] = str(a["BONDEDANIMALID"])
        insert_adoption_from_form(dbo, username, newdata, creating)
    if a["BONDEDANIMAL2ID"] is not None and a["BONDEDANIMAL2ID"] != 0 and a["BONDEDANIMAL2ID"] not in creating:
        al.debug("Found bond to animal %d, creating adoption..." % a["BONDEDANIMAL2ID"], "movement.insert_adoption_from_form", dbo)
        newdata = dict(data)
        newdata["animal"] = str(a["BONDEDANIMAL2ID"])
        insert_adoption_from_form(dbo, username, newdata, creating)
    cancel_reserves = configuration.cancel_reserves_on_adoption(dbo)
    # Prepare a dictionary of data for the movement table via insert_movement_from_form
    move_dict = {
        "person"                : utils.df_ks(data, "person"),
        "animal"                : utils.df_ks(data, "animal"),
        "adoptionno"            : utils.df_ks(data, "movementnumber"),
        "movementdate"          : utils.df_ks(data, "movementdate"),
        "type"                  : str(ADOPTION),
        "donation"              : utils.df_ks(data, "amount"),
        "insurance"             : utils.df_ks(data, "insurance"),
        "returncategory"        : configuration.default_return_reason(dbo),
        "trial"                 : utils.df_ks(data, "trial"),
        "trialenddate"          : utils.df_ks(data, "trialenddate")
    }
    # Is this animal currently on foster? If so, return the foster
    fm = get_animal_movements(dbo, utils.df_ki(data, "animal"))
    for m in fm:
        if m["MOVEMENTTYPE"] == FOSTER and m["RETURNDATE"] is None:
            return_movement(dbo, m["ID"], utils.df_ki(data, "animal"), utils.df_kd(data, "movementdate", l))
    # Is this animal current at a retailer? If so, return it from the
    # retailer and set the originalretailermovement and retailerid fields
    # on our new adoption movement so it can be linked back
    for m in fm:
        if m["MOVEMENTTYPE"] == RETAILER and m["RETURNDATE"] is None:
            return_movement(dbo, m["ID"], utils.df_ki(data, "animal"), utils.df_kd(data, "movementdate", l))
            move_dict["originalretailermovement"] = str(m["ID"])
            move_dict["retailer"] = str(m["OWNERID"])
    # Did we say we'd like to flag the owner as homechecked?
    if utils.df_kc(data, "homechecked") == 1:
        db.execute(dbo, "UPDATE owner SET IDCheck = 1, DateLastHomeChecked = %s WHERE ID = %d" % \
            ( db.dd(i18n.now(dbo.timezone)), utils.df_ki(data, "person")))
    # If the animal was flagged as not available for adoption, then it
    # shouldn't be since we've just adopted it.
    db.execute(dbo, "UPDATE animal SET IsNotAvailableForAdoption = 0 WHERE ID = %s" % utils.df_ks(data, "animal"))
    # Is the animal reserved to the person adopting? 
    movementid = 0
    for m in fm:
        if m["MOVEMENTTYPE"] == NO_MOVEMENT and m["RESERVATIONDATE"] is not None \
            and m["RESERVATIONCANCELLEDDATE"] is None and m["ANIMALID"] == utils.df_ki(data, "animal") \
            and m["OWNERID"] == utils.df_ki(data, "person"):
            # yes - update the existing movement
            movementid = m["ID"]
            move_dict["movementid"] = str(movementid)
            move_dict["adoptionno"] = utils.padleft(movementid, 6)
            move_dict["reservationdate"] = str(i18n.python2display(l, m["RESERVATIONDATE"]))
            move_dict["comments"] = utils.nulltostr(m["COMMENTS"])
            break
        elif cancel_reserves and m["MOVEMENTTYPE"] == NO_MOVEMENT and m["RESERVATIONDATE"] is not None \
            and m["RESERVATIONCANCELLEDDATE"] is None:
            # no, but it's reserved to someone else and we're cancelling
            # reserves on adoption
            db.execute(dbo, "UPDATE adoption SET ReservationCancelledDate = %s WHERE ID = %d" % \
                ( utils.df_d(data, "movementdate", l), m["ID"] ))
    if movementid != 0:
        update_movement_from_form(dbo, username, move_dict)
    else:
        movementid = insert_movement_from_form(dbo, username, move_dict)
    # Create the donation if there is one
    donation_amount = int(utils.df_m(data, "amount", l))
    if donation_amount > 0:
        due = ""
        received = utils.df_ks(data, "movementdate")
        if configuration.movement_donations_default_due(dbo):
            due = utils.df_ks(data, "movementdate")
            received = ""
        don_dict = {
            "person"                : utils.df_ks(data, "person"),
            "animal"                : utils.df_ks(data, "animal"),
            "movement"              : str(movementid),
            "type"                  : utils.df_ks(data, "donationtype"),
            "payment"               : utils.df_ks(data, "payment"),
            "frequency"             : "0",
            "amount"                : utils.df_ks(data, "amount"),
            "due"                   : due,
            "received"              : received,
            "giftaid"               : utils.df_ks(data, "giftaid")
        }
        financial.insert_donation_from_form(dbo, username, don_dict)
    # And a second donation if there is one
    donation_amount = int(utils.df_m(data, "amount2", l))
    if donation_amount > 0:
        due = ""
        received = utils.df_ks(data, "movementdate")
        if configuration.movement_donations_default_due(dbo):
            due = utils.df_ks(data, "movementdate")
            received = ""
        don_dict = {
            "person"                : utils.df_ks(data, "person"),
            "animal"                : utils.df_ks(data, "animal"),
            "movement"              : str(movementid),
            "type"                  : utils.df_ks(data, "donationtype2"),
            "payment"               : utils.df_ks(data, "payment2"),
            "frequency"             : "0",
            "amount"                : utils.df_ks(data, "amount2"),
            "due"                   : due,
            "received"              : received,
            "giftaid"               : utils.df_ks(data, "giftaid")
        }
        financial.insert_donation_from_form(dbo, username, don_dict)
    # Then any boarding cost record
    cost_amount = int(utils.df_m(data, "costamount", l))
    cost_type = utils.df_ks(data, "costtype")
    cost_create = utils.df_ki(data, "costcreate")
    if cost_amount > 0 and cost_type != "" and cost_create == 1:
        boc_dict = {
            "animalid"          : utils.df_ks(data, "animal"),
            "type"              : cost_type,
            "costdate"          : utils.df_ks(data, "movementdate"),
            "cost"              : utils.df_ks(data, "costamount")
        }
        animal.insert_cost_from_form(dbo, username, boc_dict)
    return movementid
コード例 #55
0
ファイル: movement.py プロジェクト: MoriEdan/sheltermanager
def validate_movement_form_data(dbo, data):
    """
    Verifies that form data is valid for a movement
    """
    l = dbo.locale
    movementid = utils.df_ki(data, "movementid")
    movement = None
    if movementid != 0: movement = db.query(dbo, "SELECT * FROM adoption WHERE ID = %d" % movementid)[0]
    adoptionno = utils.df_ks(data, "adoptionno")
    movementtype = utils.df_ki(data, "type")
    movementdate = utils.df_kd(data, "movementdate", l)
    returndate = utils.df_kd(data, "returndate", l)
    reservationdate = utils.df_kd(data, "reservationdate", l)
    reservationcancelled = utils.df_kd(data, "reservationcancelled", l)
    personid = utils.df_ki(data, "person")
    animalid = utils.df_ki(data, "animal")
    retailerid = utils.df_ki(data, "retailer")
    al.debug("validating saved movement %d for animal %d" % (movementid, animalid), "movement.validate_movement_form_data", dbo)
    # If we have a date but no type, get rid of it
    if movementdate is None and movementtype == 0:
        data["movementdate"] = ""
        al.debug("blank date and type", "movement.validate_movement_form_data", dbo)
    # If we've got a type, but no date, default today
    if movementtype > 0 and movementdate is None:
        movementdate = i18n.now()
        data["movementdate"] = i18n.python2display(l, movementdate)
        al.debug("type set and no date, defaulting today", "movement.validate_movement_form_data", dbo)
    # If we've got a reserve cancellation without a reserve, remove it
    if reservationdate is None and reservationcancelled is not None:
        data["reservationdate"] = ""
        al.debug("movement has no reserve or cancelled date", "movement.validate_movement_form_data", dbo)
    # Animals are always required
    if animalid == 0:
        al.debug("movement has no animal", "movement.validate_movement_form_data", dbo)
        raise utils.ASMValidationError(i18n._("Movements require an animal", l))
    # Owners are required unless type is escaped, stolen or released
    if personid == 0 and movementtype != ESCAPED and movementtype != STOLEN and movementtype != RELEASED:
        al.debug("movement has no person and is not ESCAPED|STOLEN|RELEASED", "movement.validate_movement_form_data", dbo)
        raise utils.ASMValidationError(i18n._("A person is required for this movement type.", l))
    # Is the movement number unique?
    if 0 != db.query_int(dbo, "SELECT COUNT(*) FROM adoption WHERE AdoptionNumber LIKE '%s' AND ID <> %d" % (adoptionno, movementid)):
        raise utils.ASMValidationError(i18n._("Movement numbers must be unique.", l))
    # If we're updating an existing record, we only need to continue validation
    # if one of the important fields has changed (movement date/type, return date, reservation, animal)
    if movement is not None:
        if movementtype == movement["MOVEMENTTYPE"] and movementdate == movement["MOVEMENTDATE"] and returndate == movement["RETURNDATE"] and reservationdate == movement["RESERVATIONDATE"] and animalid == movement["ANIMALID"]:
            al.debug("movement type, dates and animalid have not changed. Abandoning further validation", "movement.validate_movement_form_data", dbo)
            return
    # If the animal is held in case of reclaim, it can't be adopted
    if movementtype == ADOPTION:
        if 1 == db.query_int(dbo, "SELECT IsHold FROM animal WHERE ID = %d" % animalid):
            al.debug("movement is adoption and the animal is on hold", "movement.validate_movement_form_data", dbo)
            raise utils.ASMValidationError(i18n._("This animal is currently held and cannot be adopted.", l))
    # If it's a foster movement, make sure the owner is a fosterer
    if movementtype == FOSTER:
        if 0 == db.query_int(dbo, "SELECT IsFosterer FROM owner WHERE ID = %d" % personid):
            al.debug("movement is a foster and the person is not a fosterer.", "movement.validate_movement_form_data", dbo)
            raise utils.ASMValidationError(i18n._("This person is not flagged as a fosterer and cannot foster animals.", l))
    # If it's a retailer movement, make sure the owner is a retailer
    if movementtype == RETAILER:
        if 0 == db.query_int(dbo, "SELECT IsRetailer FROM owner WHERE ID = %d" % personid):
            al.debug("movement is a retailer and the person is not a retailer.", "movement.validate_movement_form_data", dbo)
            raise utils.ASMValidationError(i18n._("This person is not flagged as a retailer and cannot handle retailer movements.", l))
    # If a retailer is selected, make sure it's an adoption
    if retailerid != 0 and movementtype != ADOPTION:
        al.debug("movement has a retailerid set and this is not an adoption.", "movement.validate_movement_form_data", dbo)
        raise utils.ASMValidationError(i18n._("From retailer is only valid on adoption movements.", l))
    # If a retailer is selected, make sure there's been a retailer movement in this animal's history
    if retailerid != 0:
        if 0 == db.query_int(dbo, "SELECT COUNT(*) FROM adoption WHERE AnimalID = %d AND MovementType = %d" % ( animalid, RETAILER )):
            al.debug("movement has a retailerid set but has never been to a retailer.", "movement.validate_movement_form_data", dbo)
            raise utils.ASMValidationError(i18n._("This movement cannot be from a retailer when the animal has no prior retailer movements.", l))
    # You can't have a return without a movement
    if movementdate is None and returndate is not None:
        al.debug("movement is returned without a movement date.", "movement.validate_movement_form_data", dbo)
        raise utils.ASMValidationError(i18n._("You can't have a return without a movement.", l))
    # Return should be after or same day as movement
    if movementdate is not None and returndate != None and movementdate > returndate:
        al.debug("movement return date is before the movement date.", "movement.validate_movement_form_data", dbo)
        raise utils.ASMValidationError(i18n._("Return date cannot be before the movement date.", l))
    # Can't have multiple open movements
    if movementdate is not None:
        existingopen = db.query_int(dbo, "SELECT COUNT(*) FROM adoption WHERE MovementDate Is Not Null AND " \
            "ReturnDate Is Null AND AnimalID = %d AND ID <> %d" % (animalid, movementid))
        if existingopen > 0:
            al.debug("movement is open and animal already has another open movement.", "movement.validate_movement_form_data", dbo)
            raise utils.ASMValidationError(i18n._("An animal cannot have multiple open movements.", l))
    # If we have a movement and return, is there another movement with a 
    # movementdate between the movement and return date on this one?
    if movementdate is not None and returndate != None:
        clash = db.query_int(dbo, "SELECT COUNT(*) FROM adoption WHERE " \
        "AnimalID = %d AND ID <> %d AND ((ReturnDate > %s AND ReturnDate < %s) " \
        "OR (MovementDate < %s AND MovementDate > %s))" % ( animalid, movementid, 
        db.dd(movementdate), db.dd(returndate), db.dd(returndate), db.dd(movementdate) ))
        if clash > 0:
            al.debug("movement dates overlap an existing movement.", "movement.validate_movement_form_data", dbo)
            raise utils.ASMValidationError(i18n._("Movement dates clash with an existing movement.", l))
    # Does this movement date fall within the date range of an already
    # returned movement for the same animal?
    if movementdate is not None and returndate is None:
        clash = db.query_int(dbo, "SELECT COUNT(*) FROM adoption WHERE AnimalID = %d AND ID <> %d AND " \
        "MovementDate Is Not Null AND ReturnDate Is Not Null AND " \
        "%s > MovementDate AND %s < ReturnDate" % ( animalid, movementid, db.dd(movementdate), db.dd(movementdate)))
        if clash > 0:
            al.debug("movement dates overlap an existing movement.", "movement.validate_movement_form_data", dbo)
            raise utils.ASMValidationError(i18n._("Movement dates clash with an existing movement.", l))
    # If there's a cancelled reservation, make sure it's after the reserve date
    if reservationdate is not None and reservationcancelled != None and reservationcancelled < reservationdate:
        al.debug("reserve date is after cancelled date.", "movement.validate_movement_form_data", dbo)
        raise utils.ASMValidationError(i18n._("Reservation date cannot be after cancellation date.", l))
    # If this is a new reservation, make sure there's no open movement (fosters do not count)
    if movementid == 0 and movementtype == 0 and movementdate is None and reservationdate is not None:
        om = db.query_int(dbo, "SELECT COUNT(*) FROM adoption WHERE AnimalID = %d AND " \
            "MovementDate Is Not Null AND ReturnDate Is Null AND MovementType <> 2" % animalid)
        if om > 0:
            al.debug("movement is a reservation but animal has active movement.", "movement.validate_movement_form_data", dbo)
            raise utils.ASMValidationError(i18n._("Can't reserve an animal that has an active movement.", l))
    # Make sure the adoption number is unique
    an = db.query_int(dbo, "SELECT COUNT(*) FROM adoption WHERE ID <> %d AND " \
        "AdoptionNumber LIKE %s" % ( movementid, utils.df_t(data, "adoptionno" )))
    if an > 0:
        al.debug("movement number is not unique.", "movement.validate_movement_form_data", dbo)
        raise utils.ASMValidationError(i18n._("The movement number '{0}' is not unique.", l).format(utils.df_ks(data, "adoptionno")))
    # If this is an adoption and the owner had some criteria, expire them
    if movementtype == ADOPTION and personid > 0:
        al.debug("movement is an adoption, expiring person criteria.", "movement.validate_movement_form_data", dbo)
        sql = "UPDATE owner SET MatchActive = 0, MatchExpires = %s WHERE ID = %d" % ( db.dd(i18n.now(dbo.timezone)), int(personid) )
        db.execute(dbo, sql)
    # If the option to cancel reserves on adoption is set, cancel any outstanding reserves for the animal
    if movementtype == ADOPTION and configuration.cancel_reserves_on_adoption(dbo):
        al.debug("movement is an adoption, cancelling outstanding reserves.", "movement.validate_movement_form_data", dbo)
        sql = "UPDATE adoption SET ReservationCancelledDate = %s " \
            "WHERE ReservationCancelledDate Is Null AND MovementDate Is Null " \
            "AND AnimalID = %d AND ID <> %d" % ( db.dd(i18n.now(dbo.timezone)), animalid, int(movementid) )
        db.execute(dbo, sql)