コード例 #1
0
ファイル: onlineform.py プロジェクト: MoriEdan/sheltermanager
def get_onlineform_html(dbo, formid, completedocument=True):
    """ Get the selected online form as HTML """
    h = []
    l = dbo.locale
    form = db.query(dbo, "SELECT * FROM onlineform WHERE ID = %d" % formid)[0]
    if completedocument:
        header = get_onlineform_header(dbo)
        h.append(header.replace("$$TITLE$$", form["NAME"]))
        h.append('<h2 class="asm-onlineform-title">%s</h2>' % form["NAME"])
        h.append('<p class="asm-onlineform-description">%s</p>' %
                 form["DESCRIPTION"])
    h.append('<form action="%s/service" method="post">' % BASE_URL)
    h.append('<input type="hidden" name="method" value="online_form_post" />')
    h.append('<input type="hidden" name="account" value="%s" />' % dbo.alias)
    h.append('<input type="hidden" name="redirect" value="%s" />' %
             form["REDIRECTURLAFTERPOST"])
    h.append('<input type="hidden" name="flags" value="%s" />' %
             form["SETOWNERFLAGS"])
    h.append('<input type="hidden" name="formname" value="%s" />' %
             html.escape(form["NAME"]))
    h.append('<table width="100%" class="asm-onlineform-table">')
    for f in get_onlineformfields(dbo, formid):
        fname = f["FIELDNAME"] + "_" + str(f["ID"])
        h.append('<tr class="asm-onlineform-tr">')
        h.append('<td class="asm-onlineform-td">')
        h.append('<label for="f%d">%s</label>' % (f["ID"], f["LABEL"]))
        h.append('</td>')
        h.append('<td class="asm-onlineform-td">')
        if f["FIELDTYPE"] == FIELDTYPE_YESNO:
            h.append('<select name="%s" title="%s"><option>%s</option><option>%s</option></select>' % \
                ( html.escape(fname), utils.nulltostr(f["TOOLTIP"]), i18n._("No", l), i18n._("Yes", l)))
        elif f["FIELDTYPE"] == FIELDTYPE_TEXT:
            h.append('<input type="text" name="%s" title="%s" />' %
                     (html.escape(fname), utils.nulltostr(f["TOOLTIP"])))
        elif f["FIELDTYPE"] == FIELDTYPE_NOTES:
            h.append('<textarea name="%s" title="%s"></textarea>' %
                     (html.escape(fname), utils.nulltostr(f["TOOLTIP"])))
        elif f["FIELDTYPE"] == FIELDTYPE_LOOKUP:
            h.append('<select name="%s" title="%s">' %
                     (html.escape(fname), utils.nulltostr(f["TOOLTIP"])))
            for lv in utils.nulltostr(f["LOOKUPS"]).split("|"):
                h.append('<option>%s</option>' % lv)
            h.append('</select>')
        h.append('</td>')
        h.append('</tr>')
    h.append('</table>')
    h.append(
        '<p style="text-align: center"><input type="submit" value="Submit" /></p>'
    )
    h.append('</form>')
    if completedocument:
        footer = get_onlineform_footer(dbo)
        h.append(footer.replace("$$TITLE$$", form["NAME"]))
    return "\n".join(h)
コード例 #2
0
ファイル: users.py プロジェクト: tgage/asm3
def get_active_users(dbo):
    """
    Returns a list of active users on the system
    USERNAME, SINCE, MESSAGES
    """
    cachekey = "%s_activity" % dbo.database
    return utils.nulltostr(cachemem.get(cachekey))
コード例 #3
0
ファイル: users.py プロジェクト: magul/asm3
def update_user_activity(dbo, user, timenow = True):
    """
    If timenow is True, updates this user's last activity time to now.
    If timenow is False, removes this user from the active list.
    """
    if dbo is None or user is None: return
    cachekey = "%s_activity" % dbo.database
    ac = utils.nulltostr(cachemem.get(cachekey))
    # Prune old activity and remove the current user
    nc = []
    for a in ac.split(","):
        # If there are any errors reading or parsing
        # the entry, skip it
        try:
            if a != "":
                u, d = a.split("=")
                # if the last seen value was more than an hour ago, 
                # don't bother adding that user
                p = i18n.parse_date("%Y-%m-%d %H:%M:%S", d)
                if i18n.subtract_hours(i18n.now(dbo.timezone), 1) > p:
                    continue
                # Don't add the current user
                if u == user:
                    continue
                nc.append(a)
        except:
            continue
    # Add this user with the new time 
    if timenow: 
        nc.append("%s=%s" % (user, i18n.format_date("%Y-%m-%d %H:%M:%S", i18n.now(dbo.timezone))))
    cachemem.put(cachekey, ",".join(nc), 3600 * 8)
コード例 #4
0
ファイル: users.py プロジェクト: magul/asm3
def get_active_users(dbo):
    """
    Returns a list of active users on the system
    USERNAME, SINCE, MESSAGES
    """
    cachekey = "%s_activity" % dbo.database
    return utils.nulltostr(cachemem.get(cachekey))
コード例 #5
0
ファイル: users.py プロジェクト: tgage/asm3
def update_user_activity(dbo, user, timenow=True):
    """
    If timenow is True, updates this user's last activity time to now.
    If timenow is False, removes this user from the active list.
    """
    if dbo is None or user is None: return
    cachekey = "%s_activity" % dbo.database
    ac = utils.nulltostr(cachemem.get(cachekey))
    # Prune old activity and remove the current user
    nc = []
    for a in ac.split(","):
        # If there are any errors reading or parsing
        # the entry, skip it
        try:
            if a != "":
                u, d = a.split("=")
                # if the last seen value was more than an hour ago,
                # don't bother adding that user
                p = i18n.parse_date("%Y-%m-%d %H:%M:%S", d)
                if i18n.subtract_hours(i18n.now(dbo.timezone), 1) > p:
                    continue
                # Don't add the current user
                if u == user:
                    continue
                nc.append(a)
        except:
            continue
    # Add this user with the new time
    if timenow:
        nc.append(
            "%s=%s" %
            (user, i18n.format_date("%Y-%m-%d %H:%M:%S", i18n.now(
                dbo.timezone))))
    cachemem.put(cachekey, ",".join(nc), 3600 * 8)
コード例 #6
0
ファイル: onlineform.py プロジェクト: MoriEdan/sheltermanager
def get_onlineform_html(dbo, formid, completedocument = True):
    """ Get the selected online form as HTML """
    h = []
    l = dbo.locale
    form = db.query(dbo, "SELECT * FROM onlineform WHERE ID = %d" % formid)[0]
    if completedocument:
        header = get_onlineform_header(dbo)
        h.append(header.replace("$$TITLE$$", form["NAME"]))
        h.append('<h2 class="asm-onlineform-title">%s</h2>' % form["NAME"])
        h.append('<p class="asm-onlineform-description">%s</p>' % form["DESCRIPTION"])
    h.append('<form action="%s/service" method="post">' % BASE_URL)
    h.append('<input type="hidden" name="method" value="online_form_post" />')
    h.append('<input type="hidden" name="account" value="%s" />' % dbo.alias)
    h.append('<input type="hidden" name="redirect" value="%s" />' % form["REDIRECTURLAFTERPOST"])
    h.append('<input type="hidden" name="flags" value="%s" />' % form["SETOWNERFLAGS"])
    h.append('<input type="hidden" name="formname" value="%s" />' % html.escape(form["NAME"]))
    h.append('<table width="100%" class="asm-onlineform-table">')
    for f in get_onlineformfields(dbo, formid):
        fname = f["FIELDNAME"] + "_" + str(f["ID"])
        h.append('<tr class="asm-onlineform-tr">')
        h.append('<td class="asm-onlineform-td">')
        h.append('<label for="f%d">%s</label>' % ( f["ID"], f["LABEL"] ))
        h.append('</td>')
        h.append('<td class="asm-onlineform-td">')
        if f["FIELDTYPE"] == FIELDTYPE_YESNO:
            h.append('<select name="%s" title="%s"><option>%s</option><option>%s</option></select>' % \
                ( html.escape(fname), utils.nulltostr(f["TOOLTIP"]), i18n._("No", l), i18n._("Yes", l)))
        elif f["FIELDTYPE"] == FIELDTYPE_TEXT:
            h.append('<input type="text" name="%s" title="%s" />' % ( html.escape(fname), utils.nulltostr(f["TOOLTIP"])))
        elif f["FIELDTYPE"] == FIELDTYPE_NOTES:
            h.append('<textarea name="%s" title="%s"></textarea>' % ( html.escape(fname), utils.nulltostr(f["TOOLTIP"])))
        elif f["FIELDTYPE"] == FIELDTYPE_LOOKUP:
            h.append('<select name="%s" title="%s">' % ( html.escape(fname), utils.nulltostr(f["TOOLTIP"])))
            for lv in utils.nulltostr(f["LOOKUPS"]).split("|"):
                h.append('<option>%s</option>' % lv)
            h.append('</select>')
        h.append('</td>')
        h.append('</tr>')
    h.append('</table>')
    h.append('<p style="text-align: center"><input type="submit" value="Submit" /></p>')
    h.append('</form>')
    if completedocument:
        footer = get_onlineform_footer(dbo)
        h.append(footer.replace("$$TITLE$$", form["NAME"]))
    return "\n".join(h)
コード例 #7
0
def animals_to_page(dbo,
                    animals,
                    style="",
                    speciesid=0,
                    animaltypeid=0,
                    locationid=0):
    """ Returns a page of animals.
    animals: A resultset containing animal records
    style: The HTML publishing template to use
    speciesid: 0 for all species, or a specific one
    animaltypeid: 0 for all animal types or a specific one
    locationid: 0 for all internal locations or a specific one
    """
    # Get the specified template
    head, body, foot = template.get_html_template(dbo, style)
    if head == "":
        head, body, foot = get_animal_view_template(dbo)
    # Substitute the header and footer tags
    org_tags = wordprocessor.org_tags(dbo, "system")
    head = wordprocessor.substitute_tags(head, org_tags, True, "$$", "$$")
    foot = wordprocessor.substitute_tags(foot, org_tags, True, "$$", "$$")
    # Run through each animal and generate body sections
    bodies = []
    for a in animals:
        if speciesid > 0 and a.SPECIESID != speciesid: continue
        if animaltypeid > 0 and a.ANIMALTYPEID != animaltypeid: continue
        if locationid > 0 and a.SHELTERLOCATION != locationid: continue
        # Translate website media name to the service call for images
        if smcom.active():
            a.WEBSITEMEDIANAME = "%s?account=%s&method=animal_image&animalid=%d" % (
                SERVICE_URL, dbo.database, a.ID)
        else:
            a.WEBSITEMEDIANAME = "%s?method=animal_image&animalid=%d" % (
                SERVICE_URL, a.ID)
        # Generate tags for this row
        tags = wordprocessor.animal_tags_publisher(dbo, a)
        tags = wordprocessor.append_tags(tags, org_tags)
        # Add extra tags for websitemedianame2-4 if they exist
        if a.WEBSITEIMAGECOUNT > 1:
            tags["WEBMEDIAFILENAME2"] = "%s&seq=2" % a.WEBSITEMEDIANAME
        if a.WEBSITEIMAGECOUNT > 2:
            tags["WEBMEDIAFILENAME3"] = "%s&seq=3" % a.WEBSITEMEDIANAME
        if a.WEBSITEIMAGECOUNT > 3:
            tags["WEBMEDIAFILENAME4"] = "%s&seq=4" % a.WEBSITEMEDIANAME
        # Set the description
        if configuration.publisher_use_comments(dbo):
            a.WEBSITEMEDIANOTES = a.ANIMALCOMMENTS
        # Add extra publishing text, preserving the line endings
        notes = utils.nulltostr(a.WEBSITEMEDIANOTES)
        notes += configuration.third_party_publisher_sig(dbo).replace(
            "\n", "<br/>")
        tags["WEBMEDIANOTES"] = notes
        bodies.append(
            wordprocessor.substitute_tags(body, tags, True, "$$", "$$"))
    return "%s\n%s\n%s" % (head, "\n".join(bodies), foot)
コード例 #8
0
 def substituteBodyTags(self, searchin, a):
     """
     Substitutes any tags in the body for animal data
     """
     tags = wordprocessor.animal_tags_publisher(self.dbo, a)
     tags["TotalAnimals"] = str(self.totalAnimals)
     tags["IMAGE"] = str(a["WEBSITEMEDIANAME"])
     # Note: WEBSITEMEDIANOTES becomes ANIMALCOMMENTS in get_animal_data when publisher_use_comments is on
     notes = utils.nulltostr(a["WEBSITEMEDIANOTES"])
     # Add any extra text
     notes += configuration.third_party_publisher_sig(self.dbo)
     # Preserve line endings in the bio
     notes = notes.replace("\n", "**le**")
     tags["WEBMEDIANOTES"] = notes
     output = wordprocessor.substitute_tags(searchin, tags, True, "$$",
                                            "$$")
     output = output.replace("**le**", "<br />")
     return output
コード例 #9
0
def get_animal_view(dbo, animalid):
    """ Constructs the animal view page to the template. """
    a = dbo.first_row(
        get_animal_data(dbo,
                        animalid=animalid,
                        include_additional_fields=True,
                        strip_personal_data=True))
    # If the animal is not adoptable, bail out
    if a is None:
        raise utils.ASMPermissionError("animal is not adoptable (None)")
    if not is_animal_adoptable(dbo, a):
        raise utils.ASMPermissionError("animal is not adoptable (False)")
    # If the option is on, use animal comments as the notes
    if configuration.publisher_use_comments(dbo):
        a.WEBSITEMEDIANOTES = a.ANIMALCOMMENTS
    head, body, foot = get_animal_view_template(dbo)
    if head == "":
        head = "<!DOCTYPE html>\n<html>\n<head>\n<title>$$SHELTERCODE$$ - $$ANIMALNAME$$</title></head>\n<body>"
        body = "<h2>$$SHELTERCODE$$ - $$ANIMALNAME$$</h2><p><img src='$$WEBMEDIAFILENAME$$'/></p><p>$$WEBMEDIANOTES$$</p>"
        foot = "</body>\n</html>"
    if smcom.active():
        a.WEBSITEMEDIANAME = "%s?account=%s&method=animal_image&animalid=%d" % (
            SERVICE_URL, dbo.database, animalid)
    else:
        a.WEBSITEMEDIANAME = "%s?method=animal_image&animalid=%d" % (
            SERVICE_URL, animalid)
    s = head + body + foot
    tags = wordprocessor.animal_tags_publisher(dbo, a)
    tags = wordprocessor.append_tags(tags,
                                     wordprocessor.org_tags(dbo, "system"))
    # Add extra tags for websitemedianame2-10 if they exist
    for x in range(2, 11):
        if a.WEBSITEIMAGECOUNT > x - 1:
            tags["WEBMEDIAFILENAME%d" %
                 x] = "%s&seq=%d" % (a.WEBSITEMEDIANAME, x)
    # Add extra publishing text, preserving the line endings
    notes = utils.nulltostr(a.WEBSITEMEDIANOTES)
    notes += configuration.third_party_publisher_sig(dbo)
    notes = notes.replace("\n", "**le**")
    tags["WEBMEDIANOTES"] = notes
    tags["WEBSITEMEDIANOTES"] = notes
    s = wordprocessor.substitute_tags(s, tags, True, "$$", "$$")
    s = s.replace("**le**", "<br />")
    return s
コード例 #10
0
def get_onlineform_html(dbo, formid, completedocument = True):
    """ Get the selected online form as HTML """
    h = []
    l = dbo.locale
    form = db.query(dbo, "SELECT * FROM onlineform WHERE ID = %d" % formid)[0]
    formfields = get_onlineformfields(dbo, formid)
    # If a date field has been used, we need to pull jquery ui into the header
    # and have it applied to all date fields.
    needjqui = False
    for f in formfields:
        if f["FIELDTYPE"] == FIELDTYPE_DATE:
            needjqui = True
    if completedocument:
        header = get_onlineform_header(dbo)
        if needjqui:
            df = i18n.get_display_date_format(l)
            df = df.replace("%Y", "yy").replace("%m", "mm").replace("%d", "dd")
            header = header.replace("</head>", """
                %s
                %s
                %s
                <script>
                $(document).ready(function() {
                    $(".asm-onlineform-date").datepicker({ dateFormat: '%s' });
                });
                </script>
                </head>""" % (JQUERY_UI_CSS.replace("%(theme)s", "smoothness"), JQUERY_JS, JQUERY_UI_JS, df))
        h.append(header.replace("$$TITLE$$", form["NAME"]))
        h.append('<h2 class="asm-onlineform-title">%s</h2>' % form["NAME"])
        if form["DESCRIPTION"] is not None and form["DESCRIPTION"] != "":
            h.append('<p class="asm-onlineform-description">%s</p>' % form["DESCRIPTION"])
        h.append(utils.nulltostr(form["HEADER"]))
    h.append('<form action="%s/service" method="post" accept-charset="utf-8">' % BASE_URL)
    h.append('<input type="hidden" name="method" value="online_form_post" />')
    h.append('<input type="hidden" name="account" value="%s" />' % dbo.alias)
    h.append('<input type="hidden" name="redirect" value="%s" />' % form["REDIRECTURLAFTERPOST"])
    h.append('<input type="hidden" name="flags" value="%s" />' % form["SETOWNERFLAGS"])
    h.append('<input type="hidden" name="formname" value="%s" />' % html.escape(form["NAME"]))
    h.append('<table width="100%" class="asm-onlineform-table">')
    for f in formfields:
        fname = f["FIELDNAME"] + "_" + str(f["ID"])
        h.append('<tr class="asm-onlineform-tr">')
        if f["FIELDTYPE"] == FIELDTYPE_RAWMARKUP:
            h.append('<td class="asm-onlineform-td" colspan="2">')
        else:
            # Add label and cell wrapper if it's not raw markup
            h.append('<td class="asm-onlineform-td">')
            h.append('<label for="f%d">%s</label>' % ( f["ID"], f["LABEL"] ))
            h.append('</td>')
            h.append('<td class="asm-onlineform-td">')
        required = ""
        if f["MANDATORY"] == 1: 
            required = "required=\"required\""
            h.append('<span class="asm-onlineform-required" style="color: #ff0000;">*</span>')
        else:
            h.append('<span class="asm-onlineform-notrequired" style="visibility: hidden">*</span>')
        if f["FIELDTYPE"] == FIELDTYPE_YESNO:
            h.append('<select class="asm-onlineform-yesno" name="%s" title="%s"><option>%s</option><option>%s</option></select>' % \
                ( html.escape(fname), utils.nulltostr(f["TOOLTIP"]), i18n._("No", l), i18n._("Yes", l)))
        elif f["FIELDTYPE"] == FIELDTYPE_TEXT:
            h.append('<input class="asm-onlineform-text" type="text" name="%s" title="%s" %s />' % ( html.escape(fname), utils.nulltostr(f["TOOLTIP"]), required))
        elif f["FIELDTYPE"] == FIELDTYPE_DATE:
            h.append('<input class="asm-onlineform-date" type="text" name="%s" title="%s" %s />' % ( html.escape(fname), utils.nulltostr(f["TOOLTIP"]), required))
        elif f["FIELDTYPE"] == FIELDTYPE_NOTES:
            h.append('<textarea class="asm-onlineform-notes" name="%s" title="%s" %s></textarea>' % ( html.escape(fname), utils.nulltostr(f["TOOLTIP"]), required))
        elif f["FIELDTYPE"] == FIELDTYPE_LOOKUP:
            h.append('<select class="asm-onlineform-lookup" name="%s" title="%s" %s>' % ( html.escape(fname), utils.nulltostr(f["TOOLTIP"]), required))
            for lv in utils.nulltostr(f["LOOKUPS"]).split("|"):
                h.append('<option>%s</option>' % lv)
            h.append('</select>')
        elif f["FIELDTYPE"] == FIELDTYPE_SHELTERANIMAL:
            h.append('<select class="asm-onlineform-shelteranimal" name="%s" title="%s" %s>' % ( html.escape(fname), utils.nulltostr(f["TOOLTIP"]), required))
            h.append('<option></option>')
            for a in animal.get_animals_on_shelter_namecode(dbo):
                h.append('<option value="%s">%s (%s)</option>' % (a["ANIMALNAME"], a["ANIMALNAME"], a["SHELTERCODE"]))
            h.append('</select>')
        elif f["FIELDTYPE"] == FIELDTYPE_ADOPTABLEANIMAL:
            h.append('<select class="asm-onlineform-adoptableanimal" name="%s" title="%s" %s>' % ( html.escape(fname), utils.nulltostr(f["TOOLTIP"]), required))
            h.append('<option></option>')
            pc = publish.PublishCriteria(configuration.publisher_presets(dbo))
            rs = publish.get_animal_data(dbo, pc, True)
            for a in rs:
                h.append('<option value="%s">%s (%s)</option>' % (a["ANIMALNAME"], a["ANIMALNAME"], a["SHELTERCODE"]))
            h.append('</select>')
        elif f["FIELDTYPE"] == FIELDTYPE_COLOUR:
            h.append('<select class="asm-onlineform-colour" name="%s" title="%s" %s>' % ( html.escape(fname), utils.nulltostr(f["TOOLTIP"]), required))
            for l in lookups.get_basecolours(dbo):
                h.append('<option>%s</option>' % l["BASECOLOUR"])
            h.append('</select>')
        elif f["FIELDTYPE"] == FIELDTYPE_BREED:
            h.append('<select class="asm-onlineform-breed" name="%s" title="%s" %s>' % ( html.escape(fname), utils.nulltostr(f["TOOLTIP"]), required))
            for l in lookups.get_breeds(dbo):
                h.append('<option>%s</option>' % l["BREEDNAME"])
            h.append('</select>')
        elif f["FIELDTYPE"] == FIELDTYPE_SPECIES:
            h.append('<select class="asm-onlineform-species" name="%s" title="%s" %s>' % ( html.escape(fname), utils.nulltostr(f["TOOLTIP"]), required))
            for l in lookups.get_species(dbo):
                h.append('<option>%s</option>' % l["SPECIESNAME"])
            h.append('</select>')
        elif f["FIELDTYPE"] == FIELDTYPE_RAWMARKUP:
            h.append(utils.nulltostr(f["TOOLTIP"]))
        h.append('</td>')
        h.append('</tr>')
    h.append('</table>')
    h.append('<p style="text-align: center"><input type="submit" value="Submit" /></p>')
    h.append('</form>')
    if completedocument:
        h.append(utils.nulltostr(form["FOOTER"]))
        footer = get_onlineform_footer(dbo)
        h.append(footer.replace("$$TITLE$$", form["NAME"]))
    return "\n".join(h)
コード例 #11
0
    def run(self):
        def xe(s):
            if s is None: return ""
            return s.replace("&",
                             "&amp;").replace("<",
                                              "&lt;").replace(">", "&gt;")

        self.log(self.publisherName + " starting...")

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

        userid = configuration.vetenvoy_user_id(self.dbo)
        userpassword = configuration.vetenvoy_user_password(self.dbo)

        if userid == "" or userpassword == "":
            self.setLastError("VetEnvoy userid and userpassword must be set")
            return

        animals = get_microchip_data(self.dbo, self.microchipPatterns,
                                     self.publisherKey)
        if len(animals) == 0:
            self.setLastError("No animals found to publish.")
            return

        anCount = 0
        processed_animals = []
        failed_animals = []
        for an in animals:
            try:
                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()
                    return

                # Validate certain items aren't blank so we aren't registering bogus data
                if utils.nulltostr(an["CURRENTOWNERADDRESS"].strip()) == "":
                    self.logError(
                        "Address for the new owner is blank, cannot process")
                    continue

                if utils.nulltostr(an["CURRENTOWNERPOSTCODE"].strip()) == "":
                    self.logError(
                        "Postal code for the new owner is blank, cannot process"
                    )
                    continue

                if an["IDENTICHIPDATE"] is None:
                    self.logError(
                        "Microchip date cannot be blank, cannot process")
                    continue

                # Make sure the length is actually suitable
                if not len(an["IDENTICHIPNUMBER"]) in (9, 10, 15):
                    self.logError(
                        "Microchip length is not 9, 10 or 15, cannot process")
                    continue

                # Construct the XML document
                x = '<?xml version="1.0" encoding="UTF-8"?>\n' \
                    '<MicrochipRegistration ' \
                    'version="1.32" ' \
                    'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' \
                    'xsi:schemaLocation="https://www.vetenvoytest.com/partner/files/Chip%201.32.xsd">' \
                    '<Identification>' \
                    ' <PracticeID>' + userid + '</PracticeID>' \
                    ' <PinNo></PinNo>' \
                    ' <Source></Source>' \
                    '</Identification>' \
                    '<OwnerDetails>' \
                    ' <Salutation>' + xe(an["CURRENTOWNERTITLE"]) + '</Salutation>' \
                    ' <Initials>' + xe(an["CURRENTOWNERINITIALS"]) + '</Initials>' \
                    ' <Forenames>' + xe(an["CURRENTOWNERFORENAMES"]) + '</Forenames>' \
                    ' <Surname>' + xe(an["CURRENTOWNERSURNAME"]) + '</Surname>' \
                    ' <Address>' \
                    '  <Line1>'+ xe(an["CURRENTOWNERADDRESS"]) + '</Line1>' \
                    '  <LineOther>'+ xe(an["CURRENTOWNERTOWN"]) + '</LineOther>' \
                    '  <PostalCode>' + xe(an["CURRENTOWNERPOSTCODE"]) + '</PostalCode>' \
                    '  <County_State>'+ xe(an["CURRENTOWNERCOUNTY"]) + '</County_State>' \
                    '  <Country>USA</Country>' \
                    ' </Address>' \
                    ' <DaytimePhone><Number>' + xe(an["CURRENTOWNERWORKTELEPHONE"]) + '</Number><Note/></DaytimePhone>' \
                    ' <EveningPhone><Number>' + xe(an["CURRENTOWNERHOMETELEPHONE"]) + '</Number><Note/></EveningPhone>' \
                    ' <MobilePhone><Number>' + xe(an["CURRENTOWNERMOBILETELEPHONE"]) + '</Number><Note/></MobilePhone>' \
                    ' <EmergencyPhone><Number/><Note/></EmergencyPhone>' \
                    ' <OtherPhone><Number/><Note/></OtherPhone>' \
                    ' <EmailAddress>' + xe(an["CURRENTOWNEREMAILADDRESS"]) + '</EmailAddress>' \
                    ' <Fax />' \
                    '</OwnerDetails>' \
                    '<PetDetails>' \
                    '  <Name>' + xe(an["ANIMALNAME"]) + '</Name>' \
                    '  <Species>' + self.get_vetenvoy_species(an["SPECIESID"]) + '</Species>' \
                    '  <Breed><FreeText>' + xe(an["BREEDNAME"]) + '</FreeText><Code/></Breed>' \
                    '  <DateOfBirth>' + i18n.format_date("%m/%d/%Y", an["DATEOFBIRTH"]) + '</DateOfBirth>' \
                    '  <Gender>' + an["SEXNAME"][0:1] + '</Gender>' \
                    '  <Colour>' + xe(an["BASECOLOURNAME"]) + '</Colour>' \
                    '  <Markings>' + xe(an["MARKINGS"]) + '</Markings>' \
                    '  <Neutered>' + (an["NEUTERED"] == 1 and "true" or "false") + '</Neutered>' \
                    '  <NotableConditions>' + xe(an["HEALTHPROBLEMS"]) + '</NotableConditions>' \
                    '</PetDetails>' \
                    '<MicrochipDetails>' \
                    '  <MicrochipNumber>' + xe(an["IDENTICHIPNUMBER"]) + '</MicrochipNumber>' \
                    '  <ImplantDate>' + i18n.format_date("%m/%d/%Y", an["IDENTICHIPDATE"]) + '</ImplantDate>' \
                    '  <ImplanterName>' + xe(an["CREATEDBY"]) + '</ImplanterName>' \
                    '</MicrochipDetails>' \
                    '<ThirdPartyDisclosure>true</ThirdPartyDisclosure>' \
                    '<ReceiveMail>true</ReceiveMail>' \
                    '<ReceiveEmail>true</ReceiveEmail>' \
                    '<Authorisation>true</Authorisation>' \
                    '</MicrochipRegistration>'

                # Build our auth headers
                authheaders = {
                    "UserId": userid,
                    "UserPassword": userpassword,
                    "VendorPassword": VETENVOY_US_VENDOR_PASSWORD,
                    "RecipientId": self.recipientId
                }

                # Start a new conversation with VetEnvoy's microchip handler
                url = VETENVOY_US_BASE_URL + "Chip/NewConversationId"
                self.log(
                    "Contacting vetenvoy to start a new conversation: %s" %
                    url)
                try:
                    r = utils.get_url(url, authheaders)
                    self.log("Got response: %s" % r["response"])
                    conversationid = re.findall('c id="(.+?)"', r["response"])
                    if len(conversationid) == 0:
                        self.log(
                            "Could not parse conversation id, abandoning run")
                        break
                    conversationid = conversationid[0]
                    self.log("Got conversationid: %s" % conversationid)

                    # Now post the XML document
                    self.log("Posting microchip registration document: %s" % x)
                    r = utils.post_xml(
                        VETENVOY_US_BASE_URL + "Chip/" + conversationid, x,
                        authheaders)
                    self.log("Response %d, HTTP headers: %s, body: %s" %
                             (r["status"], r["headers"], r["response"]))
                    if r["status"] != 200: raise Exception(r["response"])

                    # Look in the headers for successful results
                    wassuccess = False
                    SUCCESS = ("54000", "54100", "54108")
                    for code in SUCCESS:
                        if str(r["headers"]).find(code) != -1:
                            self.log(
                                "successful %s response header found, marking processed"
                                % code)
                            processed_animals.append(an)
                            # Mark success in the log
                            self.logSuccess(
                                "Processed: %s: %s (%d of %d)" %
                                (an["SHELTERCODE"], an["ANIMALNAME"], anCount,
                                 len(animals)))
                            wassuccess = True
                            break

                    # If we saw an account not found message, there's no point sending
                    # anything else as they will all trigger the same error
                    if str(r["headers"]).find("54101") != -1 and str(
                            r["headers"]).find("Account Not Found") != -1:
                        self.logError(
                            "received HomeAgain 54101 'account not found' response header - abandoning run and disabling publisher"
                        )
                        configuration.publishers_enabled_disable(
                            self.dbo, "veha")
                        break
                    if str(r["headers"]).find("54101") != -1 and str(
                            r["headers"]).find("sender not recognized") != -1:
                        self.logError(
                            "received AKC Reunite 54101 'sender not recognized' response header - abandoning run and disabling publisher"
                        )
                        configuration.publishers_enabled_disable(
                            self.dbo, "vear")
                        break

                    if not wassuccess:
                        self.logError(
                            "no successful response header %s received" %
                            str(SUCCESS))
                        an["FAILMESSAGE"] = "%s: %s" % (
                            self.getHeader(r["headers"], "ResultCode"),
                            self.getHeader(r["headers"], "ResultDetails"))
                        failed_animals.append(an)

                except Exception as err:
                    em = str(err)
                    self.logError("Failed registering microchip: %s" % em,
                                  sys.exc_info())
                    continue

            except Exception as err:
                self.logError(
                    "Failed processing animal: %s, %s" %
                    (str(an["SHELTERCODE"]), err), sys.exc_info())

        # Only mark processed if we aren't using VetEnvoy's test URL
        if len(processed_animals) > 0 and VETENVOY_US_BASE_URL.find(
                "test") == -1:
            self.log("successfully processed %d animals, marking sent" %
                     len(processed_animals))
            self.markAnimalsPublished(processed_animals)
        if len(failed_animals) > 0 and VETENVOY_US_BASE_URL.find("test") == -1:
            self.log("failed processing %d animals, marking failed" %
                     len(failed_animals))
            self.markAnimalsPublishFailed(failed_animals)

        if VETENVOY_US_BASE_URL.find("test") != -1:
            self.log("VetEnvoy test mode, not marking animals published")

        self.saveLog()
        self.setPublisherComplete()
コード例 #12
0
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
コード例 #13
0
ファイル: foundanimals.py プロジェクト: NoelBradford/asm3
    def run(self):

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

        org = configuration.organisation(self.dbo)
        folder = configuration.foundanimals_folder(self.dbo)
        if folder == "":
            self.setLastError("No FoundAnimals folder has been set.")
            self.cleanup()
            return

        email = configuration.foundanimals_email(self.dbo)
        if email == "":
            self.setLastError("No FoundAnimals group email has been set.")
            self.cleanup()
            return

        animals = get_microchip_data(self.dbo, ["9", "0", "1"],
                                     "foundanimals",
                                     allowintake=True,
                                     organisation_email=email)
        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 FoundAnimals publisher."
                )
                configuration.publishers_enabled_disable(self.dbo, "fa")
            self.cleanup()
            return

        # foundanimals.org want data files called mmddyyyy_HHMMSS.csv in the shelter's own folder
        dateportion = i18n.format_date("%m%d%Y_%H%M%S",
                                       i18n.now(self.dbo.timezone))
        outputfile = "%s.csv" % dateportion
        self.mkdir(folder)
        self.chdir(folder)

        csv = []

        anCount = 0
        success = []
        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

                # Validate certain items aren't blank so we aren't registering bogus data
                if utils.nulltostr(an["CURRENTOWNERADDRESS"].strip()) == "":
                    self.logError(
                        "Address for the new owner is blank, cannot process")
                    continue

                if utils.nulltostr(an["CURRENTOWNERPOSTCODE"].strip()) == "":
                    self.logError(
                        "Postal code for the new owner is blank, cannot process"
                    )
                    continue

                # Make sure the length is actually suitable
                if not len(an["IDENTICHIPNUMBER"]) in (9, 10, 15):
                    self.logError(
                        "Microchip length is not 9, 10 or 15, cannot process")
                    continue

                servicedate = an["ACTIVEMOVEMENTDATE"] or an[
                    "MOSTRECENTENTRYDATE"]
                if an["NONSHELTERANIMAL"] == 1:
                    servicedate = an["IDENTICHIPDATE"]
                if servicedate < self.dbo.today(offset=-365 * 3):
                    self.logError(
                        "Service date is older than 3 years, ignoring")
                    continue

                # First Name
                line.append("\"%s\"" % an["CURRENTOWNERFORENAMES"])
                # Last Name
                line.append("\"%s\"" % an["CURRENTOWNERSURNAME"])
                # Email Address
                line.append("\"%s\"" % an["CURRENTOWNEREMAILADDRESS"])
                # Address 1
                line.append("\"%s\"" % an["CURRENTOWNERADDRESS"])
                # Address 2
                line.append("\"\"")
                # City
                line.append("\"%s\"" % an["CURRENTOWNERTOWN"])
                # State
                line.append("\"%s\"" % an["CURRENTOWNERCOUNTY"])
                # Zip Code
                line.append("\"%s\"" % an["CURRENTOWNERPOSTCODE"])
                # Home Phone
                line.append("\"%s\"" % an["CURRENTOWNERHOMETELEPHONE"])
                # Work Phone
                line.append("\"%s\"" % an["CURRENTOWNERWORKTELEPHONE"])
                # Cell Phone
                line.append("\"%s\"" % an["CURRENTOWNERMOBILETELEPHONE"])
                # Pet Name
                line.append("\"%s\"" % an["ANIMALNAME"])
                # Microchip Number
                line.append("\"%s\"" % an["IDENTICHIPNUMBER"])
                # Service Date
                line.append("\"%s\"" %
                            i18n.format_date("%m/%d/%Y", servicedate))
                # Date of Birth
                line.append("\"%s\"" %
                            i18n.format_date("%m/%d/%Y", an["DATEOFBIRTH"]))
                # Species
                line.append("\"%s\"" % an["PETFINDERSPECIES"])
                # Sex
                line.append("\"%s\"" % an["SEXNAME"])
                # Spayed/Neutered
                line.append("\"%s\"" %
                            utils.iif(an["NEUTERED"] == 1, "Yes", "No"))
                # Primary Breed
                line.append("\"%s\"" % an["PETFINDERBREED"])
                # Secondary Breed
                line.append("\"%s\"" % an["PETFINDERBREED2"])
                # Color
                line.append("\"%s\"" % an["BASECOLOURNAME"])
                # Implanting Organization
                line.append("\"%s\"" % org)
                # Rescue Group Email
                line.append("\"%s\"" % email)
                # 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)))
                success.append(an)
            except Exception as err:
                self.logError(
                    "Failed processing animal: %s, %s" %
                    (str(an["SHELTERCODE"]), err), sys.exc_info())

        # Bail if we didn't have anything to do
        if len(csv) == 0:
            self.log("No data left to send to foundanimals")
            self.cleanup()
            return

        # Mark published
        self.markAnimalsPublished(success)

        header = "First Name,Last Name,Email Address,Address 1,Address 2,City,State,Zip Code," \
            "Home Phone,Work Phone,Cell Phone,Pet Name,Microchip Number,Service Date," \
            "Date of Birth,Species,Sex,Spayed/Neutered,Primary Breed,Secondary Breed," \
            "Color,Implanting Organization,Rescue Group Email\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()
コード例 #14
0
    def run(self):

        self.log("PETtrac UK Publisher starting...")

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

        orgpostcode = configuration.avid_org_postcode(self.dbo)
        orgname = configuration.avid_org_name(self.dbo)
        orgserial = configuration.avid_org_serial(self.dbo)
        orgpassword = configuration.avid_org_password(self.dbo)
        avidrereg = configuration.avid_reregistration(self.dbo)

        orgaddress = configuration.organisation_address(self.dbo)
        orgtown = configuration.organisation_town(self.dbo)
        orgcounty = configuration.organisation_county(self.dbo)

        registeroverseas = configuration.avid_register_overseas(self.dbo)
        overseasorigin = configuration.avid_overseas_origin_country(self.dbo)

        if orgpostcode == "" or orgname == "" or orgserial == "" or orgpassword == "":
            self.setLastError(
                "orgpostcode, orgname, orgserial and orgpassword all need to be set for AVID publisher"
            )
            return

        authuser = configuration.avid_auth_user(self.dbo)
        user = users.get_users(self.dbo, authuser)
        if avidrereg and len(user) == 0:
            self.setLastError(
                "no authorised user is set, cannot re-register chips")
            return

        if avidrereg and utils.nulltostr(user[0]["SIGNATURE"]) == "":
            self.setLastError(
                "authorised user '%s' does not have an electronic signature on file"
                % authuser)
            return

        chipprefix = "977%"  # AVID Europe
        if registeroverseas:
            chipprefix = "a.IdentichipNumber LIKE '%'"  # If overseas registration is on, send all chips to AVID

        animals = get_microchip_data(self.dbo, [
            chipprefix,
        ],
                                     "pettracuk",
                                     allowintake=False or registeroverseas)
        if len(animals) == 0:
            self.setLastError("No animals found to publish.")
            return

        anCount = 0
        processed_animals = []
        for an in animals:
            try:
                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()
                    return

                # Validate certain items aren't blank so we aren't registering bogus data
                if utils.nulltostr(an["CURRENTOWNERADDRESS"].strip()) == "":
                    self.logError(
                        "Address for the new owner is blank, cannot process")
                    continue

                if utils.nulltostr(an["CURRENTOWNERPOSTCODE"].strip()) == "":
                    self.logError(
                        "Postal code for the new owner is blank, cannot process"
                    )
                    continue

                # Make sure the length is actually suitable
                if not len(an["IDENTICHIPNUMBER"]) in (9, 10, 15):
                    self.logError(
                        "Microchip length is not 9, 10 or 15, cannot process")
                    continue

                # Sort out breed
                breed = an["BREEDNAME"]
                if breed.find("Domestic Long") != -1: breed = "DLH"
                if breed.find("Domestic Short") != -1: breed = "DSH"
                if breed.find("Domestic Medium") != -1: breed = "DSLH"

                # Sort out species
                species = an["SPECIESNAME"]
                if species.find("Dog") != -1: species = "Canine"
                elif species.find("Cat") != -1: species = "Feline"
                elif species.find("Bird") != -1: species = "Avian"
                elif species.find("Horse") != -1: species = "Equine"
                elif species.find("Reptile") != -1: species = "Reptilian"
                else: species = "Other"

                # Build the animal POST data
                fields = {
                    "orgpostcode": orgpostcode,
                    "orgname": orgname,
                    "orgserial": orgserial,
                    "orgpassword": orgpassword,
                    "version": "1.1",
                    "microchip": an["IDENTICHIPNUMBER"],
                    "implantdate": i18n.format_date("%Y%m%d",
                                                    an["IDENTICHIPDATE"]),
                    "prefix": an["CURRENTOWNERTITLE"],
                    "surname": an["CURRENTOWNERSURNAME"],
                    "firstname": an["CURRENTOWNERFORENAMES"],
                    "address1": an["CURRENTOWNERADDRESS"],
                    "city": an["CURRENTOWNERTOWN"],
                    "county": an["CURRENTOWNERCOUNTY"],
                    "postcode": an["CURRENTOWNERPOSTCODE"],
                    "telhome": an["CURRENTOWNERHOMETELEPHONE"],
                    "telwork": an["CURRENTOWNERWORKTELEPHONE"],
                    "telmobile": an["CURRENTOWNERMOBILETELEPHONE"],
                    "telalternative": "",
                    "email": an["CURRENTOWNEREMAILADDRESS"],
                    "petname": an["ANIMALNAME"],
                    "petgender": an["SEXNAME"][0:1],
                    "petdob": i18n.format_date("%Y%m%d", an["DATEOFBIRTH"]),
                    "petspecies": species,
                    "petbreed": breed,
                    "petneutered": an["NEUTERED"] == 1 and "true" or "false",
                    "petcolour": an["BASECOLOURNAME"],
                    "selfreg":
                    "true",  # register the shelter as alternative contact
                    "test":
                    "false"  # if true, tells avid not to make any data changes
                }

                # If we're registering overseas chips and this chip isn't an AVID
                # one, set the origincountry parameter
                if registeroverseas and not an["IDENTICHIPNUMBER"].startswith(
                        "977"):
                    fields["origincountry"] = overseasorigin

                self.log("HTTP POST request %s: %s" %
                         (PETTRAC_UK_POST_URL, str(fields)))
                r = utils.post_form(PETTRAC_UK_POST_URL, fields)
                self.log("HTTP response: %s" % r["response"])

                # Return value is an XML fragment, look for "Registration completed successfully"
                if r["response"].find("successfully") != -1:
                    self.log("successful response, marking processed")
                    processed_animals.append(an)
                    # Mark success in the log
                    self.logSuccess("Processed: %s: %s (%d of %d)" %
                                    (an["SHELTERCODE"], an["ANIMALNAME"],
                                     anCount, len(animals)))

                # If AVID tell us the microchip is already registered, attempt to re-register
                elif r["response"].find("already registered") != -1:
                    if avidrereg:
                        self.log(
                            "microchip already registered response, re-registering"
                        )

                        pdfname = "%s-%s-%s.pdf" % (i18n.format_date(
                            "%Y%m%d", i18n.now(self.dbo.timezone)), orgserial,
                                                    an["IDENTICHIPNUMBER"])
                        fields["filenameupload"] = pdfname
                        pdf = self.reregistrationPDF(fields,
                                                     user[0]["SIGNATURE"],
                                                     user[0]["REALNAME"],
                                                     orgname, orgaddress,
                                                     orgtown, orgcounty,
                                                     orgpostcode)
                        self.log(
                            "generated re-registration PDF %s (%d bytes)" %
                            (pdfname, len(pdf)))

                        reregurl = PETTRAC_UK_POST_URL.replace(
                            "onlineregistration", "onlinereregistration")
                        self.log("HTTP multipart POST request %s: %s" %
                                 (reregurl, str(fields)))
                        r = utils.post_multipart(
                            reregurl, fields,
                            {pdfname: (pdfname, pdf, "application/pdf")})
                        self.log("HTTP response: %s" % r["response"])

                        if r["response"].find("successfully") != -1:
                            self.log(
                                "successful re-registration response, marking processed"
                            )
                            processed_animals.append(an)
                            # Mark success in the log
                            self.logSuccess(
                                "Processed: %s: %s (%d of %d) (rereg)" %
                                (an["SHELTERCODE"], an["ANIMALNAME"], anCount,
                                 len(animals)))
                        else:
                            self.logError(
                                "Problem with data encountered, not marking processed"
                            )
                    else:
                        self.logError(
                            "re-registration support is disabled, marking processed for compatibility"
                        )
                        processed_animals.append(an)
                # There's a problem with the data we sent, flag it
                else:
                    self.logError(
                        "Problem with data encountered, not marking processed")

            except Exception as err:
                self.logError(
                    "Failed processing animal: %s, %s" %
                    (str(an["SHELTERCODE"]), err), sys.exc_info())

        if len(processed_animals) > 0:
            self.log("successfully processed %d animals, marking sent" %
                     len(processed_animals))
            self.markAnimalsPublished(processed_animals)

        self.saveLog()
        self.setPublisherComplete()
コード例 #15
0
ファイル: users.py プロジェクト: magul/asm3
def web_login(post, session, remoteip, path):
    """
    Performs a login and sets up the user's session.
    Returns the username on successful login, or:
        FAIL        - problem with user/pass/account/ip
        DISABLED    - The database is disabled
        WRONGSERVER - The database is not on this server
    """
    dbo = db.DatabaseInfo()
    database = post["database"]
    username = post["username"]
    password = post["password"]
    mobileapp = post["mobile"] == "true"
    nologconnection = post["nologconnection"]
    if len(username) > 100:
        username = username[0:100]
    # Do we have multiple databases?
    if MULTIPLE_DATABASES:
        if MULTIPLE_DATABASES_TYPE == "smcom":
            # Is this sheltermanager.com? If so, we need to get the 
            # database connection info (dbo) before we can login.
            # If a database hasn't been supplied, let's bail out now
            # since we can't do anything
            if str(database).strip() == "":
                return "FAIL"
            else:
                dbo = smcom.get_database_info(database)
                # Bail out if there was a problem with the database
                if dbo.database in ("FAIL", "DISABLED", "WRONGSERVER"):
                    return dbo.database
        else:
            # Look up the database info from our map
            dbo  = db.get_multiple_database_info(database)
            if dbo.database == "FAIL":
                return dbo.database
    # Connect to the database and authenticate the username and password
    user = authenticate(dbo, username, password)
    if user is not None and not authenticate_ip(user, remoteip):
        al.error("user %s with ip %s failed ip restriction check '%s'" % (username, remoteip, user["IPRESTRICTION"]), "users.web_login", dbo)
        return "FAIL"
    if user is not None:
        al.info("%s successfully authenticated from %s" % (username, remoteip), "users.web_login", dbo)
        try:
            dbo.locked = configuration.smdb_locked(dbo)
            dbo.timezone = configuration.timezone(dbo)
            dbo.installpath = path
            session.locale = configuration.locale(dbo)
            dbo.locale = session.locale
            session.dbo = dbo
            session.user = user["USERNAME"]
            session.superuser = user["SUPERUSER"]
            session.passchange = (password == "password")
            session.mobileapp = mobileapp
            update_session(session)
        except:
            al.error("failed setting up session: %s" % str(sys.exc_info()[0]), "users.web_login", dbo, sys.exc_info())
            return "FAIL"
        try:
            session.securitymap = get_security_map(dbo, user["USERNAME"])
        except:
            # This is a pre-3002 login where the securitymap is with 
            # the user (the error occurs because there's no role table)
            al.debug("role table does not exist, using securitymap from user", "users.web_login", dbo)
            session.securitymap = user["SECURITYMAP"]
        try:
            ur = get_users(dbo, user["USERNAME"])[0]
            session.roles = ur["ROLES"]
            session.roleids = ur["ROLEIDS"]
            session.siteid = utils.cint(user["SITEID"])
            session.locationfilter = utils.nulltostr(user["LOCATIONFILTER"])
        except:
            # Users coming from v2 won't have the
            # IPRestriction or EmailAddress fields necessary for get_users - we can't
            # help them right now so just give them an empty set of
            # roles and locationfilter until they login again after the db update
            session.roles = ""
            session.roleids = ""
            session.locationfilter = ""
            session.siteid = 0
        try:
            # If it's a sheltermanager.com database, try and update the
            # last time the user connected to today
            if smcom.active() and database != "" and nologconnection == "":
                smcom.set_last_connected(dbo)
        except:
            pass
        try:
            # Mark the user logged in
            audit.login(dbo, username)
            # Check to see if any updates need performing on this database
            if dbupdate.check_for_updates(dbo):
                dbupdate.perform_updates(dbo)
                # We did some updates, better reload just in case config/reports/etc changed
                update_session(session)
            # Check to see if our views and sequences are out of date and need reloading
            if dbupdate.check_for_view_seq_changes(dbo):
                dbupdate.install_db_views(dbo)
                dbupdate.install_db_sequences(dbo)
        except:
            al.error("failed updating database: %s" % str(sys.exc_info()[0]), "users.web_login", dbo, sys.exc_info())
        try:
            al.info("%s logged in" % user["USERNAME"], "users.login", dbo)
            update_user_activity(dbo, user["USERNAME"])
        except:
            al.error("failed updating user activity: %s" % str(sys.exc_info()[0]), "users.web_login", dbo, sys.exc_info())
            return "FAIL"
    else:
        al.error("database:%s username:%s password:%s failed authentication from %s" % (database, username, password, remoteip), "users.web_login", dbo)
        return "FAIL"

    return user["USERNAME"]
コード例 #16
0
ファイル: users.py プロジェクト: tgage/asm3
def web_login(post, session, remoteip, path):
    """
    Performs a login and sets up the user's session.
    Returns the username on successful login, or:
        FAIL        - problem with user/pass/account/ip
        DISABLED    - The database is disabled
        WRONGSERVER - The database is not on this server
    """
    database = post["database"]
    username = post["username"]
    password = post["password"]
    mobileapp = post["mobile"] == "true"
    nologconnection = post["nologconnection"] == "true"
    if len(username) > 100:
        username = username[0:100]

    dbo = db.get_database(database)

    if dbo.database in ("FAIL", "DISABLED", "WRONGSERVER"):
        return dbo.database

    # Connect to the database and authenticate the username and password
    user = authenticate(dbo, username, password)
    if user is not None and not authenticate_ip(user, remoteip):
        al.error(
            "user %s with ip %s failed ip restriction check '%s'" %
            (username, remoteip, user.IPRESTRICTION), "users.web_login", dbo)
        return "FAIL"

    if user is not None and "DISABLELOGIN" in user and user.DISABLELOGIN == 1:
        al.error(
            "user %s with ip %s failed as account has logins disabled" %
            (username, remoteip), "users.web_login", dbo)
        return "FAIL"

    if user is not None:
        al.info("%s successfully authenticated from %s" % (username, remoteip),
                "users.web_login", dbo)

        try:
            dbo.locked = configuration.smdb_locked(dbo)
            dbo.timezone = configuration.timezone(dbo)
            dbo.installpath = path
            session.locale = configuration.locale(dbo)
            dbo.locale = session.locale
            session.dbo = dbo
            session.user = user.USERNAME
            session.superuser = user.SUPERUSER
            session.mobileapp = mobileapp
            update_session(session)
        except:
            al.error("failed setting up session: %s" % str(sys.exc_info()[0]),
                     "users.web_login", dbo, sys.exc_info())
            return "FAIL"

        try:
            session.securitymap = get_security_map(dbo, user.USERNAME)
        except:
            # This is a pre-3002 login where the securitymap is with
            # the user (the error occurs because there's no role table)
            al.debug("role table does not exist, using securitymap from user",
                     "users.web_login", dbo)
            session.securitymap = user.SECURITYMAP

        try:
            ur = get_users(dbo, user.USERNAME)[0]
            session.roles = ur.ROLES
            session.roleids = ur.ROLEIDS
            session.siteid = utils.cint(user.SITEID)
            session.locationfilter = utils.nulltostr(user.LOCATIONFILTER)
        except:
            # Users coming from v2 won't have the
            # IPRestriction or EmailAddress fields necessary for get_users - we can't
            # help them right now so just give them an empty set of
            # roles and locationfilter until they login again after the db update
            session.roles = ""
            session.roleids = ""
            session.locationfilter = ""
            session.siteid = 0

        try:
            # Mark the user logged in
            if not nologconnection:
                audit.login(dbo, username, remoteip)

            # Check to see if any updates need performing on this database
            if dbupdate.check_for_updates(dbo):
                dbupdate.perform_updates(dbo)
                # We did some updates, better reload just in case config/reports/etc changed
                update_session(session)

            # Check to see if our views and sequences are out of date and need reloading
            if dbupdate.check_for_view_seq_changes(dbo):
                dbupdate.install_db_views(dbo)
                dbupdate.install_db_sequences(dbo)

        except:
            al.error("failed updating database: %s" % str(sys.exc_info()[0]),
                     "users.web_login", dbo, sys.exc_info())

        try:
            al.info("%s logged in" % user.USERNAME, "users.login", dbo)
            update_user_activity(dbo, user.USERNAME)
        except:
            al.error(
                "failed updating user activity: %s" % str(sys.exc_info()[0]),
                "users.web_login", dbo, sys.exc_info())
            return "FAIL"
    else:
        al.error(
            "database:%s username:%s password:%s failed authentication from %s"
            % (database, username, password, remoteip), "users.web_login", dbo)
        return "FAIL"

    return user.USERNAME
コード例 #17
0
ファイル: lostfound.py プロジェクト: rutaq/asm3
def match(dbo, lostanimalid = 0, foundanimalid = 0, animalid = 0, limit = 0):
    """
    Performs a lost and found match by going through all lost animals
    lostanimalid:   Compare this lost animal against all found animals
    foundanimalid:  Compare all lost animals against this found animal
    animalid:       Compare all lost animals against this shelter animal
    limit:          Stop when we hit this many matches (or 0 for all)
    returns a list of LostFoundMatch objects
    """
    l = dbo.locale
    batch = []
    matches = []
    matchspecies = configuration.match_species(dbo)
    matchbreed = configuration.match_breed(dbo)
    matchage = configuration.match_age(dbo)
    matchsex = configuration.match_sex(dbo)
    matcharealost = configuration.match_area_lost(dbo)
    matchfeatures = configuration.match_features(dbo)
    matchpostcode = configuration.match_postcode(dbo)
    matchcolour = configuration.match_colour(dbo)
    matchdatewithin2weeks = configuration.match_within2weeks(dbo)
    matchmax = matchspecies + matchbreed + matchage + matchsex + \
        matcharealost + matchfeatures + matchpostcode + matchcolour + \
        matchdatewithin2weeks
    matchpointfloor = configuration.match_point_floor(dbo)
    includeshelter = configuration.match_include_shelter(dbo)
    fullmatch = animalid == 0 and lostanimalid == 0 and foundanimalid == 0
    # Ignore records older than 6 months to keep things useful
    giveup = dbo.today(offset=-182)

    # Get our set of lost animals
    lostanimals = None
    if lostanimalid == 0:
        lostanimals = dbo.query(get_lostanimal_query(dbo) + \
            " WHERE a.DateFound Is Null AND a.DateLost > ? ORDER BY a.DateLost", [giveup])
    else:
        lostanimals = dbo.query(get_lostanimal_query(dbo) + \
            " WHERE a.ID = ?", [lostanimalid])

    oldestdate = giveup
    if len(lostanimals) > 0:
        oldestdate = lostanimals[0].DATELOST

    # Get the set of found animals for comparison
    foundanimals = None
    if foundanimalid == 0:
        foundanimals = dbo.query(get_foundanimal_query(dbo) + \
            " WHERE a.ReturnToOwnerDate Is Null" \
            " AND a.DateFound >= ? ", [oldestdate])
    else:
        foundanimals = dbo.query(get_foundanimal_query(dbo) + " WHERE a.ID = ?", [foundanimalid])

    # Get the set of shelter animals for comparison - anything brought in recently
    # that's 1. still on shelter or 2. was released to wild, transferred or escaped
    shelteranimals = None
    if includeshelter:
        if animalid == 0:
            shelteranimals = dbo.query(animal.get_animal_query(dbo) + " WHERE " + \
                "(a.Archived = 0 OR a.ActiveMovementType IN (3,4,7)) " \
                "AND a.DateBroughtIn > ?", [oldestdate])
        else:
            shelteranimals = dbo.query(animal.get_animal_query(dbo) + " WHERE a.ID = ?", [animalid])

    asynctask.set_progress_max(dbo, len(lostanimals))
    for la in lostanimals:
        asynctask.increment_progress_value(dbo)
        # Stop if we've hit our limit
        if limit > 0 and len(matches) >= limit:
            break
        # Found animals (if an animal id has been given don't
        # check found animals)
        if animalid == 0:
            for fa in foundanimals:
                matchpoints = 0
                if la["ANIMALTYPEID"] == fa["ANIMALTYPEID"]: matchpoints += matchspecies
                if la["BREEDID"] == fa["BREEDID"]: matchpoints += matchbreed
                if la["AGEGROUP"] == fa["AGEGROUP"]: matchpoints += matchage
                if la["SEX"] == fa["SEX"]: matchpoints += matchsex
                matchpoints += words(la["AREALOST"], fa["AREAFOUND"], matcharealost)
                matchpoints += words(la["DISTFEAT"], fa["DISTFEAT"], matchfeatures)
                if la["AREAPOSTCODE"] == fa["AREAPOSTCODE"]: matchpoints += matchpostcode
                if la["BASECOLOURID"] == fa["BASECOLOURID"]: matchpoints += matchcolour
                if date_diff_days(la["DATELOST"], fa["DATEFOUND"]) <= 14: matchpoints += matchdatewithin2weeks
                if matchpoints > matchmax: matchpoints = matchmax
                if matchpoints >= matchpointfloor:
                    m = LostFoundMatch(dbo)
                    m.lid = la["ID"]
                    m.lcontactname = la["OWNERNAME"]
                    m.lcontactnumber = la["HOMETELEPHONE"]
                    m.larealost = la["AREALOST"]
                    m.lareapostcode = la["AREAPOSTCODE"]
                    m.lagegroup = la["AGEGROUP"]
                    m.lsexid = la["SEX"]
                    m.lsexname = la["SEXNAME"]
                    m.lspeciesid = la["ANIMALTYPEID"]
                    m.lspeciesname = la["SPECIESNAME"]
                    m.lbreedid = la["BREEDID"]
                    m.lbreedname = la["BREEDNAME"]
                    m.ldistinguishingfeatures = la["DISTFEAT"]
                    m.lbasecolourid = la["BASECOLOURID"]
                    m.lbasecolourname = la["BASECOLOURNAME"]
                    m.ldatelost = la["DATELOST"]
                    m.fid = fa["ID"]
                    m.fanimalid = 0
                    m.fcontactname = fa["OWNERNAME"]
                    m.fcontactnumber = fa["HOMETELEPHONE"]
                    m.fareafound = fa["AREAFOUND"]
                    m.fareapostcode = fa["AREAPOSTCODE"]
                    m.fagegroup = fa["AGEGROUP"]
                    m.fsexid = fa["SEX"]
                    m.fsexname = fa["SEXNAME"]
                    m.fspeciesid = fa["ANIMALTYPEID"]
                    m.fspeciesname = fa["SPECIESNAME"]
                    m.fbreedid = fa["BREEDID"]
                    m.fbreedname = fa["BREEDNAME"]
                    m.fdistinguishingfeatures = fa["DISTFEAT"]
                    m.fbasecolourid = fa["BASECOLOURID"]
                    m.fbasecolourname = fa["BASECOLOURNAME"]
                    m.fdatefound = fa["DATEFOUND"]
                    m.matchpoints = int((float(matchpoints) / float(matchmax)) * 100.0)
                    matches.append(m)
                    if fullmatch: 
                        batch.append(m.toParams())
                    if limit > 0 and len(matches) >= limit:
                        break

        # Shelter animals
        if includeshelter:
            for a in shelteranimals:
                matchpoints = 0
                if la["ANIMALTYPEID"] == a["SPECIESID"]: matchpoints += matchspecies
                if la["BREEDID"] == a["BREEDID"] or la["BREEDID"] == a["BREED2ID"]: matchpoints += matchbreed
                if la["BASECOLOURID"] == a["BASECOLOURID"]: matchpoints += matchcolour
                if la["AGEGROUP"] == a["AGEGROUP"]: matchpoints += matchage
                if la["SEX"] == a["SEX"]: matchpoints += matchsex
                matchpoints += words(la["AREALOST"], a["ORIGINALOWNERADDRESS"], matcharealost)
                matchpoints += words(la["DISTFEAT"], a["MARKINGS"], matchfeatures)
                if utils.nulltostr(a["ORIGINALOWNERPOSTCODE"]).find(la["AREAPOSTCODE"]) != -1: matchpoints += matchpostcode
                if date_diff_days(la["DATELOST"], a["DATEBROUGHTIN"]) <= 14: matchpoints += matchdatewithin2weeks
                if matchpoints > matchmax: matchpoints = matchmax
                if matchpoints >= matchpointfloor:
                    m = LostFoundMatch(dbo)
                    m.lid = la["ID"]
                    m.lcontactname = la["OWNERNAME"]
                    m.lcontactnumber = la["HOMETELEPHONE"]
                    m.larealost = la["AREALOST"]
                    m.lareapostcode = la["AREAPOSTCODE"]
                    m.lagegroup = la["AGEGROUP"]
                    m.lsexid = la["SEX"]
                    m.lsexname = la["SEXNAME"]
                    m.lspeciesid = la["ANIMALTYPEID"]
                    m.lspeciesname = la["SPECIESNAME"]
                    m.lbreedid = la["BREEDID"]
                    m.lbreedname = la["BREEDNAME"]
                    m.ldistinguishingfeatures = la["DISTFEAT"]
                    m.lbasecolourid = la["BASECOLOURID"]
                    m.lbasecolourname = la["BASECOLOURNAME"]
                    m.ldatelost = la["DATELOST"]
                    m.fid = 0
                    m.fanimalid = a["ID"]
                    m.fcontactname = _("Shelter animal {0} '{1}'", l).format(a["CODE"], a["ANIMALNAME"])
                    m.fcontactnumber = a["SPECIESNAME"]
                    m.fareafound = _("On Shelter", l)
                    m.fareapostcode = a["ORIGINALOWNERPOSTCODE"]
                    m.fagegroup = a["AGEGROUP"]
                    m.fsexid = a["SEX"]
                    m.fsexname = a["SEXNAME"]
                    m.fspeciesid = a["SPECIESID"]
                    m.fspeciesname = a["SPECIESNAME"]
                    m.fbreedid = a["BREEDID"]
                    m.fbreedname = a["BREEDNAME"]
                    m.fdistinguishingfeatures = a["MARKINGS"]
                    m.fbasecolourid = a["BASECOLOURID"]
                    m.fbasecolourname = a["BASECOLOURNAME"]
                    m.fdatefound = a["DATEBROUGHTIN"]
                    m.matchpoints = int((float(matchpoints) / float(matchmax)) * 100.0)
                    matches.append(m)
                    if fullmatch:
                        batch.append(m.toParams())
                    if limit > 0 and len(matches) >= limit:
                        break

    if fullmatch:
        dbo.execute("DELETE FROM animallostfoundmatch")
        sql = "INSERT INTO animallostfoundmatch (AnimalLostID, AnimalFoundID, AnimalID, LostContactName, LostContactNumber, " \
            "LostArea, LostPostcode, LostAgeGroup, LostSex, LostSpeciesID, LostBreedID, LostFeatures, LostBaseColourID, LostDate, " \
            "FoundContactName, FoundContactNumber, FoundArea, FoundPostcode, FoundAgeGroup, FoundSex, FoundSpeciesID, FoundBreedID, " \
            "FoundFeatures, FoundBaseColourID, FoundDate, MatchPoints) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
        if len(batch) > 0:
            dbo.execute_many(sql, batch)

    return matches
コード例 #18
0
    def run(self):
        def xe(s):
            if s is None: return ""
            return s.replace("&",
                             "&amp;").replace("<",
                                              "&lt;").replace(">", "&gt;")

        self.log(self.publisherName + " starting...")

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

        practiceid = configuration.anibase_practice_id(self.dbo)
        pinno = configuration.anibase_pin_no(self.dbo)

        if pinno == "":
            self.setLastError("Anibase vet code must be set")
            return

        animals = get_microchip_data(self.dbo, ['9851', '9861'], "anibaseuk")
        if len(animals) == 0:
            self.setLastError("No animals found to publish.")
            return

        anCount = 0
        processed_animals = []
        for an in animals:
            try:
                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()
                    return

                # Validate certain items aren't blank so we aren't registering bogus data
                if utils.nulltostr(an["CURRENTOWNERADDRESS"].strip()) == "":
                    self.logError(
                        "Address for the new owner is blank, cannot process")
                    continue

                if utils.nulltostr(an["CURRENTOWNERPOSTCODE"].strip()) == "":
                    self.logError(
                        "Postal code for the new owner is blank, cannot process"
                    )
                    continue

                if an["IDENTICHIPDATE"] is None:
                    self.logError(
                        "Microchip date cannot be blank, cannot process")
                    continue

                # Make sure the length is actually suitable
                if not len(an["IDENTICHIPNUMBER"]) in (9, 10, 15):
                    self.logError(
                        "Microchip length is not 9, 10 or 15, cannot process")
                    continue

                # Construct the XML document
                x = '<?xml version="1.0" encoding="UTF-8"?>\n' \
                    '<MicrochipRegistration>' \
                    '<Identification>' \
                    ' <PracticeID>' + practiceid + '</PracticeID>' \
                    ' <PinNo>' + pinno + '</PinNo>' \
                    ' <Source></Source>' \
                    '</Identification>' \
                    '<OwnerDetails>' \
                    ' <Salutation>' + xe(an["CURRENTOWNERTITLE"]) + '</Salutation>' \
                    ' <Initials>' + xe(an["CURRENTOWNERINITIALS"]) + '</Initials>' \
                    ' <Forenames>' + xe(an["CURRENTOWNERFORENAMES"]) + '</Forenames>' \
                    ' <Surname>' + xe(an["CURRENTOWNERSURNAME"]) + '</Surname>' \
                    ' <Address>' \
                    '  <Line1>'+ xe(an["CURRENTOWNERADDRESS"]) + '</Line1>' \
                    '  <LineOther>'+ xe(an["CURRENTOWNERTOWN"]) + '</LineOther>' \
                    '  <PostalCode>' + xe(an["CURRENTOWNERPOSTCODE"]) + '</PostalCode>' \
                    '  <County_State>'+ xe(an["CURRENTOWNERCOUNTY"]) + '</County_State>' \
                    '  <Country>USA</Country>' \
                    ' </Address>' \
                    ' <DaytimePhone><Number>' + xe(an["CURRENTOWNERWORKTELEPHONE"]) + '</Number><Note/></DaytimePhone>' \
                    ' <EveningPhone><Number>' + xe(an["CURRENTOWNERHOMETELEPHONE"]) + '</Number><Note/></EveningPhone>' \
                    ' <MobilePhone><Number>' + xe(an["CURRENTOWNERMOBILETELEPHONE"]) + '</Number><Note/></MobilePhone>' \
                    ' <EmergencyPhone><Number/><Note/></EmergencyPhone>' \
                    ' <OtherPhone><Number/><Note/></OtherPhone>' \
                    ' <EmailAddress>' + xe(an["CURRENTOWNEREMAILADDRESS"]) + '</EmailAddress>' \
                    ' <Fax />' \
                    '</OwnerDetails>' \
                    '<PetDetails>' \
                    '  <Name>' + xe(an["ANIMALNAME"]) + '</Name>' \
                    '  <Species>' + self.get_vetxml_species(an["SPECIESID"]) + '</Species>' \
                    '  <Breed><FreeText>' + xe(an["BREEDNAME"]) + '</FreeText><Code/></Breed>' \
                    '  <DateOfBirth>' + i18n.format_date("%m/%d/%Y", an["DATEOFBIRTH"]) + '</DateOfBirth>' \
                    '  <Gender>' + an["SEXNAME"][0:1] + '</Gender>' \
                    '  <Colour>' + xe(an["BASECOLOURNAME"]) + '</Colour>' \
                    '  <Markings>' + xe(an["MARKINGS"]) + '</Markings>' \
                    '  <Neutered>' + (an["NEUTERED"] == 1 and "true" or "false") + '</Neutered>' \
                    '  <NotableConditions>' + xe(an["HEALTHPROBLEMS"]) + '</NotableConditions>' \
                    '</PetDetails>' \
                    '<MicrochipDetails>' \
                    '  <MicrochipNumber>' + xe(an["IDENTICHIPNUMBER"]) + '</MicrochipNumber>' \
                    '  <ImplantDate>' + i18n.format_date("%m/%d/%Y", an["IDENTICHIPDATE"]) + '</ImplantDate>' \
                    '  <ImplanterName>' + xe(an["CREATEDBY"]) + '</ImplanterName>' \
                    '</MicrochipDetails>' \
                    '<ThirdPartyDisclosure>true</ThirdPartyDisclosure>' \
                    '<ReceiveMail>true</ReceiveMail>' \
                    '<ReceiveEmail>true</ReceiveEmail>' \
                    '<Authorisation>true</Authorisation>' \
                    '</MicrochipRegistration>'

                # Build our auth headers
                authheaders = {
                    "APIUSER": ANIBASE_API_USER,
                    "APIKEY": ANIBASE_API_KEY
                }

                try:
                    # Post the VetXML document
                    self.log(
                        "Posting microchip registration document to %s \n%s\n"
                        % (ANIBASE_BASE_URL, x))
                    r = utils.post_xml(ANIBASE_BASE_URL, x, authheaders)
                    self.log("Response %d, HTTP headers: %s, body: %s" %
                             (r["status"], r["headers"], r["response"]))
                    if r["status"] != 200: raise Exception(r["response"])

                    # Look in the headers for successful results
                    wassuccess = False
                    SUCCESS = ("54000", "54100", "54108")
                    for code in SUCCESS:
                        if str(r["headers"]).find(code) != -1:
                            self.log(
                                "successful %s response header found, marking processed"
                                % code)
                            processed_animals.append(an)
                            # Mark success in the log
                            self.logSuccess(
                                "Processed: %s: %s (%d of %d)" %
                                (an["SHELTERCODE"], an["ANIMALNAME"], anCount,
                                 len(animals)))
                            wassuccess = True
                            break

                    # If we got a chipfound=false or chipRegisterable=false message, mark the chip as processed
                    # and a success so we don't try and register it in future
                    if str(
                            r["response"]
                    ).find("<chipFound>false</chipFound>") != -1 or str(
                            r["response"]
                    ).find("<chipRegisterable>false</chipRegisterable>") != -1:
                        self.log(
                            "chipFound=false/chipRegisterable=false response found, marking chip processed to prevent future sending"
                        )
                        processed_animals.append(an)
                        wassuccess = True

                    # If we saw an account not found message, there's no point sending
                    # anything else as they will all trigger the same error
                    if str(r["headers"]).find("54101") != -1:
                        self.logError(
                            "received Anibase 54101 'sender not recognised' response header - abandoning run"
                        )
                        break

                    if not wassuccess:
                        self.logError(
                            "no successful response header %s received" %
                            str(SUCCESS))

                except Exception as err:
                    em = str(err)
                    self.logError("Failed registering microchip: %s" % em,
                                  sys.exc_info())
                    continue

            except Exception as err:
                self.logError(
                    "Failed processing animal: %s, %s" %
                    (str(an["SHELTERCODE"]), err), sys.exc_info())

        # Only mark processed if we aren't using Anibase test URL
        if len(processed_animals) > 0 and ANIBASE_BASE_URL.find("test") == -1:
            self.log("successfully processed %d animals, marking sent" %
                     len(processed_animals))
            self.markAnimalsPublished(processed_animals)

        if ANIBASE_BASE_URL.find("test") != -1:
            self.log("Anibase test mode, not marking animals published")

        self.saveLog()
        self.setPublisherComplete()
コード例 #19
0
ファイル: users.py プロジェクト: MoriEdan/sheltermanager
def web_login(post, session, remoteip, path):
    """
    Performs a login and sets up the user's session.
    Returns the username on successful login, or:
        FAIL     - problem with user/pass/account/ip
        DISABLED - The database is disabled
    """
    dbo = db.DatabaseInfo()
    database = post["database"]
    username = post["username"]
    password = post["password"]
    nologconnection = post["nologconnection"]
    # Do we have multiple databases?
    if MULTIPLE_DATABASES:
        if MULTIPLE_DATABASES_TYPE == "smcom":
            # Is this sheltermanager.com? If so, we need to get the
            # database connection info (dbo) before we can login.
            # If a database hasn't been supplied, let's bail out now
            # since we can't do anything
            if str(database).strip() == "":
                return "FAIL"
            else:
                dbo = smcom.get_database_info(database)
                # Bail out if there was a problem with the database
                if dbo.database == "FAIL" or dbo.database == "DISABLED":
                    return dbo.database
        else:
            # Look up the database info from our map
            dbo = db.get_multiple_database_info(database)
            if dbo.database == "FAIL":
                return dbo.database
    # Connect to the database and authenticate the username and password
    user = authenticate(dbo, username, password)
    if user is not None and not authenticate_ip(user, remoteip):
        al.error(
            "user %s with ip %s failed ip restriction check '%s'" %
            (username, remoteip, user["IPRESTRICTION"]), "users.web_login",
            dbo)
        return "FAIL"
    if user is not None:
        al.info("%s successfully authenticated from %s" % (username, remoteip),
                "users.web_login", dbo)
        try:
            dbo.locked = configuration.smdb_locked(dbo)
            dbo.timezone = configuration.timezone(dbo)
            dbo.installpath = path
            session.locale = configuration.locale(dbo)
            dbo.locale = session.locale
            session.dbo = dbo
            session.user = user["USERNAME"]
            session.superuser = user["SUPERUSER"]
            session.passchange = (password == "password")
            update_session(session)
        except:
            al.error("failed setting up session: %s" % str(sys.exc_info()[0]),
                     "users.web_login", dbo, sys.exc_info())
            return "FAIL"
        try:
            session.securitymap = get_security_map(dbo, user["USERNAME"])
        except:
            # This is a pre-3002 login where the securitymap is with
            # the user (the error occurs because there's no role table)
            al.debug("role table does not exist, using securitymap from user",
                     "users.web_login", dbo)
            session.securitymap = user["SECURITYMAP"]
        try:
            ur = get_users(dbo, user["USERNAME"])[0]
            session.roles = ur["ROLES"]
            session.roleids = ur["ROLEIDS"]
            session.locationfilter = utils.nulltostr(user["LOCATIONFILTER"])
        except:
            # Users coming from v2 won't have the
            # IPRestriction or EmailAddress fields necessary for get_users - we can't
            # help them right now so just give them an empty set of
            # roles and locationfilter until they login again after the db update
            session.roles = ""
            session.roleids = ""
            session.locationfilter = ""
        try:
            # If it's a sheltermanager.com database, try and update the
            # last time the user connected to today
            if smcom.active() and database != "" and nologconnection == "":
                smcom.set_last_connected(dbo)
        except:
            pass
        try:
            # Check to see if any updates need performing on this database
            if dbupdate.check_for_updates(dbo):
                dbupdate.perform_updates(dbo)
                # We did some updates, better reload just in case config/reports/etc changed
                update_session(session)
            # Check to see if our views and sequences are out of date and need reloading
            if dbupdate.check_for_view_seq_changes(dbo):
                dbupdate.install_db_views(dbo)
                dbupdate.install_db_sequences(dbo)
        except:
            al.error("failed updating database: %s" % str(sys.exc_info()[0]),
                     "users.web_login", dbo, sys.exc_info())
        try:
            # Log out any old users that have been hanging around
            auto_logout(dbo)
            # Let this user through
            login(dbo, user["USERNAME"])
        except:
            al.error(
                "failed updating activeuser table: %s" %
                str(sys.exc_info()[0]), "users.web_login", dbo, sys.exc_info())
            return "FAIL"
    else:
        al.error(
            "database:%s username:%s password:%s failed authentication from %s"
            % (database, username, password, remoteip), "users.web_login", dbo)
        return "FAIL"

    return user["USERNAME"]
コード例 #20
0
    def run(self):

        self.log("Maddies Fund Publisher starting...")

        BATCH_SIZE = 250  # How many animals to send in one POST
        PERIOD = 214  # How many days to go back when checking for fosters and adoptions (7 months * 30.5 = 214 days)

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

        username = configuration.maddies_fund_username(self.dbo)
        password = configuration.maddies_fund_password(self.dbo)
        organisation = configuration.organisation(self.dbo)

        if username == "" or password == "":
            self.setLastError(
                "username and password all need to be set for Maddies Fund Publisher"
            )
            self.cleanup()
            return

        # Send all fosters and adoptions for the period that haven't been sent since they last had a change.
        # (we use lastchangeddate instead of sent date because MPA want an update when a number of key
        #  animal fields change, such as neuter status, microchip info, rabies tag, etc)
        cutoff = i18n.subtract_days(i18n.now(self.dbo.timezone), PERIOD)
        sql = "%s WHERE a.ActiveMovementType IN (1,2) " \
            "AND a.ActiveMovementDate >= ? AND a.DeceasedDate Is Null AND a.NonShelterAnimal = 0 " \
            "AND NOT EXISTS(SELECT AnimalID FROM animalpublished WHERE AnimalID = a.ID AND PublishedTo = 'maddiesfund' AND SentDate >= %s) " \
            "ORDER BY a.ID" % (animal.get_animal_query(self.dbo), self.dbo.sql_greatest(["a.ActiveMovementDate", "a.LastChangedDate"]))
        animals = self.dbo.query(sql, [cutoff], distincton="ID")

        # Now find animals who have been sent previously and are now deceased (using sent date against deceased to prevent re-sends)
        sql = "%s WHERE a.DeceasedDate Is Not Null AND a.DeceasedDate >= ? AND " \
            "EXISTS(SELECT AnimalID FROM animalpublished WHERE AnimalID = a.ID AND " \
            "PublishedTo = 'maddiesfund' AND SentDate < a.DeceasedDate)" % animal.get_animal_query(self.dbo)
        animals += self.dbo.query(sql, [cutoff], distincton="ID")

        # Now find shelter animals who have been sent previously and are back (using sent date against return to prevent re-sends)
        sql = "%s WHERE a.Archived = 0 AND " \
            "EXISTS(SELECT AnimalID FROM animalpublished WHERE AnimalID = a.ID AND " \
            "PublishedTo = 'maddiesfund' AND SentDate < " \
            "(SELECT MAX(ReturnDate) FROM adoption WHERE AnimalID = a.ID AND MovementType IN (1,2) AND ReturnDate Is Not Null))" % animal.get_animal_query(self.dbo)
        animals += self.dbo.query(sql, distincton="ID")

        # Now find animals who have been sent previously and have a new/changed vaccination since then
        sql = "%s WHERE a.Archived = 0 AND " \
            "EXISTS(SELECT p.AnimalID FROM animalpublished p INNER JOIN animalvaccination av ON av.AnimalID = a.ID WHERE p.AnimalID = a.ID AND " \
            "p.PublishedTo = 'maddiesfund' AND (p.SentDate < av.CreatedDate OR p.SentDate < av.LastChangedDate))" % animal.get_animal_query(self.dbo)
        animals += self.dbo.query(sql, [cutoff], distincton="ID")

        if len(animals) == 0:
            self.setLastError("No animals found to publish.")
            return

        # Get an authentication token
        token = ""
        try:
            fields = {
                "username": username,
                "password": password,
                "grant_type": "password"
            }
            r = utils.post_form(MADDIES_FUND_TOKEN_URL, fields)
            token = utils.json_parse(r["response"])["access_token"]
            self.log("got access token: %s (%s)" % (token, r["response"]))
        except Exception as err:
            self.setLastError(
                "failed to get access token: %s (request: '%s') (response: '%s')"
                % (err, r["requestbody"], r["response"]))
            self.cleanup()
            return

        anCount = 0
        thisbatch = []
        processed = []
        for an in animals:
            try:
                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()
                    return

                # Build an adoption JSON object containing the adopter and animal
                a = {
                    "PetID":
                    an["ID"],
                    "PetCode":
                    an["SHELTERCODE"],
                    "Site":
                    organisation,
                    "PetName":
                    an["ANIMALNAME"],
                    "PetStatus":
                    self.getPetStatus(an),
                    "PetLitterID":
                    an["ACCEPTANCENUMBER"],
                    "GroupType":
                    utils.iif(
                        utils.nulltostr(an["ACCEPTANCENUMBER"]) != "",
                        "Litter", ""),
                    "PetSpecies":
                    an["SPECIESNAME"],
                    "PetSex":
                    an["SEXNAME"],
                    "DateofBirth":
                    self.getDate(an["DATEOFBIRTH"]),
                    "SpayNeuterStatus":
                    utils.iif(an["NEUTERED"] == 1, "Spayed/Neutered", ""),
                    "Breed":
                    an["BREEDNAME"],
                    "Color":
                    an["BASECOLOURNAME"],
                    "SecondaryColor":
                    "",
                    "Pattern":
                    "",
                    "HealthStatus":
                    an["ASILOMARINTAKECATEGORY"] +
                    1,  # We're zero based, they use 1-base
                    "PetBiography":
                    an["ANIMALCOMMENTS"],
                    "Photo":
                    "%s?method=animal_image&account=%s&animalid=%s" %
                    (SERVICE_URL, self.dbo.database, an["ID"]),
                    "Microchip":
                    an["IDENTICHIPNUMBER"],
                    "MicrochipIssuer":
                    lookups.get_microchip_manufacturer(self.dbo.locale,
                                                       an["IDENTICHIPNUMBER"]),
                    "RelationshipType":
                    self.getRelationshipType(an),
                    "FosterCareDate":
                    self.getDate(an["ACTIVEMOVEMENTDATE"]),
                    "FosterEndDate":
                    "",
                    "RabiesTag":
                    an["RABIESTAG"],
                    "ID":
                    an["CURRENTOWNERID"],
                    "Firstname":
                    an["CURRENTOWNERFORENAMES"],
                    "Lastname":
                    an["CURRENTOWNERSURNAME"],
                    "EmailAddress":
                    self.getEmail(an["CURRENTOWNEREMAILADDRESS"]),
                    "Street":
                    an["CURRENTOWNERADDRESS"],
                    "Apartment":
                    "",
                    "City":
                    an["CURRENTOWNERTOWN"],
                    "State":
                    an["CURRENTOWNERCOUNTY"],
                    "Zipcode":
                    an["CURRENTOWNERPOSTCODE"],
                    "ContactNumber":
                    an["CURRENTOWNERHOMETELEPHONE"],
                    "Organization":
                    organisation,
                }

                # Build a list of intake histories - use the initial one first
                ph = [{
                    "IntakeType": an["ENTRYREASONNAME"],
                    "IntakeDate": self.getDate(an["DATEBROUGHTIN"]),
                    "City": utils.nulltostr(an["BROUGHTINBYOWNERTOWN"]),
                    "State": utils.nulltostr(an["BROUGHTINBYOWNERCOUNTY"]),
                    "LengthOwned": ""
                }]
                # Then any exit movements where the animal was returned
                for ra in movement.get_animal_movements(self.dbo, an["ID"]):
                    if ra["MOVEMENTTYPE"] > 0 and ra["MOVEMENTTYPE"] not in (
                            2, 8) and ra["RETURNDATE"] is not None:
                        ph.append({
                            "IntakeType": ra["RETURNEDREASONNAME"],
                            "IntakeDate": self.getDate(ra["RETURNDATE"]),
                            "City": utils.nulltostr(ra["OWNERTOWN"]),
                            "State": utils.nulltostr(ra["OWNERCOUNTY"]),
                            "LengthOwned": ""  # We don't have this info
                        })
                a["PetHistoryDetails"] = ph

                # Next add vaccination histories
                vh = []
                for v in medical.get_vaccinations(self.dbo, an["ID"]):
                    vh.append({
                        "VaccinationRecordNumber":
                        str(v["ID"]),
                        "VaccinationStatus":
                        utils.iif(v["DATEOFVACCINATION"] is not None,
                                  "Completed", "Scheduled"),
                        "VaccinationStatusDateTime":
                        self.getDate(v["DATEREQUIRED"]),
                        "Vaccine":
                        v["VACCINATIONTYPE"],
                        "Type":
                        "",  # Live/Killed - we don't keep this info yet, see issue #281
                        "Manufacturer":
                        utils.nulltostr(v["MANUFACTURER"]),
                        "VaccineLot":
                        utils.nulltostr(v["BATCHNUMBER"]),
                        "VaccinationNotes":
                        v["COMMENTS"],
                        "Length":
                        "",  # Not sure what this value is for - advised to ignore by MPA devs
                        "RevaccinationDate":
                        self.getDate(v["DATEEXPIRES"])
                    })
                a["PetVaccinationDetails"] = vh

                thisbatch.append(a)
                processed.append(an)
                self.logSuccess("Processed: %s: %s (%d of %d)" %
                                (an["SHELTERCODE"], an["ANIMALNAME"], anCount,
                                 len(animals)))

                # If we have hit our batch size, or this is the
                # last animal then send what we have.
                if len(thisbatch) == BATCH_SIZE or anCount == len(animals):
                    j = utils.json({"Animals": thisbatch})
                    headers = {"Authorization": "Bearer %s" % token}
                    self.log(
                        "HTTP POST request %s: headers: '%s', body: '%s'" %
                        (MADDIES_FUND_UPLOAD_URL, headers, j))
                    r = utils.post_json(MADDIES_FUND_UPLOAD_URL, j, headers)
                    if r["status"] != 200:
                        self.logError("HTTP %d response: %s" %
                                      (r["status"], r["response"]))
                    else:
                        self.log("HTTP %d response: %s" %
                                 (r["status"], r["response"]))
                        self.markAnimalsPublished(processed)
                    # start counting again
                    thisbatch = []
                    processed = []

            except Exception as err:
                self.logError(
                    "Failed processing animal: %s, %s" %
                    (an["SHELTERCODE"], err), sys.exc_info())

        self.cleanup()
コード例 #21
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
コード例 #22
0
    def run(self):

        self.log("PetLinkPublisher starting...")

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

        plemail = configuration.petlink_email(self.dbo)
        plowneremail = configuration.petlink_owner_email(self.dbo)
        password = configuration.petlink_password(self.dbo)

        if plemail == "" or password == "":
            self.setLastError("No PetLink login has been set.")
            return

        animals = get_microchip_data(self.dbo, [
            '98102',
        ],
                                     "petlink",
                                     organisation_email=plowneremail)
        if len(animals) == 0:
            self.setLastError("No animals found to publish.")
            return

        anCount = 0
        csv = []
        processed_animals = []
        failed_animals = []

        csv.append("Software,TransactionType,MicrochipID,FirstName,LastName,Address,City,State,ZipCode,Country," \
            "Phone1,Phone2,Phone3,Email,Password,Date_of_Implant,PetName,Species,Breed,Gender," \
            "Spayed_Neutered,ColorMarkings")

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

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

                # If the microchip number isn't 15 digits, skip it
                if len(an["IDENTICHIPNUMBER"].strip()) != 15:
                    self.logError(
                        "Chip number failed validation (%s not 15 digits), skipping."
                        % an["IDENTICHIPNUMBER"])
                    continue

                # Validate certain items aren't blank so we aren't trying to register
                # things that PetLink will bounce back anyway
                if utils.nulltostr(an["CURRENTOWNERTOWN"]).strip() == "":
                    self.logError(
                        "City for the new owner is blank, cannot process")
                    continue

                if utils.nulltostr(an["CURRENTOWNERCOUNTY"]).strip() == "":
                    self.logError(
                        "State for the new owner is blank, cannot process")
                    continue

                if utils.nulltostr(an["CURRENTOWNERPOSTCODE"]).strip() == "":
                    self.logError(
                        "Zipcode for the new owner is blank, cannot process")
                    continue

                # If there's no email or phone, PetLink won't accept it
                email = utils.nulltostr(an["CURRENTOWNEREMAILADDRESS"]).strip()
                homephone = utils.nulltostr(
                    an["CURRENTOWNERHOMETELEPHONE"]).strip()
                workphone = utils.nulltostr(
                    an["CURRENTOWNERWORKTELEPHONE"]).strip()
                mobilephone = utils.nulltostr(
                    an["CURRENTOWNERMOBILETELEPHONE"]).strip()
                if email == "" and homephone == "" and workphone == "" and mobilephone == "":
                    self.logError(
                        "No email address or phone number for owner, skipping."
                    )
                    continue

                # If there's no phone, we can't set the chip password so skip it
                if homephone == "" and workphone == "" and mobilephone == "":
                    self.logError("No phone number for owner, skipping.")
                    continue

                # Get the phone number and strip it of non-numeric data
                phone = homephone or mobilephone or workphone
                phone = "".join(c for c in phone if c.isdigit())

                # If we don't have an email address, use [email protected]
                if email == "":
                    email = "*****@*****.**" % phone

                # Software
                line.append("\"ASM\"")
                # TransactionType
                line.append(
                    "\"%s\"" %
                    (self.getLastPublishedDate(an["ID"]) is None and 'N'
                     or 'T'))
                # MicrochipID
                line.append("\"%s\"" % (an["IDENTICHIPNUMBER"]))
                # FirstName
                line.append("\"%s\"" % (an["CURRENTOWNERFORENAMES"]))
                # LastName
                line.append("\"%s\"" % (an["CURRENTOWNERSURNAME"]))
                # Address
                line.append("\"%s\"" % (an["CURRENTOWNERADDRESS"]))
                # City
                line.append("\"%s\"" % (an["CURRENTOWNERTOWN"]))
                # State
                line.append("\"%s\"" % (an["CURRENTOWNERCOUNTY"]))
                # ZipCode
                line.append("\"%s\"" % (an["CURRENTOWNERPOSTCODE"]))
                # Country
                line.append("\"USA\"")
                # Phone1
                line.append("\"%s\"" % (an["CURRENTOWNERHOMETELEPHONE"]))
                # Phone2
                line.append("\"%s\"" % (an["CURRENTOWNERWORKTELEPHONE"]))
                # Phone3
                line.append("\"%s\"" % (an["CURRENTOWNERMOBILETELEPHONE"]))
                # Email (mandatory)
                line.append("\"%s\"" % (email))
                # Chip Password (stripped phone number)
                line.append("\"%s\"" % phone)
                # Date_of_Implant (yy-mm-dd)
                line.append("\"%s\"" %
                            i18n.format_date("%y-%m-%d", an["IDENTICHIPDATE"]))
                # PetName
                line.append("\"%s\"" % an["ANIMALNAME"])
                # Species
                line.append("\"%s\"" % an["SPECIESNAME"])
                # Breed (or "Mixed Breed" for crossbreeds, Other for animals not cats and dogs)
                line.append("\"%s\"" % self.plBreed(
                    an["BREEDNAME1"], an["SPECIESNAME"], an["CROSSBREED"]))
                # Gender
                line.append("\"%s\"" % an["SEXNAME"])
                # Spayed_Neutered (y or n)
                line.append("\"%s\"" % self.plYesNo(an["NEUTERED"]))
                # ColorMarkings (our BaseColour field)
                line.append("\"%s\"" % an["BASECOLOURNAME"])
                # Add to our data file.
                csv.append(",".join(line))
                # Remember we included this one
                processed_animals.append(an)
                # 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())

        # If we excluded our only animals and have nothing to send, stop now
        if len(csv) == 1:
            self.log("No animals left to send to PetLink.")
            self.saveLog()
            self.setPublisherComplete()
            return

        # POST the csv data
        headers = {
            "Authorization":
            "Basic %s" % base64.b64encode("%s:%s" % (plemail, password)),
            "Content-Type":
            "text/csv"
        }
        self.log("Uploading data file (%d csv lines) to %s..." %
                 (len(csv), UPLOAD_URL))
        try:
            r = utils.post_data(UPLOAD_URL, "\n".join(csv), headers=headers)
            response = r["response"].decode("utf-8").encode(
                "ascii", "xmlcharrefreplace")

            self.log("req hdr: %s, \nreq data: %s" %
                     (r["requestheaders"], r["requestbody"]))
            self.log("resp hdr: %s, \nresp body: %s" %
                     (r["headers"], response))

            jresp = utils.json_parse(response)

            # Look for remote exceptions
            if "exception" in jresp and jresp["exception"] != "":
                self.successes = 0
                self.logError(
                    "PetLink remote exception received, abandoning: %s" %
                    jresp["exception"])
                self.saveLog()
                self.setPublisherComplete()
                return

            # Parse any errors in the JSON response
            for e in jresp["errors"]:
                chip = ""
                message = ""
                try:
                    # Prefer microchip= in location column, then fall back to id=/microchip= in column
                    if e["location"].find("microchip=") != -1:
                        chip = e["location"]
                        chip = chip[chip.find("microchip=") + 10:]
                    elif e["column"].find("id=") != -1:
                        chip = e["column"].replace("id=", "")
                    elif e["column"].find("microchip=") != -1:
                        chip = e["column"].replace("microchip=", "")
                    message = e["message"]
                except Exception as erj:
                    try:
                        self.logError(
                            "Failed unpacking error message (message=%s) from '%s'"
                            % (erj, e))
                    except:
                        self.logError(
                            "Failed decoding error message from PetLink")
                    continue

                # Iterate over a copy of the processed list so we can remove animals from it
                # that have error emssages.
                for an in processed_animals[:]:

                    if an["IDENTICHIPNUMBER"] == chip:
                        processed_animals.remove(an)
                        try:
                            self.logError("%s: %s (%s) - Received error message from PetLink: %s" % \
                                (an["SHELTERCODE"], an["ANIMALNAME"], an["IDENTICHIPNUMBER"], message))
                        except Exception as erm:
                            self.logError("%s: %s (%s) - Error decoding message from PetLink" % \
                                (an["SHELTERCODE"], an["ANIMALNAME"], an["IDENTICHIPNUMBER"]))
                            continue

                        # If the message was that the chip is already registered,
                        # mark this animal as published but on the intake date -
                        # this will force this publisher to put it through as a transfer
                        # next time since we'll find a previous published record.
                        if message.find("has already been registered") != -1:
                            self.markAnimalPublished(an["ID"],
                                                     an["DATEBROUGHTIN"])
                            self.log("%s: %s (%s) - Already registered, marking as PetLink TRANSFER for next publish" % \
                                (an["SHELTERCODE"], an["ANIMALNAME"], an["IDENTICHIPNUMBER"]))
                            continue

                        # If the message is one of PetLink's permanent failure conditons,
                        # mark the chip failed so that we stop trying.
                        # Any other error message we treat as transient and do nothing
                        # (which means we'll attempt to register the chip the next time this publisher is run).
                        PERMANENT_FAILURES = [
                            "has an existing PetLink account and their contact information is already on file",
                            "Not a prepaid microchip",
                            "This is a Found Animals Registry chip",
                            "cannot be transferred - the account is locked.",
                            "Microchip number has already been registered in the database"
                        ]
                        for m in PERMANENT_FAILURES:
                            if message.find(m) != -1:
                                an["FAILMESSAGE"] = message
                                failed_animals.append(an)

            if len(processed_animals) > 0:
                self.markAnimalsPublished(processed_animals)

            if len(failed_animals) > 0:
                self.markAnimalsPublishFailed(failed_animals)

        except Exception as err:
            self.logError("Failed uploading data file: %s" % err)

        self.saveLog()
        self.setPublisherComplete()
コード例 #23
0
ファイル: movement.py プロジェクト: tgage/asm3
def insert_adoption_from_form(dbo, username, post, creating = [], create_payments = True):
    """
    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.
    create_payments is True if we should create payments - don't do this
    for bonded animals or we'll double up all the payments.
    """
    l = dbo.locale
    # Validate that we have a movement date before doing anthing
    if None is post.date("movementdate"):
        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, post.integer("animal"))
    if a is None:
        raise utils.ASMValidationError("Adoption POST has an invalid animal ID: %d" % post.integer("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. We only do this if
    # the other animals are still on shelter (therefore alive).
    if a.BONDEDANIMALID is not None and a.BONDEDANIMALID != 0 and a.BONDEDANIMAL1ARCHIVED == 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(post.data)
        newdata["animal"] = str(a.BONDEDANIMALID)
        insert_adoption_from_form(dbo, username, utils.PostedData(newdata, dbo.locale), creating, create_payments = False)
    if a.BONDEDANIMAL2ID is not None and a.BONDEDANIMAL2ID != 0 and a.BONDEDANIMAL2ARCHIVED == 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(post.data)
        newdata["animal"] = str(a.BONDEDANIMAL2ID)
        insert_adoption_from_form(dbo, username, utils.PostedData(newdata, dbo.locale), creating, create_payments = False)
    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"                : post["person"],
        "animal"                : post["animal"],
        "adoptionno"            : post["movementnumber"],
        "movementdate"          : post["movementdate"],
        "type"                  : str(ADOPTION),
        "donation"              : post["amount"],
        "insurance"             : post["insurance"],
        "returncategory"        : configuration.default_return_reason(dbo),
        "trial"                 : post["trial"],
        "trialenddate"          : post["trialenddate"]
    }
    # Is this animal currently on foster? If so, return the foster
    fm = get_animal_movements(dbo, post.integer("animal"))
    for m in fm:
        if m.MOVEMENTTYPE == FOSTER and m.RETURNDATE is None:
            return_movement(dbo, m["ID"], post.integer("animal"), post.date("movementdate"))
    # 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, post.integer("animal"), post.date("movementdate"))
            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 post.boolean("homechecked") == 1:
        dbo.update("owner", post.integer("person"), { "IDCheck": 1, "DateLastHomeChecked": dbo.today() }, username)
    # If the animal was flagged as not available for adoption, then it
    # shouldn't be since we've just adopted it.
    dbo.update("animal", a.ID, { "IsNotAvailableForAdoption": 0 })
    # 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 == post.integer("animal") \
            and m.OWNERID == post.integer("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
            dbo.update("adoption", m.ID, { "ReservationCancelledDate": post.date("movementdate") }, username)
    if movementid != 0:
        update_movement_from_form(dbo, username, utils.PostedData(move_dict, l))
    else:
        movementid = insert_movement_from_form(dbo, username, utils.PostedData(move_dict, l))
    # Create any payments
    if create_payments:
        financial.insert_donations_from_form(dbo, username, post, post["movementdate"], False, post["person"], post["animal"], movementid) 
    # Then any boarding cost record
    cost_amount = post.integer("costamount")
    cost_type = post["costtype"]
    cost_create = post.integer("costcreate")
    if cost_amount > 0 and cost_type != "" and cost_create == 1:
        boc_dict = {
            "animalid"          : post["animal"],
            "type"              : cost_type,
            "costdate"          : post["movementdate"],
            "costpaid"          : post["movementdate"],
            "cost"              : post["costamount"]
        }
        animal.insert_cost_from_form(dbo, username, utils.PostedData(boc_dict, l))
    return movementid