Skip to content

Commit

Permalink
Document how to reimburse cloud and add oxipng nox job (#716)
Browse files Browse the repository at this point in the history
  • Loading branch information
choldgraf authored Apr 20, 2023
1 parent 2ed06a6 commit fd406b5
Show file tree
Hide file tree
Showing 11 changed files with 98 additions and 0 deletions.
74 changes: 74 additions & 0 deletions administration/reimburse.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,77 @@ This can drastically speed up the process of approving recurring transactions.

Ramp should scan the e-mail and automatically attach the receipt to the proper expense.
See [the Ramp receipt detection documentation](https://support.ramp.com/hc/en-us/articles/360042588454-Submitting-Receipts-Memos) for more details.

(reimburse:cloud)=
## Cloud reimbursements

We must follow a few extra steps to reimburse our cloud bills.
CS&S requires **invoices** (not a receipts) for cloud costs.

We document how to find each of these for our cloud providers below.

### Google Cloud Platform (GCP)

Use the Google Cloud Console UI to find invoices for previous months.
In GCP "invoices" are called "**statements**".
To find a statement for a month, follow these steps:

First, go to [`console.cloud.google.com`](https://console.cloud.google.com).

Double-check that you're signed in with your `@2i2c.org` account.

Click on `Billing` in the hamburger menu.

```{image} /images/reimbursements/billing-menu.png
:width: 500
```

Click the billing account name you need an invoice for.
Our default billing account is called `2i2c Billing`.
This is where the majority of our cloud costs come from on GCP.
Some project-specific billing accounts are usually listed as well.

```{image} /images/reimbursements/billing-accounts.png
:width: 500
```

In the left menu, scroll down to the `Payments` section and click `Documents`.

```{image} /images/reimbursements/find-documents-page.png
:width: 500
```


Check the box next to the month you want, and then click `Download selected`.

```{image} /images/reimbursements/download-selected-invoice.png
:width: 500
```

This PDF is the statement (invoice) that you will upload to the corresponding Ramp.com transaction.

Look for the Ramp.com transaction that corresponds to this invoice.
You can do so by finding the Google Cloud transactions that are "flagged for review" (because it is missing an invoice), and cross-reference the total charged amount.

```{warning}
Some Google Cloud Billing Accounts will split a monthly cost into multiple transactions.
For example, some accounts have an "automatic charge at $1,000" trigger.
In this case, find multiple transactions that add up to the amount of the monthly invoice.
```

```{image} /images/reimbursements/find-missing-item-receipt.png
:width: 500
```

Upload the PDF to the receipt section of this transaction.

```{image} /images/reimbursements/upload-receipt-to-ramp.png
:width: 500
```

### Amazon Web Services (AWS)

AWS automatically e-mails cloud account admins a PDF of their monthly invoice.
Chris Holdgraf's e-mail account is set up to automatically forward this e-mail to `[email protected]`, and this will automatically match the PDF with the corresponding charge in our Ramp account.

Chris' account also automatically forwards this e-mail to `[email protected]`, so if we must manually upload the receipt for some reason, find the e-mail with the PDF in the Google Group for that e-mail account.
4 changes: 4 additions & 0 deletions finance/cloud.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ They have a different line-item and category in our CS&S invoicing statements an

We may wish to charge a bit extra for the **staffing** costs of this service, but this is different from the pass-through cloud bill.

## Reimburse cloud costs

See [](reimburse:cloud).

## Dedicated clusters

When a community has a dedicated cluster, it is straightforward to calculate their monthly cloud costs.
Expand Down
Binary file modified images/airtable-major-sections.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/reimbursements/billing-accounts.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/reimbursements/billing-menu.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/reimbursements/find-documents-page.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/reimbursements/upload-receipt-to-ramp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions noxfile.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import nox
from textwrap import dedent
from shlex import split
from pathlib import Path

nox.options.reuse_existing_virtualenvs = True

Expand Down Expand Up @@ -28,3 +31,20 @@ def docs(session):
cmd = ["sphinx-build"]
cmd.extend(build_command + session.posargs)
session.run(*cmd)

@nox.session
def images(session):
"""Optimize images using oxipng. Note you must install oxipng on your own first."""
# Command taken from https://github.com/shssoichiro/oxipng#usage
# Use the external environment since we assume oxipng is installed on its own.
try:
images = Path("images").rglob("**/*.png")
for img in images:
session.run(*split(f"oxipng -o 4 -i 0 --strip safe --recursive {img}"), external=True)
except Exception:
msg = dedent(f"""
Could not run oxipng, double-check that it is installed properly.
See https://github.com/shssoichiro/oxipng#installing.
""")
print(msg)

0 comments on commit fd406b5

Please sign in to comment.