Changeset - f1214a3c932b
[Not reviewed]
0 1 4
Brett Smith (brett) - 4 years ago 2017-09-22 14:44:52
brett@sfconservancy.org
projects: Add Policies section with travel policy.
5 files changed with 1017 insertions and 1 deletions:
0 comments (0 inline, 0 general)
www/conservancy/static/projects/policies/conservancy-travel-policy.783dcdd92fc61f3f150e1c65782c0fe527c8ff52.html
Show inline comments
 
new file 100644
 
{% extends "base_projects.html" %}
 
{% block subtitle %}Travel and Reimburseable Expense Policy - {% endblock %}
 
{% block submenuselection %}Policies{% endblock %}
 
{% block content %}
 

	
 
<h1 id="software-freedom-conservancy-travel-and-reimbursable-expense-policy">Software Freedom Conservancy Travel and Reimbursable Expense Policy</h1>
 
<h2 id="overview">Overview</h2>
 
<p>This Travel and Reimbursable Expense Policy (&ldquo;Policy&rdquo;) applies to all
 
Conservancy Member Projects (&ldquo;Projects&rdquo;) of Software Freedom Conservancy
 
(&ldquo;Conservancy&rdquo;) and has been created to memorialize Conservancy&rsquo;s
 
reimbursement policies relating to travel and other business expenses
 
incurred by Conservancy staff, Project Leadership Committee (&ldquo;PLC&rdquo;)
 
members, and project volunteers while engaged in business on behalf of, or
 
at the behest of Conservancy and/or a Project (&ldquo;Travelers&rdquo;).</p>
 
<p>This Policy includes an Easy Reference Guide that can be used as a
 
template for most of the travel covered under this Policy.  When in doubt,
 
refer to the more detailed sections below.</p>
 
<h2 id="purpose">Purpose</h2>
 
<p>Conservancy must maintain effective control of business-related expenses
 
in order to maintain its financial viability and tax exempt status.
 
Conservancy and each Project is also accountable to our donors to ensure
 
that we manage their contributions wisely and maximize our ability to
 
pursue our charitable mission.  As such, Conservancy expects Travelers to
 
use good judgment and to claim reimbursement for only those expenses that
 
are necessary and reasonable.  Excessive expenses, including but not
 
limited to luxury accommodations and services unnecessary for, or unrelated
 
to the furtherance of Conservancy&rsquo;s charitable mission are not eligible for
 
reimbursement.</p>
 
<p>Any travel expense that adheres to this Policy is considered In-Policy
 
and does not require special approval, so long as the trip itself
 
has been approved in writing by Conservancy&rsquo;s Executive Director or
 
by a Project&rsquo;s Leadership Committee (&ldquo;PLC&rdquo;) in a regular and documented
 
PLC vote.  Conservancy and/or a PLC can limit allowable travel expenses
 
to an amount less than what would otherwise be considered acceptable
 
according to this Policy. If so, the smaller budget is the maximum
 
allowed expense.</p>
 
<p>PLC&rsquo;s may, in fact, have their own travel policy that is more restrictive
 
than this one.  Please consult the PLC for your Conservancy project before
 
incurring an expenses to ensure you understand what expenses can be
 
reimbursed.</p>
 
<h2 id="easy-reference-guide">Easy Reference Guide</h2>
 
<p>Travelers should adhere to the following guidelines to stay In-Policy.</p>
 
<h3 id="flights">Flights</h3>
 
<ul>
 
<li>
 
<p>Before you buy tickets, save a screenshot of a flight search that
 
  shows the least expensive fare available from multiple airlines for
 
  the dates you need to travel.</p>
 
</li>
 
<li>
 
<p>Book at least 14 days in advance.</p>
 
</li>
 
<li>
 
<p>Fares within $100 of that lowest fare you found are In-Policy, even if
 
  you book on a different site or for different dates.</p>
 
</li>
 
<li>
 
<p>Fares over $750 domestically or $1,650 internationally require
 
  Conservancy&rsquo;s pre-approval.</p>
 
</li>
 
</ul>
 
<h3 id="hotels">Hotels</h3>
 
<ul>
 
<li>
 
<p>Hotels are In-Policy as long as the average nightly rate you pay
 
  (excluding taxes and fees) is under the maximum rate for lodging for your
 
  destination.  See the &ldquo;Rates&rdquo; section below for details.</p>
 
</li>
 
<li>
 
<p>Be sure the receipt from your hotel includes the dates of your
 
  stay, not just a total.</p>
 
</li>
 
</ul>
 
<h3 id="receipts">Receipts</h3>
 
<p>Keep and submit PDFs of the following, as applicable:</p>
 
<ul>
 
<li>
 
<p>Your fare search (i.e., a screen shot)</p>
 
</li>
 
<li>
 
<p>Your plane and rail tickets (e-confirmation of purchase is sufficient)</p>
 
</li>
 
<li>
 
<p>Your hotel/lodging invoice</p>
 
</li>
 
</ul>
 
<h3 id="per-diem">Per Diem</h3>
 
<ul>
 
<li>
 
<p>Use your per diem to cover meals and incidental expenses.</p>
 
</li>
 
<li>
 
<p>Your total per diem allowance follows the rates published for your
 
  destination.  See the &ldquo;Rates&rdquo; section below for details.</p>
 
</li>
 
<li>
 
<p>Try to be frugal: per diem rates are rather generous.</p>
 
</li>
 
<li>
 
<p>When attending a conference where food is included, Do The Right
 
  Thing and claim a lower per diem.</p>
 
</li>
 
</ul>
 
<h3 id="reimbursement">Reimbursement</h3>
 
<ul>
 
<li>
 
<p>To receive reimbursement, send transportation and hotel receipts,
 
  along with a list of per diem days and totals, to
 
  <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#97;&#99;&#99;&#111;&#117;&#110;&#116;&#105;&#110;&#103;&#64;&#115;&#102;&#99;&#111;&#110;&#115;&#101;&#114;&#118;&#97;&#110;&#99;&#121;&#46;&#111;&#114;&#103;">&#97;&#99;&#99;&#111;&#117;&#110;&#116;&#105;&#110;&#103;&#64;&#115;&#102;&#99;&#111;&#110;&#115;&#101;&#114;&#118;&#97;&#110;&#99;&#121;&#46;&#111;&#114;&#103;</a>.  Refer to the Expense Report
 
  section below for details.</p>
 
</li>
 
<li>
 
<p>Your complete reimbursement request must be submitted to
 
  <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#97;&#99;&#99;&#111;&#117;&#110;&#116;&#105;&#110;&#103;&#64;&#115;&#102;&#99;&#111;&#110;&#115;&#101;&#114;&#118;&#97;&#110;&#99;&#121;&#46;&#111;&#114;&#103;">&#97;&#99;&#99;&#111;&#117;&#110;&#116;&#105;&#110;&#103;&#64;&#115;&#102;&#99;&#111;&#110;&#115;&#101;&#114;&#118;&#97;&#110;&#99;&#121;&#46;&#111;&#114;&#103;</a> within 90 days of the last date of
 
  travel.  Untimely requests <strong>will not be reimbursed</strong>.</p>
 
</li>
 
</ul>
 
<h2 id="rates">Rates</h2>
 
<p>Throughout this document, we refer to rates reported by other parties.</p>
 
<p>For travel in the United States, we follow the maximum rates for lodging and
 
M&amp;IE per diem set by the
 
<a href="https://www.gsa.gov/perdiem">US General Services Administration</a>.</p>
 
<p>For travel outside the United States, we follow the maximum rates for lodging and
 
M&amp;IE per diem set by the
 
<a href="https://aoprals.state.gov/web920/per_diem.asp">US Department of State</a>.</p>
 
<p>We calculate the total per diem allowance for a trip using the same method
 
as the GSA.  Travelers may request up to 100% of the listed rate for each
 
full day of travel, plus 75% of the listed rate for each partial day of
 
travel.  For example, if you fly to a conference on Monday, spend Tuesday
 
through Thursday at the conference, and return home on Friday, and the per
 
diem rate for the conference city is $80, you may request up to $360: $80
 
for each day Tuesday through Thursday, plus $60 for each day you flew.</p>
 
<p>When we convert currencies (e.g., to determine whether a hotel paid in Euros
 
was within the maximum lodging rate), we use the final rate published by
 
<a href="https://openexchangerates.org/">Open Exchange Rates</a> on the date we received
 
the reimbursement request.  Please do not do your own currency conversions
 
in your reimbursement requests.  Simply report expenses in their original
 
currency/ies, and we will convert appropriately.  If you have questions or
 
concerns about our rates, just ask, and we&rsquo;ll be happy to provide details
 
before we send you final payment.</p>
 
<h2 id="reimbursement-procedure">Reimbursement Procedure</h2>
 
<p>Conservancy handles reimbursements on a NET-30 basis, starting from the date
 
that complete materials are received.  If this is an issue, Conservancy is
 
available to prepurchase expensive items like airline tickets on your
 
behalf, so that you don&rsquo;t need to be reimbursed.</p>
 
<p>If you seek to be reimbursed for Conservancy Project expenses, please send
 
the following, in a self contained email (with attachments as necessary),
 
cc&rsquo;ing your Project Leadership Committee address (PROJECT@sfconservancy.org)
 
for Project approval:</p>
 
<ul>
 
<li>
 
<p>A brief paragraph explaining what was accomplished for the project
 
  during your travel and/or with the funds being reimbursed.  This can
 
  be informal; it&rsquo;s just for our records to confirm the travel advanced
 
  the not-for-profit mission of both Conservancy and the project.</p>
 
</li>
 
<li>
 
<p>A brief report listing the items to be reimbursed.</p>
 
</li>
 
<li>
 
<p>Full receipt(s) for everything, unless the travel policy does not
 
  require receipts (e.g., for per diem expenses).</p>
 
</li>
 
</ul>
 
<p>If your receipts are in a different currency than your preferred one
 
  for reimbursement, include documentation of the rate conversion (e.g., a
 
  redacted credit card statement in your preferred currency).  Otherwise,
 
  Conservancy will use the prevailing rate for the date of the expense for
 
  conversion.</p>
 
<p>Please verify that the receipts that you submit are within the attached
 
  travel policy requirements.  Note, however, that your Project Leadership
 
  Committee may have set a stricter budget than what the general
 
  Conservancy policy allows.</p>
 
<ul>
 
<li>
 
<p>How you&rsquo;d liked to be reimbursed. The four payment options, in order of
 
  Conservancy&rsquo;s preference, are:</p>
 
</li>
 
<li>
 
<p>PayPal.  For this, we need (a) the email address that is registered to
 
    the PayPal account that will receive reimbursement and (b) the preferred
 
    currency.  (Please verify that PayPal supports transactions in
 
    <a href="https://www.paypal.com/cgi-bin/webscr?cmd=p/sell/mc/mc_intro-outside">your preferred currency before choosing one</a>.)
 
    Note that sometimes PayPal charges fees.  Usually we&rsquo;re taking funds
 
    from our PayPal balance, which means no fees appear on our side, but
 
    they may appear on yours.  In our experience, USA PayPal account holders
 
    physically in the USA are not typically charged fees; but we do advise
 
    you to check PayPal&rsquo;s fee schedule before choosing this method.</p>
 
<p>NOTE: Typically, when choosing PayPal as a payment option, amounts owed
 
        in USD will be paid in USD, regardless of your preferred currency
 
        selection.</p>
 
</li>
 
<li>
 
<p>Issue you a check in USD from a USA bank, sent to you via post.
 
    For this option, I just need your postal address.</p>
 
</li>
 
<li>
 
<p>Wire the amount in your local currency to your bank account in your
 
    country.  For this option, I need as much of the following information
 
    as it&rsquo;s possible for you to collect.</p>
 
<p><strong>Required information</strong></p>
 
<ul>
 
<li>
 
<p>Full Name of the Account Holder</p>
 
</li>
 
<li>
 
<p>Full Address of the Account Holder</p>
 
</li>
 
<li>
 
<p>Account Number</p>
 
</li>
 
<li>
 
<p>Preferred Currency</p>
 
</li>
 
<li>
 
<p>Bank Name</p>
 
</li>
 
<li>
 
<p>Bank Address</p>
 
</li>
 
<li>
 
<p>Bank ACH or ABA routing number (for banks in the US);
 
    or SWIFT and/or BIC code (for banks outside the US)</p>
 
</li>
 
</ul>
 
<p><strong>Additional required information by country</strong></p>
 
<ul>
 
<li>
 
<p>All countries inside the EU: IBAN</p>
 
</li>
 
<li>
 
<p>Australia: BSB or &ldquo;Bank Code&rdquo;</p>
 
</li>
 
<li>
 
<p>Brazil: IABN; Tax ID of the Account Holder (your 14-digit CNPJ
 
      or 11-digit CPF); Phone Number of the Account Holder;
 
      and Bank Agency Code</p>
 
</li>
 
<li>
 
<p>Colombia: Tax ID of the Account Holder; and Phone Number
 
      of the Account Holder</p>
 
</li>
 
<li>
 
<p>India: IFSC Code</p>
 
</li>
 
<li>
 
<p>Kenya: The name of the local branch of your bank where you hold your
 
      account</p>
 
</li>
 
<li>
 
<p>Qatar: IBAN</p>
 
</li>
 
<li>
 
<p>Russian Federation: Beneficiary INN; Patronymic Name of Beneficiary;
 
      and VAT/VO Code of Beneficiary Bank</p>
 
</li>
 
<li>
 
<p>Ukraine: BSB or &ldquo;Bank Code&rdquo;; Tax ID of the Account Holder;
 
      and Phone Number of the Account Holder</p>
 
</li>
 
<li>
 
<p>United States: Phone Number of the Account Holder</p>
 
</li>
 
</ul>
 
<p><strong>Additional information we can use</strong></p>
 
<p>Banks outside the US will often designate a Correspondent Bank when
 
  receiving funds from the US.  If you can give us the Correspondent
 
  Bank Name and ACH, we can specify that in the wire.  Your bank will
 
  usually take the fewest fees when receiving wires from its
 
  Correspondent Bank, so this will mean the most money for you.</p>
 
</li>
 
<li>
 
<p>A check in your local currency, sent to you via post. For this option, we
 
    just need your postal address and what currency you want. Note that this
 
    is a more involved option to process and will usually take at least 30
 
    days to issue payment.  We do not recommend this method.  Please choose
 
    it only if you absolutely cannot receive a wire transfer for some reason.</p>
 
</li>
 
</ul>
 
<p>Project Leadership Committees: when you see emails of this nature, please
 
be sure to have your designated Representative review the materials and
 
send an approval message to Conservancy.</p>
 
<h2 id="project-leadership-committee-review">Project Leadership Committee Review</h2>
 
<p>Conservancy foresees the need for periodic reasonable exceptions to
 
this Policy.  Persons working on behalf of a specific Project seeking
 
an exception to this Policy must petition their PLC to obtain written
 
approval from Conservancy authorizing the exception.  Persons working
 
directly on behalf of Conservancy seeking an exception to the
 
Policy must obtain written approval from Conservancy authorizing the
 
exception.</p>
 
<p>PLCs are responsible for creating procedures for requesting exceptions,
 
and submitting to Conservancy reimbursement requests associated with
 
their respective Projects.  PLCs are also responsible for making available
 
a list of required response times for inquiries, including but not
 
limited to, the following two cases</p>
 
<ul>
 
<li>
 
<p>a specific number of days to respond to regular reimbursement requests,
 
and</p>
 
</li>
 
<li>
 
<p>a specific number of days to respond to pre-authorization requests.</p>
 
</li>
 
</ul>
 
<p>PLCs are also responsible for monitoring the available balance in their
 
Project Fund, and for granting or refusing approval for travel expense
 
requests based on an assessment of the funds available and of any
 
outstanding contracts payable.  PLCs are not to approve travel expense
 
requests when their Project does not have sufficient funds to cover the
 
expense.  If a PLC has any questions regarding whether their Project has
 
sufficient funds to cover a Traveler&rsquo;s expense request, the PLC should
 
contact Conservancy.</p>
 
<h2 id="transportation">Transportation</h2>
 
<h3 id="overall-transportation-cost">Overall transportation Cost</h3>
 
<p>Domestic transportation costs greater than US$750 requires Conservancy
 
approval prior to booking, even if all other Policy conditions have been
 
met.  International transportation costs greater than US$1,800 requires
 
Conservancy approval prior to booking, even if all other Policy conditions
 
have been met.</p>
 
<h3 id="advance-purchase">Advance Purchase</h3>
 
<p>Tickets for travel by air or rail (excluding commuter train and subway)
 
should be booked at least 14 days in advance; any travel booked less than
 
14 days in advance requires written pre-authorization by Conservancy.
 
Tickets for travel by air or rail beyond 365 days in advance also require
 
written pre-authorization by Conservancy.</p>
 
<h3 id="air-travel">Air Travel</h3>
 
<h4 id="class-of-service">Class of Service</h4>
 
<p>Coach and/or Economy Airfare is the only acceptable class for all flights
 
(domestic and international) unless a PLC provides a special exception and
 
a valid reason (such as a need for business class due to a documented
 
medical reason) to Conservancy for written approval.  Travelers may select
 
their airline of choice (e.g., for the purpose of collecting airline miles
 
and rewards), provided that the resulting fare otherwise meets the
 
requirements of this Policy.  Travelers should not book out-of-Policy trips
 
(and thus pay a higher fare) in order to qualify for a mileage upgrade.</p>
 
<h4 id="advance-purchase_1">Advance Purchase</h4>
 
<p>Air travel should be booked at least 14 days in advance; any travel booked
 
less than 14 days in advance requires written pre-authorization by
 
Conservancy.  Flights beyond 365 days in advance also require written
 
pre-authorization by Conservancy.</p>
 
<h4 id="low-fare">Low Fare</h4>
 
<p>Conservancy aims to balance cost savings with time savings and convenience.
 
Budgets for flights are set based on their travel time compared to the
 
flight with the lowest available fare.  Flights with fares that are within
 
budget are in-Policy.</p>
 
<p>To find the lowest available fare, run a flight search that meets these
 
criteria, and save the results:</p>
 
<ul>
 
<li>
 
<p>The search must include fares from multiple airlines.  Any
 
  widely-recognized airfare search site that lists results from multiple
 
  airlines is acceptable, including sites such as
 
  <a href="http://orbitz.com">Orbitz</a>, <a href="http://kayak.com">Kayak</a> or
 
  <a href="http://hipmunk.com/">Hipmunk</a>.</p>
 
</li>
 
<li>
 
<p>The search must cover only the dates of relevant travel.  For example, if
 
  you&rsquo;re attending a conference that runs Monday through Friday, the search
 
  must have you arriving no earlier than Sunday, and leaving no later than
 
  Saturday.</p>
 
</li>
 
<li>
 
<p>Except as allowed by Policy, the search must not use filters that might
 
  exclude the least expensive fare.  For example, you may filter out
 
  flights with two or more connections, since Conservancy does not
 
  consider those reasonable.  However, you may not filter out specific
 
  airlines, or flights without WiFi.</p>
 
</li>
 
</ul>
 
<p>Save the results of this search.  A PDF printout of the first page of
 
results from your browser is ideal.  A screenshot can work too.  Just make
 
sure the output shows the search criteria and the lowest available fare.
 
When you send your reimbursement request, attach these results.</p>
 
<p>The budget for a flight is set depending on how its cost and travel time
 
compares to the flight with the lowest available fare.  Travel time is
 
measured from the scheduled departure time of the first flight in the
 
itinerary to the scheduled landing time of the final flight.  We use the
 
following table to determine the budget:</p>
 
<table>
 
<thead>
 
<tr>
 
<th>If the travel time for a flight is…</th>
 
<th>the budget for that flight is…</th>
 
</tr>
 
</thead>
 
<tbody>
 
<tr>
 
<td>the same or longer than the flight with the lowest available fare</td>
 
<td>the lowest available fare + US$100</td>
 
</tr>
 
<tr>
 
<td>less than three hours shorter</td>
 
<td>the lowest available fare + US$100</td>
 
</tr>
 
<tr>
 
<td>between three and six hours shorter</td>
 
<td>the lowest available fare + US$200</td>
 
</tr>
 
<tr>
 
<td>between six and ten hours shorter</td>
 
<td>the lowest available fare + US$350</td>
 
</tr>
 
<tr>
 
<td>at least ten hours shorter</td>
 
<td>the lowest available fare + US$600</td>
 
</tr>
 
</tbody>
 
</table>
 
<p>Any flight with a total cost that is within its corresponding budget is
 
within Policy.  Any flight with a cost over its budget requires written
 
pre-authorization by Conservancy.</p>
 
<p>Travelers may book their tickets on different dates or a different site as
 
long as they used a qualifying fare search site to determine that the
 
booked flights are within Policy.</p>
 
<h4 id="reasonable-flights">Reasonable Flights</h4>
 
<p>Conservancy asks that Travelers allow for flexibility with respect
 
to departure times during a desired day of travel, as well as longer
 
trips in order to reduce cost.  However, Conservancy does consider
 
flights with two or more connections as unreasonable and does not
 
expect Travelers to consider those flight options to be reasonable.</p>
 
<h4 id="excess-baggage">Excess Baggage</h4>
 
<p>Should a team member travel on an airline that charges for a single piece of
 
checked baggage, such a baggage expense is eligible for reimbursement with a
 
receipt.  Team members are responsible for charges on any baggage beyond a
 
single piece, unless that additional baggage is materials specifically
 
related to the Project&rsquo;s and Conservancy&rsquo;s mission (i.e., bringing t-shirts
 
and other promotional materials to an event).</p>
 
<h4 id="out-of-policy-bookings">Out-of-Policy Bookings</h4>
 
<p>All air travel not adhering to the above Policies are considered Out-of-Policy
 
and require written pre-authorization by an officer of Conservancy.</p>
 
<h4 id="cancellation-fees">Cancellation Fees</h4>
 
<p>Cancellation fees and other penalties incurred result of a change
 
of plans are reimbursable at Conservancy&rsquo;s discretion.  In general,
 
Conservancy shall reimburse such fees if the Traveler can submit a
 
valid reason for the change of plans.  Acceptable reasons include Conservancy
 
and/or the PLC canceling or altering the trip or unexpected delays
 
in flight connections.  In instances where these fees are incurred
 
without adequate explanation, Conservancy reserves the right to refuse
 
to reimburse the cost of the fees.</p>
 
<h3 id="other-transportation">Other Transportation</h3>
 
<h4 id="ground-transportation">Ground Transportation</h4>
 
<p>Ground transportation necessary as part of authorized Project trips
 
is considered to be a reasonable expense.   Public ground transportation,
 
such as taxis, shuttles, buses and municipal transit, are generally
 
the most cost-effective options and are the standard for eligible
 
ground transportation reimbursements.  All car rentals require pre-authorization
 
by the PLC or by an officer of Conservancy.  When car rentals
 
have been pre-approved, the rental of compact cars is encouraged;
 
mid-size vehicles are authorized when necessary (e.g., when compact-sized
 
vehicles are not available or the number of passengers or volume of
 
baggage makes a compact vehicle impractical).</p>
 
<h4 id="rail-transportation">Rail Transportation</h4>
 
<p>Rail transportation as a means of travel for an authorized Project
 
trip is considered to be a reasonable expense.  All rail transportation
 
must be in economy and/or coach class.</p>
 
<h4 id="use-of-personal-vehicles">Use of Personal Vehicles</h4>
 
<p>When circumstances require Travelers to utilize their personal vehicles for
 
Project purposes, they can be reimbursed at the current
 
<a href="https://www.irs.gov/tax-professionals/standard-mileage-rates/">USA IRS Standard Mileage Rate</a>,
 
plus any related parking expenses and toll fees.  Drivers are encouraged to
 
find the lowest cost parking area reasonably near their destination.</p>
 
<h2 id="additional-days-of-travel">Additional Days of Travel</h2>
 
<p>Travelers often seek to add extra days before or after an approved trip
 
(e.g., the weekend before a conference). A Traveler may seek approval for
 
the expenses associated with an extended stay prior to booking the trip,
 
provided that the additional days are solely to enable a Traveler to
 
conduct work within the PLC&rsquo;s objectives and Conservancy&rsquo;s charitable
 
mission, or to get a particular airfare that <strong>reduces</strong> the overall cost of
 
the trip.  Travelers may seek approval to book travel itineraries that
 
include extra days for personal reasons, so long as the cost of the flight
 
meets the other requirements of this Policy.  Other expenses incurred
 
during extra personal days beyond transportation costs are not reimbursable.</p>
 
<h2 id="lodging">Lodging</h2>
 
<p>Travelers are expected to be cost-conscious and prudent when booking lodging
 
for approved trips, and to verify that rates are within the maximum lodging
 
rates for the hotel&rsquo;s location.  See the &ldquo;Rates&rdquo; section above for details.</p>
 
<p>If the lodging chosen by the Traveler and/or the PLC exceeds the maximum
 
lodging rate for the given location (per Traveler), the Traveler and/or the
 
PLC <strong>must</strong> obtain written pre-approval from Conservancy and the PLC before
 
booking the hotel.  If written pre-approval is not sought or is not granted,
 
Conservancy will only reimburse up to the maximum lodging rate.</p>
 
<p>Lodging documentation submitted as part of a reimbursement request must
 
include a copy of the hotel invoice detailing all charges (credit card
 
receipts <strong>alone</strong> are unacceptable).  In particular, since Conservancy only
 
reimburses for room charges (plus relevant taxes and fees) for the necessary
 
travel dates, the receipt from the hotel must clearly show the dates of stay,
 
and separately list room charges and any food or service charges.
 
Conservancy will not reimburse Travelers for any costs associated with an
 
upgrade of room accommodations.</p>
 
<p>In some cases, Conservancy, upon consultation with the PLC, may decide to
 
book lodging on behalf of Travelers.  In this case, Conservancy-booked
 
lodging is always considered In-Policy.</p>
 
<h2 id="other-reimbursable-expenses">Other Reimbursable Expenses</h2>
 
<p>Conservancy will reimburse persons for Project-related expenses that
 
are incurred while traveling on approved Project business and/or approved
 
Conservancy business. Only necessary, ordinary and reasonable expenses
 
are eligible for reimbursement, and only those categories of expenses
 
listed in this document qualify.</p>
 
<h3 id="meals-and-incidental-expenses">Meals and Incidental Expenses</h3>
 
<h4 id="overview_1">Overview</h4>
 
<p>Travelers can submit for a per diem for meals and incidental expenses for
 
every day of a trip devoted to Project- and/or Conservancy-related mission
 
work, including the day(s) of travel itself, up to the maximum rate for the
 
destination of the trip.  See the &ldquo;Rates&rdquo; section above for details.</p>
 
<p>These per diem rates are the maximum daily rate Travelers can claim.  If a
 
conference has provided food, or food is provided in some other form, or
 
the costs the Traveler incurs are lower than this rate, then the Traveler
 
should reasonably reduce their per diem claim.</p>
 
<p>PLCs and/or Conservancy have the authority to set lower per diem rates
 
than those generated by the calculators above.  In those instances,
 
Travelers will only be able to submit for the lower per diem rates.</p>
 
<h4 id="group-meals">Group Meals</h4>
 
<p>For groups of Travelers on an In-Policy trip, each Traveler should
 
pay for his/her own meals, seeing as all participants will have an
 
opportunity to submit for separate per diem reimbursements after the trip.</p>
 
<p>For clarification purposes, this Policy does not relate to planned
 
group events that include meals and/or refreshments (e.g., a PLC-organized
 
conference that includes lunch for all attendees).  Further, PLCs and/or
 
Conservancy retain the right to allocate a separate budget for anticipated
 
large group meals beyond the individual per diem limits of each Traveler,
 
provided that they are within the PLC&rsquo;s technical objectives and/or
 
Conservancy&rsquo;s mission.  Travelers anticipating a need to cover such
 
a large group meal should seek pre-approval from his/her PLC and/or Conservancy
 
for such expenses before the trip.</p>
 
<p>For any such group meal, Conservancy will require a written paragraph
 
summary of the meeting, indicating what was accomplished for the Project&rsquo;s
 
and Conservancy&rsquo;s mission.</p>
 
<h4 id="meals-for-organizational-development">Meals For Organizational Development</h4>
 
<p>Travelers may occasionally have the need to invite third parties
 
(e.g., prospective donors, contributors, community members, etc.) to
 
meals in order to further a PLC&rsquo;s technical direction and/or Conservancy&rsquo;s
 
mission.  Conservancy recommends that Travelers seek pre-approval from
 
their PLC and/or Conservancy for such meals.</p>
 
<p>For any such organizational development meal, Conservancy will require a
 
written paragraph summary of the meeting, indicating what was accomplished
 
for the Project&rsquo;s and Conservancy&rsquo;s mission.</p>
 
<h4 id="phone-call-charges-part-of-per-diem">Phone Call Charges Part of Per Diem</h4>
 
<p>Charges for personal phone calls (e.g., made from a hotel, or via
 
a mobile phone in international travel) are not reimbursable as an
 
expense separate from the allocated per diem.</p>
 
<h4 id="currency-conversion-charges-part-of-per-diem">Currency Conversion Charges Part of Per Diem</h4>
 
<p>Any fees associated with currency conversion are not reimbursable as an
 
expense separate from the allocated per diem.</p>
 
<h3 id="conference-registration-fees">Conference Registration Fees</h3>
 
<p>Conservancy will reimburse conference registration fees up to $100 per day
 
for Travelers on approved Project business and/or approved Conservancy
 
business.  For example, a $250 registration fee for a 3-day conference is
 
In-Policy; however, a $225 registration fee for a 2-day conference is not.</p>
 
<p>Travelers seeking reimbursement for registration fees that exceed $100 per
 
day must obtain prior approval from an officer of Conservancy.</p>
 
<h3 id="internet-access">Internet Access</h3>
 
<p>Internet access/wi-fi fees charged by a hotel are reimbursable, provided
 
that they are listed on the hotel/lodging invoice submitted for
 
reimbursement.  Other internet access fees (e.g., airport internet
 
services, personal wi-fi hotspots, internet cafes) are not reimbursable
 
except as incidental expenses to be covered by a Traveler&rsquo;s per diem.</p>
 
<h2 id="non-reimbursable-expenses">Non-reimbursable Expenses</h2>
 
<p>Non-reimbursable expenses are identified throughout this policy.  The
 
following items are typically non-reimbursable expenses:</p>
 
<ul>
 
<li>
 
<p>Partner, spouse, and/or companion travel</p>
 
</li>
 
<li>
 
<p>First class travel (unless medically necessary)</p>
 
</li>
 
<li>
 
<p>Upgrades to air travel, car rentals, or hotel rooms</p>
 
</li>
 
<li>
 
<p>Purchase of clothing, luggage, toiletries and other miscellaneous
 
personal items</p>
 
</li>
 
<li>
 
<p>Supplemental travel or car rental insurance</p>
 
</li>
 
<li>
 
<p>Fines, penalties, or legal fees</p>
 
</li>
 
<li>
 
<p>Personal entertainment or recreational expenses beyond the allotted per
 
diem</p>
 
</li>
 
</ul>
 
<p>Travelers are permitted to pay for their own upgrades, or use bonus
 
programs to upgrade Conservancy-reimbursed expenses.  However, Travelers
 
must ensure that Conservancy does not receive nor reimburse any charges
 
for any such transaction.</p>
 
<h2 id="satisfaction-of-irs-requirements">Satisfaction of IRS Requirements</h2>
 
<p>Reimbursed travel expenses are subject to examination by the USA Internal
 
Revenue Service (IRS).  Travelers are responsible for retaining documentary
 
evidence that all expenses are strictly for Project- and/or
 
Conservancy-related purposes, not personal in nature, and therefore not
 
includable as taxable income to the Traveler.  Receipts are required for
 
all expenses, no matter the amount.</p>
 
<h2 id="approvals">Approvals</h2>
 
<p>Travelers traveling on behalf of a Project must seek approvals and
 
submit expense reports to their PLC.  PLCs are to review those expense
 
reports and pass them along to Conservancy&rsquo;s accounting office for
 
final approval and reimbursement.</p>
 
<p>Travelers traveling on behalf of Conservancy must seek approvals from
 
Conservancy&rsquo;s Executive Director, and submit expense reports to
 
Conservancy&rsquo;s accounting office for reimbursement.</p>
 
<h2 id="expense-reporting">Expense Reporting</h2>
 
<p>Travelers seeking reimbursement must submit an expense report to the
 
appropriate channel with the following information:</p>
 
<ul>
 
<li>
 
<p>Name of Traveler</p>
 
</li>
 
<li>
 
<p>Brief description of trip and trip&rsquo;s purpose (e.g., &ldquo;August 2011
 
trip to XYZ conference for ABC project, served as planning committee
 
member&rdquo;; &ldquo;Feb. &lsquo;12 FOO hackfest in Portland, OR; contributed code&rdquo;)</p>
 
</li>
 
<li>
 
<p>A brief paragraph explaining what was accomplished for the project
 
during your travel.</p>
 
</li>
 
<li>
 
<p>Number of days traveled (with documentary evidence, e.g., conference
 
itinerary, etc.) and associated per diem</p>
 
</li>
 
<li>
 
<p>List of expenses not covered by per diem (e.g., transportation, lodging)
 
with substantiating receipts (or scans of receipts).</p>
 
</li>
 
</ul>
 
<p>In the event that it is impractical to obtain a required receipt and/or if
 
  such receipt has been inadvertently destroyed or lost, the Traveler should
 
  furnish a written statement to that effect, as well as an explanation of
 
  the expenditure involved.  When possible, secondary documentation (such as
 
  a redacted credit card bill) should be provided instead of the
 
  lost/destroyed receipt.</p>
 
<p>Any expense without a substantiated receipt and/or a supporting written
 
statement will not be reimbursed.</p>
 
<p>Conservancy requests that all expense reports be submitted within two weeks
 
of travel.  Expense reports filed more than 90 days after the last day of
 
travel (or for other reimbursable expenses, the day expenses are incurred)
 
<strong>will not be reimbursed</strong>.</p>
 
<p>Reimbursements are paid by Conservancy on a NET-30 basis, from the
 
date of receipt by Conservancy of the fully complete report and supporting
 
documentation for the travel.</p>
 
<h2 id="consequences-of-policy-violations">Consequences of Policy Violations</h2>
 
<p>Failure to comply with this policy may result in the denial of, or delay
 
in payment for, reimbursement requests.</p>
 
<h2 id="policy-changes">Policy Changes</h2>
 
<p>The Conservancy reserves the right to change any terms of this Policy
 
from time to time. The Policy of record shall be the Policy most recently
 
distributed by the Conservancy. </p>
 

	
 
{% endblock %}
www/conservancy/static/projects/policies/conservancy-travel-policy.html
Show inline comments
 
new file 120000
 
conservancy-travel-policy.783dcdd92fc61f3f150e1c65782c0fe527c8ff52.html
...
 
\ No newline at end of file
www/conservancy/static/projects/policies/index.html
Show inline comments
 
new file 100644
 
{% extends "base_projects.html" %}
 
{% block subtitle %}Member Project Policies - {% endblock %}
 
{% block submenuselection %}Policies{% endblock %}
 
{% block content %}
 

	
 
<h1>Member Project Policies</h1>
 

	
 
<p>These are the policies that member projects follow in working with Conservancy.  These pages are provided as a reference to all projects participants.</p>
 

	
 
<ul>
 
  <li><a href="conservancy-travel-policy.html">Travel and reimburseable expense policy</a></li>
 
</ul>
 

	
 
<p>For more background about the policies, including licensing and change requests, please refer to <a href="https://k.sfconservancy.org/policies">their source code in Git</a>.</p>
 

	
 
{% endblock %}
www/conservancy/static/projects/policies/publish-travel-policy.py
Show inline comments
 
new file 100755
 
#!/usr/bin/env python3
 

	
 
import argparse
 
import contextlib
 
import functools
 
import locale
 
import os
 
import pathlib
 
import shutil
 
import subprocess
 
import sys
 
import tempfile
 

	
 
try:
 
    import markdown
 
    from markdown.extensions import tables as mdx_tables
 
    from markdown.extensions import sane_lists as mdx_sane_lists
 
    from markdown.extensions import smarty as mdx_smarty
 
    from markdown.extensions import toc as mdx_toc
 
    markdown_import_success = True
 
except ImportError:
 
    if __name__ != '__main__':
 
        raise
 
    markdown_import_success = False
 

	
 
TEMPLATE_HEADER = """{% extends "base_projects.html" %}
 
{% block subtitle %}Travel and Reimburseable Expense Policy - {% endblock %}
 
{% block submenuselection %}Policies{% endblock %}
 
{% block content %}
 

	
 
"""
 

	
 
TEMPLATE_FOOTER = """
 

	
 
{% endblock %}
 
"""
 

	
 
@contextlib.contextmanager
 
def run(cmd, encoding=None, ok_exitcodes=frozenset([0]), **kwargs):
 
    kwargs.setdefault('stdout', subprocess.PIPE)
 
    if encoding is None:
 
        mode = 'rb'
 
        no_data = b''
 
    else:
 
        mode = 'r'
 
        no_data = ''
 
    with contextlib.ExitStack() as exit_stack:
 
        proc = exit_stack.enter_context(subprocess.Popen(cmd, **kwargs))
 
        pipes = [exit_stack.enter_context(open(
 
                   getattr(proc, name).fileno(), mode, encoding=encoding, closefd=False))
 
                 for name in ['stdout', 'stderr']
 
                 if kwargs.get(name) is subprocess.PIPE]
 
        if pipes:
 
            yield (proc, *pipes)
 
        else:
 
            yield proc
 
        for pipe in pipes:
 
            for _ in iter(lambda: pipe.read(4096), no_data):
 
                pass
 
    if proc.returncode not in ok_exitcodes:
 
        raise subprocess.CalledProcessError(proc.returncode, cmd)
 

	
 
class GitPath:
 
    GIT_BIN = shutil.which('git')
 
    CLEAN_ENV = {k: v for k, v in os.environ.items() if not k.startswith('GIT_')}
 
    ANY_EXITCODE = range(-256, 257)
 
    IGNORE_ERRORS = {
 
        'ok_exitcodes': ANY_EXITCODE,
 
        'stderr': subprocess.DEVNULL,
 
    }
 
    STATUS_CLEAN_OR_UNMANAGED = frozenset(' ?')
 

	
 
    def __init__(self, path, encoding, env=None):
 
        self.path = path
 
        self.dir_path = path if path.is_dir() else path.parent
 
        self.encoding = encoding
 
        self.run_defaults = {
 
            'cwd': str(self.dir_path),
 
            'env': env,
 
        }
 

	
 
    @classmethod
 
    def can_run(cls):
 
        return cls.GIT_BIN is not None
 

	
 
    def _run(self, cmd, encoding=None, ok_exitcodes=frozenset([0]), **kwargs):
 
        return run(cmd, encoding, ok_exitcodes, **self.run_defaults, **kwargs)
 

	
 
    def _cache(orig_func):
 
        attr_name = '_cached_' + orig_func.__name__
 
        @functools.wraps(orig_func)
 
        def cache_wrapper(self):
 
            try:
 
                return getattr(self, attr_name)
 
            except AttributeError:
 
                setattr(self, attr_name, orig_func(self))
 
                return getattr(self, attr_name)
 
        return cache_wrapper
 

	
 
    @_cache
 
    def is_work_tree(self):
 
        with self._run([self.GIT_BIN, 'rev-parse', '--is-inside-work-tree'],
 
                       self.encoding, **self.IGNORE_ERRORS) as (_, stdout):
 
            return stdout.readline() == 'true\n'
 

	
 
    @_cache
 
    def status_lines(self):
 
        with self._run([self.GIT_BIN, 'status', '-z'],
 
                       self.encoding) as (_, stdout):
 
            return stdout.read().split('\0')
 

	
 
    @_cache
 
    def has_managed_modifications(self):
 
        return any(line and line[1] not in self.STATUS_CLEAN_OR_UNMANAGED
 
                   for line in self.status_lines())
 

	
 
    @_cache
 
    def has_staged_changes(self):
 
        return any(line and line[0] not in self.STATUS_CLEAN_OR_UNMANAGED
 
                   for line in self.status_lines())
 

	
 
    def commit_at(self, revision):
 
        with self._run([self.GIT_BIN, 'rev-parse', revision],
 
                       self.encoding) as (_, stdout):
 
            return stdout.readline().rstrip('\n') or None
 

	
 
    @_cache
 
    def upstream_commit(self):
 
        return self.commit_at('@{upstream}')
 

	
 
    @_cache
 
    def head_commit(self):
 
        return self.commit_at('HEAD')
 

	
 
    def in_sync_with_upstream(self):
 
        return self.upstream_commit() == self.head_commit()
 

	
 
    @_cache
 
    def last_commit(self):
 
        with self._run([self.GIT_BIN, 'log', '-n1', '--format=format:%H', self.path.name],
 
                       self.encoding, **self.IGNORE_ERRORS) as (_, stdout):
 
            return stdout.readline().rstrip('\n') or None
 

	
 
    def operate(self, subcmd, ok_exitcodes=frozenset([0])):
 
        with self._run([self.GIT_BIN, *subcmd], None, ok_exitcodes, stdout=None):
 
            pass
 

	
 

	
 
def add_parser_flag(argparser, dest, **kwargs):
 
    kwargs.update(dest=dest, default=None)
 
    switch_root = dest.replace('_', '-')
 
    switch = '--' + switch_root
 
    argparser.add_argument(switch, **kwargs, action='store_true')
 
    kwargs['help'] = "Do not do {}".format(switch)
 
    argparser.add_argument('--no-' + switch_root, **kwargs, action='store_false')
 

	
 
def parse_arguments(arglist):
 
    parser = argparse.ArgumentParser(
 
        epilog="""By default, the program will pull from Git if the output path
 
is a Git checkout with a tracking branch, and will commit and push if
 
that checkout is in sync with the tracking branch without any staged changes.
 
Setting any flag will always override the default behavior.
 
""",
 
    )
 

	
 
    parser.add_argument(
 
        '--encoding', '-E',
 
        default=locale.getpreferredencoding(),
 
        help="Encoding to use for all I/O. "
 
        "Default is your locale's encoding.",
 
    )
 
    parser.add_argument(
 
        '--revision', '-r',
 
        help="Revision string to version the published page. "
 
        "Default determined from the revision of the source file.",
 
    )
 
    add_parser_flag(
 
        parser, 'pull',
 
        help="Try to pull the remote tracking branch to make the checkout "
 
        "up-to-date before making changes"
 
    )
 
    add_parser_flag(
 
        parser, 'commit',
 
        help="Commit changes to the travel policy",
 
    )
 
    parser.add_argument(
 
        '-m', dest='commit_message',
 
        default="Publish {filename} revision {revision}.",
 
        help="Message for any commit",
 
    )
 
    add_parser_flag(
 
        parser, 'push',
 
        help="Push to the remote tracking branch after committing changes",
 
    )
 
    parser.add_argument(
 
        'input_path', type=pathlib.Path,
 
        help="Path to the Conservancy travel policy Markdown source",
 
    )
 
    parser.add_argument(
 
        'output_path', type=pathlib.Path,
 
        nargs='?', default=pathlib.Path(__file__).parent,
 
        help="Path to the directory to write output files",
 
    )
 

	
 
    if not markdown_import_success:
 
        parser.error("""markdown module is not installed.
 
Try `apt install python3-markdown` or `python3 -m pip install --user Markdown`.""")
 

	
 
    args = parser.parse_args(arglist)
 
    args.git_output = GitPath(args.output_path, args.encoding)
 
    if args.pull or args.commit or args.push:
 
        if not args.git_output.can_run():
 
            parser.error("Git operation requested but `git` not found in PATH")
 
        elif not args.git_output.is_work_tree():
 
            parser.error("Git operation requested but {} is not a working path".format(
 
                args.output_path.as_posix()))
 
    if args.revision is None:
 
        try:
 
            args.revision = GitPath(args.input_path, args.encoding, GitPath.CLEAN_ENV).last_commit()
 
        except subprocess.CalledProcessError:
 
            pass
 
        if args.revision is None:
 
            parser.error("no --revision specified and not found from input path")
 
    args.output_link_path = args.git_output.dir_path / 'conservancy-travel-policy.html'
 
    args.output_file_path = args.output_link_path.with_suffix('.{}.html'.format(args.revision))
 
    return args
 

	
 
class GitOperation:
 
    def __init__(self, args):
 
        self.args = args
 
        self.git_path = args.git_output
 
        self.exitcode = None
 
        self.on_work_tree = self.git_path.can_run() and self.git_path.is_work_tree()
 

	
 
    def run(self):
 
        arg_state = getattr(self.args, self.NAME)
 
        if arg_state is None:
 
            arg_state = self.should_run()
 
        if not arg_state:
 
            return
 
        try:
 
            self.exitcode = self.run_git() or 0
 
        except subprocess.CalledProcessError as error:
 
            self.exitcode = error.returncode
 

	
 

	
 
class GitPull(GitOperation):
 
    NAME = 'pull'
 

	
 
    def should_run(self):
 
        return self.on_work_tree and not self.git_path.has_staged_changes()
 

	
 
    def run_git(self):
 
        self.git_path.operate(['fetch', '--no-tags'])
 
        self.git_path.operate(['merge', '--ff-only'])
 

	
 

	
 
class GitCommit(GitOperation):
 
    NAME = 'commit'
 
    VERB = 'committed'
 

	
 
    def __init__(self, args):
 
        super().__init__(args)
 
        try:
 
            self._should_run = ((not self.git_path.has_staged_changes())
 
                                and self.git_path.in_sync_with_upstream())
 
        except subprocess.CalledProcessError:
 
            self._should_run = False
 

	
 
    def should_run(self):
 
        return self.on_work_tree and self._should_run
 

	
 
    def run_git(self):
 
        self.git_path.operate([
 
            'add', str(self.args.output_file_path), str(self.args.output_link_path),
 
        ])
 
        commit_message = self.args.commit_message.format(
 
            filename=self.args.output_link_path.name,
 
            revision=self.args.revision,
 
        )
 
        self.git_path.operate(['commit', '-m', commit_message])
 

	
 

	
 
class GitPush(GitCommit):
 
    NAME = 'push'
 
    VERB = 'pushed'
 

	
 
    def run_git(self):
 
        self.git_path.operate(['push'])
 

	
 

	
 
def write_output(args):
 
    converter = markdown.Markdown(
 
        extensions=[
 
            mdx_tables.TableExtension(),
 
            mdx_sane_lists.SaneListExtension(),
 
            mdx_smarty.SmartyExtension(),
 
            mdx_toc.TocExtension(),
 
        ],
 
        output_format='html5',
 
    )
 
    with args.input_path.open(encoding=args.encoding) as src_file:
 
        body = converter.convert(src_file.read())
 
    with tempfile.NamedTemporaryFile(
 
            'w',
 
            encoding=args.encoding,
 
            dir=args.git_output.dir_path.as_posix(),
 
            suffix='.html',
 
            delete=False,
 
    ) as tmp_out:
 
        try:
 
            tmp_out.write(TEMPLATE_HEADER)
 
            tmp_out.write(body)
 
            tmp_out.write(TEMPLATE_FOOTER)
 
            tmp_out.flush()
 
            os.rename(tmp_out.name, str(args.output_file_path))
 
        except BaseException:
 
            os.unlink(tmp_out.name)
 
            raise
 
    if args.output_link_path.is_symlink():
 
        args.output_link_path.unlink()
 
    args.output_link_path.symlink_to(args.output_file_path.name)
 

	
 
def main(arglist=None, stdout=sys.stdout, stderr=sys.stderr):
 
    args = parse_arguments(arglist)
 
    pull = GitPull(args)
 
    pull.run()
 
    if pull.exitcode:
 
        return pull.exitcode
 
    write_output(args)
 
    ops = [GitCommit(args), GitPush(args)]
 
    for op in ops:
 
        op.run()
 
        if op.exitcode != 0:
 
            exitcode = op.exitcode or 0
 
            break
 
    else:
 
        exitcode = 0
 
    print(args.input_path.name, "converted,",
 
          ", ".join(op.VERB if op.exitcode == 0 else "not " + op.VERB for op in ops),
 
          file=stdout)
 
    return exitcode
 

	
 
if __name__ == '__main__':
 
    exit(main())
 

	
www/conservancy/templates/base_projects.html
Show inline comments
 
{% extends "base_conservancy.html" %}
 
{% block outercontent %}
 
    <div id="container">
 
         <div id="sidebar" class="{% block submenuselection %}other{% endblock %}">
 
            <h2>{% block category %}Projects{% endblock %} &amp; Services</h2>
 
            <ul>
 
            <li class="Current"><a href="/projects/current/">Current Member Projects</a></li>
 
            <li class="Services"><a href="/projects/services/">Member Project Services</a></li>
 
            <li class="Applying"><a href="/projects/apply/">Applying</a></li>
 
            <li class="Services"><a href="/projects/services/">Member Project Services</a></li>
 
            <li class="Policies"><a href="/projects/policies/">Member Project Policies</a></li>
 
            </ul>
 
         </div>
 
               <div id="mainContent">{% block content %}{% endblock %}
 
               </div>
 
   </div>
 
{% endblock %}
0 comments (0 inline, 0 general)