Full Code of pydanny/dj-stripe for AI

master b17d637fede5 cached
290 files
2.0 MB
446.5k tokens
1597 symbols
1 requests
Download .txt
Showing preview only (2,110K chars total). Download the full file or copy to clipboard to get everything.
Repository: pydanny/dj-stripe
Branch: master
Commit: b17d637fede5
Files: 290
Total size: 2.0 MB

Directory structure:
gitextract_rkwri8yg/

├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── api-change-notice.md
│   │   ├── bug_report.md
│   │   ├── documentation-issue-request.md
│   │   ├── feature-or-enhancement-proposal.md
│   │   ├── general-bug.md
│   │   ├── how-to-usage-question.md
│   │   ├── issue-with-webhooks-or-sync.md
│   │   ├── migration-upgrade-issue.md
│   │   └── other-issue.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   ├── install_poetry_action/
│   │   └── action.yaml
│   └── workflows/
│       ├── ci.yml
│       ├── codeql-analysis.yml
│       ├── docs.yml
│       └── linting.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .readthedocs.yml
├── LICENSE
├── djstripe/
│   ├── __init__.py
│   ├── admin/
│   │   ├── __init__.py
│   │   ├── actions.py
│   │   ├── admin.py
│   │   ├── admin_inline.py
│   │   ├── filters.py
│   │   ├── forms.py
│   │   ├── utils.py
│   │   └── views.py
│   ├── apps.py
│   ├── checks.py
│   ├── enums.py
│   ├── event_handlers.py
│   ├── exceptions.py
│   ├── fields.py
│   ├── locale/
│   │   ├── fr/
│   │   │   └── LC_MESSAGES/
│   │   │       └── django.po
│   │   └── ru/
│   │       └── LC_MESSAGES/
│   │           └── django.po
│   ├── management/
│   │   ├── __init__.py
│   │   └── commands/
│   │       ├── __init__.py
│   │       ├── djstripe_clear_expired_idempotency_keys.py
│   │       ├── djstripe_init_customers.py
│   │       ├── djstripe_process_events.py
│   │       ├── djstripe_sync_customers.py
│   │       ├── djstripe_sync_models.py
│   │       └── djstripe_update_invoiceitem_ids.py
│   ├── managers.py
│   ├── migrations/
│   │   ├── 0001_initial.py
│   │   ├── 0008_2_5.py
│   │   ├── 0009_2_6.py
│   │   ├── 0010_alter_customer_balance.py
│   │   ├── 0011_2_7.py
│   │   ├── 0012_auto_20221217_0559.py
│   │   ├── 0013_product_default_price.py
│   │   ├── 0014_lineitem.py
│   │   ├── 0015_alter_payout_destination.py
│   │   ├── 0016_alter_payout_destination.py
│   │   ├── 0017_invoiceorlineitem.py
│   │   ├── 0018_discount.py
│   │   ├── 0019_add_customer_discount.py
│   │   ├── __init__.py
│   │   └── sql/
│   │       ├── migrate_mysql_backward.sql
│   │       ├── migrate_mysql_forward.sql
│   │       ├── migrate_postgresql_backward.sql
│   │       ├── migrate_postgresql_forward.sql
│   │       ├── migrate_sqlite_backward.sql
│   │       └── migrate_sqlite_forward.sql
│   ├── mixins.py
│   ├── models/
│   │   ├── __init__.py
│   │   ├── account.py
│   │   ├── api.py
│   │   ├── base.py
│   │   ├── billing.py
│   │   ├── checkout.py
│   │   ├── connect.py
│   │   ├── core.py
│   │   ├── fraud.py
│   │   ├── orders.py
│   │   ├── payment_methods.py
│   │   ├── sigma.py
│   │   └── webhooks.py
│   ├── settings.py
│   ├── signals.py
│   ├── sync.py
│   ├── templates/
│   │   └── djstripe/
│   │       └── admin/
│   │           ├── add_form.html
│   │           ├── change_form.html
│   │           ├── confirm_action.html
│   │           └── webhook_endpoint/
│   │               ├── add_form.html
│   │               ├── change_form.html
│   │               └── delete_confirmation.html
│   ├── urls.py
│   ├── utils.py
│   ├── views.py
│   └── webhooks.py
├── docs/
│   ├── CONTRIBUTING.md
│   ├── README.md
│   ├── __init__.py
│   ├── api_keys.md
│   ├── api_versions.md
│   ├── history/
│   │   ├── 0_x.md
│   │   ├── 1_x.md
│   │   ├── 2_4_0.md
│   │   ├── 2_4_x.md
│   │   ├── 2_5_0.md
│   │   ├── 2_5_x.md
│   │   ├── 2_6_0.md
│   │   ├── 2_6_x.md
│   │   ├── 2_7_0.md
│   │   ├── 2_7_x.md
│   │   ├── 2_8_0.md
│   │   └── 2_x.md
│   ├── installation.md
│   ├── project/
│   │   ├── authors.md
│   │   ├── release_process.md
│   │   ├── sponsors.md
│   │   ├── support.md
│   │   └── test_fixtures.md
│   ├── reference/
│   │   ├── enums.md
│   │   ├── managers.md
│   │   ├── models.md
│   │   ├── project.md
│   │   ├── settings.md
│   │   └── utils.md
│   ├── stripe_elements_js.md
│   └── usage/
│       ├── creating_individual_charges.md
│       ├── creating_usage_record.md
│       ├── local_webhook_testing.md
│       ├── managing_subscriptions.md
│       ├── manually_syncing_with_stripe.md
│       ├── subscribing_customers.md
│       ├── using_stripe_checkout.md
│       ├── using_with_docker.md
│       └── webhooks.md
├── manage.py
├── mkdocs.yml
├── pyproject.toml
├── tests/
│   ├── __init__.py
│   ├── apps/
│   │   ├── __init__.py
│   │   ├── example/
│   │   │   ├── __init__.py
│   │   │   ├── forms.py
│   │   │   ├── management/
│   │   │   │   ├── __init__.py
│   │   │   │   └── commands/
│   │   │   │       ├── __init__.py
│   │   │   │       └── regenerate_test_fixtures.py
│   │   │   ├── templates/
│   │   │   │   ├── checkout.html
│   │   │   │   ├── checkout_success.html
│   │   │   │   ├── example_base.html
│   │   │   │   ├── payment_intent.html
│   │   │   │   ├── purchase_subscription.html
│   │   │   │   └── purchase_subscription_success.html
│   │   │   ├── urls.py
│   │   │   └── views.py
│   │   ├── testapp/
│   │   │   ├── __init__.py
│   │   │   ├── models.py
│   │   │   └── urls.py
│   │   ├── testapp_content/
│   │   │   ├── README.md
│   │   │   ├── __init__.py
│   │   │   ├── models.py
│   │   │   └── urls.py
│   │   └── testapp_namespaced/
│   │       ├── __init__.py
│   │       ├── models.py
│   │       └── urls.py
│   ├── conftest.py
│   ├── fields/
│   │   ├── admin.py
│   │   └── models.py
│   ├── fixtures/
│   │   ├── account_custom_acct_1IuHosQveW0ONQsd.json
│   │   ├── account_express_acct_1IuHosQveW0ONQsd.json
│   │   ├── account_standard_acct_1Fg9jUA3kq9o1aTc.json
│   │   ├── balance_transaction_txn_fake_ch_fakefakefakefakefake0001.json
│   │   ├── bank_account_ba_fakefakefakefakefake0003.json
│   │   ├── bank_account_ba_fakefakefakefakefake0004.json
│   │   ├── card_card_fakefakefakefakefake0001.json
│   │   ├── card_card_fakefakefakefakefake0002.json
│   │   ├── card_card_fakefakefakefakefake0003.json
│   │   ├── card_card_fakefakefakefakefake0004.json
│   │   ├── charge_ch_fakefakefakefakefake0001.json
│   │   ├── customer_cus_4QWKsZuuTHcs7X.json
│   │   ├── customer_cus_4UbFSo9tl62jqj.json
│   │   ├── customer_cus_6lsBvm5rJ0zyHc.json
│   │   ├── customer_cus_example_with_bank_account.json
│   │   ├── dispute_ch_fakefakefakefake01.json
│   │   ├── dispute_dp_fakefakefakefake01.json
│   │   ├── dispute_dp_fakefakefakefake02.json
│   │   ├── dispute_dp_funds_reinstated_full.json
│   │   ├── dispute_pi_fakefakefakefake01.json
│   │   ├── dispute_pm_fakefakefakefake01.json
│   │   ├── dispute_txn_fakefakefakefake01.json
│   │   ├── event_account_application_authorized.json
│   │   ├── event_account_application_deauthorized.json
│   │   ├── event_account_updated_custom.json
│   │   ├── event_account_updated_express.json
│   │   ├── event_account_updated_standard.json
│   │   ├── event_external_account_bank_account_created.json
│   │   ├── event_external_account_bank_account_deleted.json
│   │   ├── event_external_account_bank_account_updated.json
│   │   ├── event_external_account_card_created.json
│   │   ├── event_external_account_card_deleted.json
│   │   ├── event_external_account_card_updated.json
│   │   ├── invoice_in_fakefakefakefakefake0001.json
│   │   ├── invoice_in_fakefakefakefakefake0004.json
│   │   ├── line_item_il_invoice_item_fakefakefakefakefake0001.json
│   │   ├── line_item_il_invoice_item_fakefakefakefakefake0002.json
│   │   ├── order_order_fakefakefakefake0001.json
│   │   ├── payment_intent_pi_destination_charge.json
│   │   ├── payment_intent_pi_fakefakefakefakefake0001.json
│   │   ├── payment_method_card_fakefakefakefakefake0001.json
│   │   ├── payment_method_pm_fakefakefakefake0001.json
│   │   ├── payout_custom_bank_account.json
│   │   ├── payout_custom_card.json
│   │   ├── plan_gold21323.json
│   │   ├── plan_silver41294.json
│   │   ├── price_gold21323.json
│   │   ├── price_silver41294.json
│   │   ├── product_prod_fake1.json
│   │   ├── setup_intent_pi_destination_charge.json
│   │   ├── shipping_rate_shr_fakefakefakefakefake0001.json
│   │   ├── shipping_rate_shr_fakefakefakefakefake0002.json
│   │   ├── source_src_fakefakefakefakefake0001.json
│   │   ├── subscription_sub_fakefakefakefakefake0001.json
│   │   ├── subscription_sub_fakefakefakefakefake0002.json
│   │   ├── subscription_sub_fakefakefakefakefake0003.json
│   │   ├── subscription_sub_fakefakefakefakefake0004.json
│   │   ├── tax_code_txcd_fakefakefakefakefake0001.json
│   │   ├── tax_id_txi_fakefakefakefakefake0001.json
│   │   ├── tax_rate_txr_fakefakefakefakefake0001.json
│   │   ├── tax_rate_txr_fakefakefakefakefake0002.json
│   │   ├── usage_record_summary_sis_fakefakefakefakefake0001.json
│   │   └── webhook_endpoint_fake0001.json
│   ├── settings.py
│   ├── templates/
│   │   └── base.html
│   ├── test_account.py
│   ├── test_admin.py
│   ├── test_api_keys.py
│   ├── test_apikey.py
│   ├── test_balance_transaction.py
│   ├── test_bank_account.py
│   ├── test_card.py
│   ├── test_charge.py
│   ├── test_checks.py
│   ├── test_coupon.py
│   ├── test_customer.py
│   ├── test_discount.py
│   ├── test_dispute.py
│   ├── test_django.py
│   ├── test_enums.py
│   ├── test_event.py
│   ├── test_event_handlers.py
│   ├── test_fields.py
│   ├── test_file_link.py
│   ├── test_file_upload.py
│   ├── test_forms.py
│   ├── test_idempotency_keys.py
│   ├── test_integrations/
│   │   ├── README.md
│   │   └── __init__.py
│   ├── test_invoice.py
│   ├── test_invoiceitem.py
│   ├── test_line_item.py
│   ├── test_managers.py
│   ├── test_migrations.py
│   ├── test_mixins.py
│   ├── test_order.py
│   ├── test_payment_intent.py
│   ├── test_payment_method.py
│   ├── test_payout.py
│   ├── test_plan.py
│   ├── test_price.py
│   ├── test_product.py
│   ├── test_refund.py
│   ├── test_session.py
│   ├── test_settings.py
│   ├── test_setup_intent.py
│   ├── test_shipping_rate.py
│   ├── test_source.py
│   ├── test_stripe_model.py
│   ├── test_subscription.py
│   ├── test_subscription_item.py
│   ├── test_subscription_schedule.py
│   ├── test_sync.py
│   ├── test_tax_code.py
│   ├── test_tax_id.py
│   ├── test_tax_rates.py
│   ├── test_transfer.py
│   ├── test_transfer_reversal.py
│   ├── test_usage_record.py
│   ├── test_usage_record_summary.py
│   ├── test_utils.py
│   ├── test_views.py
│   ├── test_webhooks.py
│   └── urls.py
└── tox.ini

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# EditorConfig: http://editorconfig.org
root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
quote_type = double
insert_final_newline = true
trim_trailing_whitespace = true
max_line_length = 88

[*.json]
insert_final_newline = false


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: dj-stripe
open_collective: dj-stripe


================================================
FILE: .github/ISSUE_TEMPLATE/api-change-notice.md
================================================
---
name: API Change Notice
about: Has something changed in the Stripe API that we haven't gotten to? Let us know
title: API change for [Stripe Object Names] in version [New Stripe Version]
labels: api change
assignees: ''

---

**Changelog Link**
<!-- Supply a direct link to the [changelog](https://stripe.com/docs/upgrades#api-changelog) entry -->

**Describe the Change**
<!-- Provide a brief, clear, and concise description of what was added/updated/removed. A bulleted-list of affected models and fields would be incredibly helpful (bonus points for links to dj-stripe code). -->


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Any other type of bug or crash
title: ''
labels: bug
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
<!-- Please describe how to reproduce the issue below. Make sure not to include private keys or live customer information. -->


**Software versions**
- Dj-Stripe version:
- Python version:
- Django version:
- Stripe API version:
- Database type and version:


================================================
FILE: .github/ISSUE_TEMPLATE/documentation-issue-request.md
================================================
---
name: Documentation Issue/Request
about: Is something missing from the docs? Is a section of the docs outdated or incorrect?
  Let us know.
title: ''
labels: documentation
assignees: ''

---

**What did you run into?**

**Why would it be helpful to document or fix this?**

**To which section of the docs does this belong?**


================================================
FILE: .github/ISSUE_TEMPLATE/feature-or-enhancement-proposal.md
================================================
---
name: Feature or Enhancement Proposal
about: Suggest an idea for this project
title: ''
labels: discussion
assignees: ''

---

**Is your request related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->

**Describe the solution you'd like**
<!-- A clear and concise description of what you would like to see. -->

**Additional context**
<!-- Add any other context about the request here. -->


================================================
FILE: .github/ISSUE_TEMPLATE/general-bug.md
================================================
---
name: General Bug
about: Any type of bug or crash not related to webhooks or syncing
title: ''
labels: bug
assignees: ''

---

**Describe the bug**
<!-- A clear and concise description of what the bug is. Make sure not to include private keys or live customer information. -->

**Software versions**
- dj-stripe version:
- Python version:
- Django version:
- Stripe API version:
- Database type and version:

**Steps To Reproduce**
<!-- Please tell us how to reproduce the issue. Use numbered steps. Make sure not to include private keys or live customer information. -->

**Can you reproduce the issue with the latest version of master?**
<!-- Yes or No -->

**Expected Behavior**
<!-- Please clearly and concisely describe what should happen after following the reproduction steps -->

**Actual Behavior**
<!-- Please clearly and concisely describe what actually happens after following the reproduction steps. Include a traceback if you have it, but ENSURE YOU REDACT IT  -->


================================================
FILE: .github/ISSUE_TEMPLATE/how-to-usage-question.md
================================================
---
name: How To/Usage Question
about: Have a question on how to use a dj-stripe feature?
title: How do I [short description]?
labels: question
assignees: ''

---

<!-- If this is an implementation-related question, you're probably better off asking it on StackOverflow and tagging it ``dj-stripe`` -->

**What are you trying to accomplish?**


================================================
FILE: .github/ISSUE_TEMPLATE/issue-with-webhooks-or-sync.md
================================================
---
name: Issue with webhooks or sync
about: For issues happening specifically when data is being synced from Stripe to
  Dj-Stripe
title: ''
labels: webhook / sync issues
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:

e.g.:

1. Enable stripe webhook to dj-stripe
2. In stripe dashboard create a billing product with feature X
3. See attached error on webhook

**Expected behavior**
A clear and concise description of what you expected to happen.

If relevant it's very helpful to include webhook tracebacks and content (note that these are logged in the database and are visible in django admin - eg http://127.0.0.1:8000/admin/djstripe/webhookeventtrigger/ )

**Environment**
- dj-stripe version: [e.g. master at <hash>, 2.0.0 etc]
- Your Stripe account's default API version: [e.g. 2019-02-19 - shown as "default" on https://dashboard.stripe.com/developers]
- Database: [e.g. MySQL 5.7.25]
- Python version: [e.g. 3.8.2]
- Django version: [e.g. 2.1.7]

**Can you reproduce the issue with the latest version of master?**

[Yes / No]


================================================
FILE: .github/ISSUE_TEMPLATE/migration-upgrade-issue.md
================================================
---
name: Migration/Upgrade Issue
about: Having trouble upgrading versions of dj-stripe? Let us know
title: Failure when attempting to upgrade from dj-strive [old version] to [new version]
labels: migrations
assignees: ''

---

**Software versions**
- Upgrading from dj-stripe version:
- Upgrading to dj-stripe version:
- Python version:
- Django version:
- Stripe API version:
- Database type and version:
- Failing migration id:

**Can you reproduce the issue with the latest version of master?**
<!-- Yes or No -->

**Describe the issue**
<!-- Please clearly and concisely describe what happens when attempting to upgrade Include a traceback if you have it, but ENSURE YOU REDACT IT.  -->


================================================
FILE: .github/ISSUE_TEMPLATE/other-issue.md
================================================
---
name: Other Issue
about: For anything else
title: ''
labels: ''
assignees: ''

---




================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!--

Thank you for your pull request!

Please adhere to the following guidelines:

- Clear, single-purpose, atomic commits with a short summary and a descriptive body.
- Make sure your code is tested, especially if it fixes bugs or introduces complexity.
- Document important changes in the changelog (Most recent file in docs/history/ folder)

Much appreciated!

-->


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  # Update Github actions in workflows
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "daily"


================================================
FILE: .github/install_poetry_action/action.yaml
================================================
name: Setup and install poetry
description: Install and Setup Poetry

inputs:
  POETRY_VERSION:
    required: true
    type: string
  python_version:
    required: true
    type: string


runs:
  using: "composite"
  steps:
      - name: Set up Python ${{ inputs.python_version }}
        uses: actions/setup-python@v4
        with:
          python-version: ${{ inputs.python_version }}

      - name: Install poetry (${{ inputs.POETRY_VERSION }}) binary on runner
        run: |
          curl -sL https://install.python-poetry.org | python - --version ${{ inputs.POETRY_VERSION }}
        shell: bash

      - name: Set up cache
        uses: actions/cache@v3
        id: cache
        with:
          path: .venv
          key: venv-${{ inputs.python_version }}

      - name: Ensure cache is healthy
        if: steps.cache.outputs.cache-hit == 'true'
        run: timeout 10s poetry run pip --version || rm -rf .venv
        shell: bash


================================================
FILE: .github/workflows/ci.yml
================================================
name: CI tests

on:
  push:
    paths-ignore:
      - "docs/**"
      - "pyproject.toml"
      - "mkdocs.yml"
      - ".readthedocs.yml"
      - ".github/workflows/docs.yml"

  pull_request:
    # The branches below must be a subset of the branches above
    branches: [master]

env:
  POETRY_VERSION: "1.2.2"
  POETRY_VIRTUALENVS_IN_PROJECT: "1"

jobs:
  tests:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: true
      matrix:
        python-version: ["3.8", "3.9", "3.10", "3.11"]

    services:
      postgres:
        image: postgres:12
        env:
          POSTGRES_PASSWORD: djstripe
          POSTGRES_DB: djstripe
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
      mysql:
        image: mysql:5.7
        env:
          MYSQL_ROOT_PASSWORD: djstripe
          MYSQL_DATABASE: djstripe
        ports:
          - 3306:3306
        options: >-
          --health-cmd="mysqladmin ping"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
      - uses: actions/checkout@v3

      - uses: ./.github/install_poetry_action
        with:
            POETRY_VERSION: ${{ env.POETRY_VERSION }}
            python_version: ${{ matrix.python-version }}

      - name: Install dependencies
        run: poetry install --with ci

      - name: Test with tox for ${{ matrix.python-version }}
        run: poetry run tox

      - name: Convert coverage
        run: poetry run coverage xml


================================================
FILE: .github/workflows/codeql-analysis.yml
================================================
name: "CodeQL"

on:
  push:
    branches: [master]
  pull_request:
    # The branches below must be a subset of the branches above
    branches: [master]
  schedule:
    - cron: "0 11 * * 2"

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        # Override automatic language detection by changing the below list
        # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
        language: ["python"]
        # Learn more...
        # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      # Initializes the CodeQL tools for scanning.
      - name: Initialize CodeQL
        uses: github/codeql-action/init@v2
        with:
          languages: ${{ matrix.language }}
          # If you wish to specify custom queries, you can do so here or in a config file.
          # By default, queries listed here will override any specified in a config file.
          # Prefix the list here with "+" to use these queries and those in the config file.
          # queries: ./path/to/local/query, your-org/your-repo/queries@main

      # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
      # If this step fails, then you should remove it and run the build manually (see below)
      - name: Autobuild
        uses: github/codeql-action/autobuild@v2

      # ℹ️ Command-line programs to run using the OS shell.
      # 📚 https://git.io/JvXDl

      # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
      #    and modify them (or add more) to build your code if your project
      #    uses a compiled language

      #- run: |
      #   make bootstrap
      #   make release

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v2


================================================
FILE: .github/workflows/docs.yml
================================================
name: Build and deploy docs

on:
  push:
    branches:
      - "master"
      # Push events to branches matching "stable/*"
      - "stable/.+"

  workflow_dispatch: # to trigger manually

env:
  POETRY_VERSION: "1.2.2"
  POETRY_VIRTUALENVS_IN_PROJECT: "1"
  LATEST_STABLE_BRANCH: "stable/2.7"

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - uses: ./.github/install_poetry_action
        with:
            POETRY_VERSION: ${{ env.POETRY_VERSION }}
            python_version: "3.11"

      - name: Install dependencies
        run: poetry install --with docs

      - name: Configure git user to make commit
        run: |
          git config user.name "dj-stripe commit bot"
          git config user.email "admin@djstripe.dev"

      - name: Fetch gh-pages remote changes (if any)
        run: git fetch origin gh-pages --depth=1

      - name: Deploy (and Update) docs for the branch, ${GITHUB_REF##*/}
        run: poetry run mike deploy --push --rebase "${GITHUB_REF##*/}"

      - name: Set default docs to ${LATEST_STABLE_BRANCH##*/}
        run: poetry run mike set-default --push --rebase "${LATEST_STABLE_BRANCH##*/}"


================================================
FILE: .github/workflows/linting.yml
================================================
name: Linting

on:
  push:

  pull_request:
    # The branches below must be a subset of the branches above
    branches: [master]

env:
  POETRY_VERSION: "1.2.2"
  POETRY_VIRTUALENVS_IN_PROJECT: "1"


jobs:
  linting:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - uses: ./.github/install_poetry_action
        with:
            POETRY_VERSION: ${{ env.POETRY_VERSION }}
            python_version: "3.11"

      - name: Install pre-commit
        run: poetry install --with dev

      - name: Run pre-commit
        run: poetry run pre-commit run --all-files --show-diff-on-failure


================================================
FILE: .gitignore
================================================
*.py[cod]
__pycache__
.tox
dj_stripe.egg-info
*.mo

# Environments
.venv

# mkdocs
site/

# SQLite
*.sqlite3

# Coverage
/cover
.coverage

# Editor files
.vscode
.idea

# Do not commit Poetry lockfiles for libraries
poetry.lock


================================================
FILE: .pre-commit-config.yaml
================================================
exclude: ".git|.tox|.pytest_cache"
default_stages: [commit]
fail_fast: true

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: "v4.4.0"
    hooks:
      - id: check-builtin-literals
      - id: check-case-conflict
      - id: check-toml
      - id: check-yaml
      - id: end-of-file-fixer
      - id: trailing-whitespace

  - repo: https://github.com/psf/black
    rev: "23.1.0"
    hooks:
      - id: black

  - repo: https://github.com/timothycrosley/isort
    rev: "5.12.0"
    hooks:
      - id: isort

  - repo: https://github.com/adamchainz/django-upgrade
    rev: "1.12.0"
    hooks:
      - id: django-upgrade
        args: [--target-version, "3.2"]


================================================
FILE: .readthedocs.yml
================================================
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

version: 2
mkdocs:
  configuration: mkdocs.yml

python:
  version: "3.11"
  install:
    - method: pip
      path: .
      extra_requirements:
        - docs


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020 The @dj-stripe Organization

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: djstripe/__init__.py
================================================


================================================
FILE: djstripe/admin/__init__.py
================================================
from .admin import StripeModelAdmin

# Do not remove: This ensures loading of djstripe.admin.admin
__all__ = ["StripeModelAdmin"]


================================================
FILE: djstripe/admin/actions.py
================================================
"""
Django Administration Custom Actions Module
"""
from django.contrib import admin
from django.contrib.admin import helpers
from django.contrib.admin.utils import quote
from django.shortcuts import render
from django.urls import path, reverse
from django.utils.html import format_html
from django.utils.text import capfirst

from . import views
from .forms import CustomActionForm


class CustomActionMixin:
    # So that actions get shown even if there are 0 instances
    # https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.show_full_result_count
    show_full_result_count = False

    def get_urls(self):
        custom_urls = [
            path(
                "action/<str:action_name>/<str:model_name>/",
                self.admin_site.admin_view(views.ConfirmCustomAction.as_view()),
                name="djstripe_custom_action",
            ),
        ]
        return custom_urls + super().get_urls()

    def get_admin_action_context(self, queryset, action_name, form_class):
        context = {
            "action_name": action_name,
            "model_name": self.model._meta.model_name,
            "info": [],
            "queryset": queryset,
            "changelist_url": reverse(
                f"admin:{self.model._meta.app_label}_{self.model._meta.model_name}_changelist"
            ),
            "ACTION_CHECKBOX_NAME": helpers.ACTION_CHECKBOX_NAME,
            "form": form_class(
                initial={
                    helpers.ACTION_CHECKBOX_NAME: queryset.values_list("pk", flat=True)
                },
                model_name=self.model._meta.model_name,
                action_name=action_name,
            ),
        }

        if action_name == "_sync_all_instances":
            context["form"] = form_class(
                initial={helpers.ACTION_CHECKBOX_NAME: [action_name]},
                model_name=self.model._meta.model_name,
                action_name=action_name,
            )

        else:
            for obj in queryset:
                admin_url = reverse(
                    f"admin:{obj._meta.app_label}_{obj._meta.model_name}_change",
                    None,
                    (quote(obj.pk),),
                )
                context["info"].append(
                    format_html(
                        '{}: <a href="{}">{}</a>',
                        capfirst(obj._meta.verbose_name),
                        admin_url,
                        obj,
                    )
                )
        return context

    def get_actions(self, request):
        """
        Returns _resync_instances only for
        models with a defined model.stripe_class.retrieve
        """
        actions = super().get_actions(request)

        # ensure we return "_resync_instances" ONLY for
        # models that have a GET method
        if not getattr(self.model.stripe_class, "retrieve", None):
            actions.pop("_resync_instances", None)

        return actions

    @admin.action(description="Re-Sync Selected Instances")
    def _resync_instances(self, request, queryset):
        """Admin Action to resync selected instances"""
        context = self.get_admin_action_context(
            queryset, "_resync_instances", CustomActionForm
        )
        return render(request, "djstripe/admin/confirm_action.html", context)

    @admin.action(description="Sync All Instances for all API Keys")
    def _sync_all_instances(self, request, queryset):
        """Admin Action to Sync All Instances"""
        context = self.get_admin_action_context(
            queryset, "_sync_all_instances", CustomActionForm
        )
        return render(request, "djstripe/admin/confirm_action.html", context)

    def changelist_view(self, request, extra_context=None):
        # we fool it into thinking we have selected some query
        # since we need to sync all instances
        post = request.POST.copy()
        if (
            helpers.ACTION_CHECKBOX_NAME not in post
            and post.get("action") == "_sync_all_instances"
        ):
            post[helpers.ACTION_CHECKBOX_NAME] = None
            request._set_post(post)
        return super().changelist_view(request, extra_context)


================================================
FILE: djstripe/admin/admin.py
================================================
"""
Django Administration interface definitions
"""
from typing import Any, Dict

from django.contrib import admin
from django.db import IntegrityError, transaction
from django.shortcuts import render
from stripe.error import InvalidRequestError

from djstripe import models

from .actions import CustomActionMixin
from .admin_inline import (
    InvoiceItemInline,
    LineItemInline,
    SubscriptionInline,
    SubscriptionItemInline,
    SubscriptionScheduleInline,
    TaxIdInline,
)
from .filters import CustomerHasSourceListFilter, CustomerSubscriptionStatusListFilter
from .forms import (
    APIKeyAdminCreateForm,
    CustomActionForm,
    WebhookEndpointAdminCreateForm,
    WebhookEndpointAdminEditForm,
)
from .utils import ReadOnlyMixin, get_forward_relation_fields_for_model


@admin.register(models.IdempotencyKey)
class IdempotencyKeyAdmin(ReadOnlyMixin, admin.ModelAdmin):
    list_display = ("uuid", "action", "created", "is_expired", "livemode")
    list_filter = ("livemode",)
    search_fields = ("uuid", "action")


@admin.register(models.WebhookEventTrigger)
class WebhookEventTriggerAdmin(ReadOnlyMixin, admin.ModelAdmin):
    list_display = (
        "created",
        "event",
        "stripe_trigger_account",
        "webhook_endpoint",
        "remote_ip",
        "processed",
        "valid",
        "exception",
        "djstripe_version",
    )
    list_filter = ("created", "valid", "processed")
    list_select_related = ("event",)
    raw_id_fields = get_forward_relation_fields_for_model(models.WebhookEventTrigger)

    def reprocess(self, request, queryset):
        for trigger in queryset:
            if not trigger.valid:
                self.message_user(request, "Skipped invalid trigger {trigger!r}")
                continue

            trigger.process()

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .select_related("stripe_trigger_account", "event", "webhook_endpoint")
        )


class StripeModelAdmin(CustomActionMixin, admin.ModelAdmin):
    """Base class for all StripeModel-based model admins"""

    change_form_template = "djstripe/admin/change_form.html"
    add_form_template = "djstripe/admin/add_form.html"
    actions = ("_resync_instances", "_sync_all_instances")

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.raw_id_fields = get_forward_relation_fields_for_model(self.model)

    def get_list_display(self, request):
        return (
            ("__str__", "id", "djstripe_owner_account")
            + self.list_display
            + ("created", "livemode")
        )

    def get_list_filter(self, request):
        return self.list_filter + ("created", "livemode")

    def get_readonly_fields(self, request, obj=None):
        return self.readonly_fields + ("id", "djstripe_owner_account", "created")

    def get_search_fields(self, request):
        return self.search_fields + ("id",)

    def get_fieldsets(self, request, obj=None):
        common_fields = ("livemode", "id", "djstripe_owner_account", "created")
        # Have to remove the fields from the common set,
        # otherwise they'll show up twice.
        fields = [f for f in self.get_fields(request, obj) if f not in common_fields]
        return (
            (None, {"fields": common_fields}),
            (self.model.__name__, {"fields": fields}),
        )

    def get_queryset(self, request):
        return super().get_queryset(request).select_related("djstripe_owner_account")


@admin.register(models.Account)
class AccountAdmin(StripeModelAdmin):
    list_display = ("business_url", "country", "default_currency")
    list_filter = ("details_submitted",)
    search_fields = ("settings", "business_profile")


@admin.register(models.APIKey)
class APIKeyAdmin(admin.ModelAdmin):
    add_form_template = "djstripe/admin/add_form.html"
    change_form_template = "djstripe/admin/change_form.html"

    list_display = ("__str__", "type", "djstripe_owner_account", "livemode")
    readonly_fields = ("djstripe_owner_account", "livemode", "type", "secret")
    search_fields = ("name",)

    def get_readonly_fields(self, request, obj=None):
        if obj is None:
            return ["djstripe_owner_account", "livemode", "type"]
        return super().get_readonly_fields(request, obj=obj)

    def get_fields(self, request, obj=None):
        if obj is None:
            return APIKeyAdminCreateForm.Meta.fields
        return ["type", "djstripe_owner_account", "livemode", "name", "secret"]

    def get_form(self, request, obj=None, **kwargs):
        if obj is None:
            return APIKeyAdminCreateForm
        return super().get_form(request, obj, **kwargs)

    def get_queryset(self, request):
        return super().get_queryset(request).select_related("djstripe_owner_account")

    def save_model(self, request: Any, obj, form: Any, change: Any) -> None:
        try:
            # for non-existent Platform Accounts, because of Account._find_owner_account()
            # it will try to retrieve by api_key, Account.get_or_retrieve_for_api_key().
            # Account.get_or_retrieve_for_api_key will create this APIKey! This would cause
            # an IntegrityError as the APIKey gets created before this form gets saved
            with transaction.atomic():
                obj.save()
        except IntegrityError:
            pass


@admin.register(models.BalanceTransaction)
class BalanceTransactionAdmin(ReadOnlyMixin, StripeModelAdmin):
    list_display = (
        "type",
        "net",
        "amount",
        "fee",
        "currency",
        "available_on",
        "status",
    )
    list_filter = ("status", "type")


@admin.register(models.Charge)
class ChargeAdmin(StripeModelAdmin):
    list_display = (
        "customer",
        "amount",
        "invoice",
        "payment_method",
        "description",
        "paid",
        "disputed",
        "refunded",
        "fee",
    )

    search_fields = ("customer__id", "invoice__id")
    list_filter = ("status", "paid", "refunded", "captured")

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .select_related(
                "balance_transaction",
                "customer",
                "invoice",
                "payment_method",
                "payment_method__customer",
            )
        )


@admin.register(models.Coupon)
class CouponAdmin(StripeModelAdmin):
    list_display = (
        "amount_off",
        "percent_off",
        "duration",
        "duration_in_months",
        "redeem_by",
        "max_redemptions",
        "times_redeemed",
    )
    list_filter = ("duration", "redeem_by")
    radio_fields = {"duration": admin.HORIZONTAL}


@admin.register(models.Customer)
class CustomerAdmin(StripeModelAdmin):
    list_display = (
        "deleted",
        "subscriber",
        "email",
        "currency",
        "default_source",
        "default_payment_method",
        "coupon",
        "balance",
    )

    list_filter = (
        CustomerHasSourceListFilter,
        CustomerSubscriptionStatusListFilter,
        "deleted",
    )
    search_fields = ("email", "description", "deleted")
    inlines = (SubscriptionInline, SubscriptionScheduleInline, TaxIdInline)

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .select_related(
                "subscriber", "default_source", "default_payment_method", "coupon"
            )
        )


@admin.register(models.Discount)
class DiscountAdmin(ReadOnlyMixin, StripeModelAdmin):
    list_display = (
        "customer",
        "coupon",
        "invoice_item",
        "promotion_code",
        "subscription",
    )
    list_filter = ("customer", "start", "end", "promotion_code", "coupon")

    def get_actions(self, request):
        """
        Returns _resync_instances only for
        models with a defined model.stripe_class.retrieve
        """
        actions = super().get_actions(request)

        # remove "_sync_all_instances" as Discounts cannot be listed
        actions.pop("_sync_all_instances", None)

        return actions


@admin.register(models.Dispute)
class DisputeAdmin(ReadOnlyMixin, StripeModelAdmin):
    list_display = ("reason", "status", "amount", "currency", "is_charge_refundable")
    list_filter = ("is_charge_refundable", "reason", "status")


@admin.register(models.Event)
class EventAdmin(ReadOnlyMixin, StripeModelAdmin):
    list_display = ("type", "request_id")
    list_filter = ("type", "created")
    search_fields = ("request_id",)


@admin.register(models.File)
class FileAdmin(StripeModelAdmin):
    list_display = ("purpose", "size", "type")
    list_filter = ("purpose", "type")
    search_fields = ("filename",)


@admin.register(models.FileLink)
class FileLinkAdmin(StripeModelAdmin):
    list_display = ("url",)
    list_filter = ("expires_at",)

    def get_queryset(self, request):
        return super().get_queryset(request).select_related("file")


@admin.register(models.Order)
class OrderAdmin(StripeModelAdmin):
    list_display = (
        "amount_total",
        "customer",
        "status",
    )
    list_filter = (
        "customer",
        "status",
    )
    list_select_related = ("customer", "payment_intent")


@admin.register(models.PaymentIntent)
class PaymentIntentAdmin(StripeModelAdmin):
    list_display = (
        "on_behalf_of",
        "customer",
        "amount",
        "payment_method",
        "currency",
        "description",
        "amount_capturable",
        "amount_received",
        "receipt_email",
    )
    search_fields = ("customer__id", "invoice__id")

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .select_related(
                "customer", "payment_method", "payment_method__customer", "on_behalf_of"
            )
        )


@admin.register(models.Payout)
class PayoutAdmin(StripeModelAdmin):
    list_display = (
        "destination",
        "amount",
        "arrival_date",
        "method",
        "status",
        "type",
    )
    list_filter = ("destination__id",)
    search_fields = ("destination__id", "balance_transaction__id")

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .select_related("balance_transaction", "destination")
        )


@admin.register(models.SetupIntent)
class SetupIntentAdmin(StripeModelAdmin):
    list_display = (
        "created",
        "customer",
        "description",
        "on_behalf_of",
        "payment_method",
        "payment_method_types",
        "status",
    )
    list_filter = ("status",)
    search_fields = ("customer__id", "status")

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .select_related(
                "on_behalf_of",
                "customer",
                "customer__subscriber",
                "payment_method",
                "payment_method__customer",
            )
        )


@admin.register(models.Session)
class SessionAdmin(StripeModelAdmin):
    list_display = ("customer", "customer_email", "subscription")
    list_filter = ("customer", "mode")
    search_fields = ("customer__id", "customer_email")

    def get_queryset(self, request):
        return super().get_queryset(request).select_related("customer", "subscription")


@admin.register(models.Invoice)
class InvoiceAdmin(StripeModelAdmin):
    list_display = (
        "total",
        "get_default_tax_rates",
        "paid",
        "currency",
        "number",
        "customer",
        "due_date",
    )
    list_filter = (
        "status",
        "paid",
        "attempted",
        "created",
        "due_date",
        "period_start",
        "period_end",
    )
    search_fields = ("customer__id", "number", "receipt_number")
    inlines = (InvoiceItemInline,)

    @admin.display(description="Default Tax Rates")
    def get_default_tax_rates(self, obj):
        result = [str(tax_rate) for tax_rate in obj.default_tax_rates.all()]
        if result:
            return ", ".join(result)

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .select_related("customer")
            .prefetch_related("default_tax_rates")
        )


@admin.register(models.LineItem)
class LineItemAdmin(StripeModelAdmin):
    list_display = (
        "amount",
        "invoice_item",
        "subscription",
        "subscription_item",
        "type",
    )
    list_filter = ("type", "invoice_item", "subscription", "subscription_item")
    list_select_related = ("invoice_item", "subscription", "subscription_item")


@admin.register(models.Mandate)
class MandateAdmin(StripeModelAdmin):
    list_display = ("status", "type", "payment_method")
    list_filter = ("multi_use", "single_use")
    search_fields = ("payment_method__id",)

    def get_queryset(self, request):
        return super().get_queryset(request).select_related("payment_method")

    def get_actions(self, request):
        """
        Returns _resync_instances only for
        models with a defined model.stripe_class.retrieve
        """
        actions = super().get_actions(request)

        # remove "_sync_all_instances" as Mandates cannot be listed
        actions.pop("_sync_all_instances", None)

        return actions


@admin.register(models.Plan)
class PlanAdmin(StripeModelAdmin):
    radio_fields = {"interval": admin.HORIZONTAL}

    def get_readonly_fields(self, request, obj=None):
        """Return extra readonly_fields."""
        readonly_fields = super().get_readonly_fields(request, obj)

        if obj:
            readonly_fields += (
                "amount",
                "currency",
                "interval",
                "interval_count",
                "trial_period_days",
            )

        return readonly_fields

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .select_related("product")
            .prefetch_related("subscriptions")
        )


@admin.register(models.Price)
class PriceAdmin(StripeModelAdmin):
    list_display = ("product", "currency", "active")
    list_filter = ("active", "type", "billing_scheme", "tiers_mode")
    raw_id_fields = ("product",)
    search_fields = ("nickname",)
    radio_fields = {"type": admin.HORIZONTAL}

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .select_related("product")
            .prefetch_related("product__prices")
        )


@admin.register(models.Product)
class ProductAdmin(StripeModelAdmin):
    list_display = (
        "name",
        "default_price",
        "type",
        "active",
        "url",
        "statement_descriptor",
    )
    list_filter = ("type", "active", "shippable")
    search_fields = ("name", "statement_descriptor")

    def get_queryset(self, request):
        return super().get_queryset(request).prefetch_related("prices")


@admin.register(models.Refund)
class RefundAdmin(StripeModelAdmin):
    list_display = (
        "amount",
        "currency",
        "charge",
        "reason",
        "status",
        "failure_reason",
    )
    list_filter = ("reason", "status")
    search_fields = ("receipt_number",)

    def get_queryset(self, request):
        return super().get_queryset(request).select_related("charge")


@admin.register(models.Source)
class SourceAdmin(StripeModelAdmin):
    list_display = ("customer", "type", "status", "amount", "currency", "usage", "flow")
    list_filter = ("type", "status", "usage", "flow")

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .select_related("customer", "customer__subscriber")
        )


@admin.register(models.PaymentMethod)
class PaymentMethodAdmin(StripeModelAdmin):
    list_display = ("customer", "type", "billing_details")
    list_filter = ("type",)
    search_fields = ("customer__id",)

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .select_related("customer", "customer__subscriber")
        )


@admin.register(models.Card)
class CardAdmin(StripeModelAdmin):
    list_display = ("customer", "account")
    search_fields = ("customer__id", "account__id")

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .select_related(
                "customer",
                "customer__default_source",
                "customer__default_payment_method",
                "account",
            )
        )


@admin.register(models.BankAccount)
class BankAccountAdmin(StripeModelAdmin):
    list_display = ("customer", "account")
    search_fields = ("customer__id", "account__id")

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .select_related(
                "customer",
                "customer__default_source",
                "customer__default_payment_method",
                "account",
            )
        )


@admin.register(models.ShippingRate)
class ShippingRateAdmin(StripeModelAdmin):
    list_display = ("display_name", "active", "tax_behavior", "tax_code")
    list_filter = ("active", "tax_behavior")
    list_select_related = ("tax_code",)


@admin.register(models.Subscription)
class SubscriptionAdmin(StripeModelAdmin):
    list_display = ("customer", "status", "get_product_name", "get_default_tax_rates")
    list_filter = ("status", "cancel_at_period_end")

    inlines = (SubscriptionItemInline, SubscriptionScheduleInline, LineItemInline)

    def get_actions(self, request):
        # get all actions
        actions = super().get_actions(request)
        actions["_cancel"] = self.get_action("_cancel")
        return actions

    @admin.action(description="Cancel selected subscriptions")
    def _cancel(self, request, queryset):
        """Cancel a subscription."""
        context = self.get_admin_action_context(queryset, "_cancel", CustomActionForm)
        return render(request, "djstripe/admin/confirm_action.html", context)

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .select_related(
                "customer",
                "plan",
                "plan__product",
            )
            .prefetch_related(
                "customer__subscriptions",
                "customer__subscriptions__plan",
                "customer__subscriptions__plan__product",
                "default_tax_rates",
            )
        )

    @admin.display(description="Default Tax Rates")
    def get_default_tax_rates(self, obj):
        result = [str(tax_rate) for tax_rate in obj.default_tax_rates.all()]
        if result:
            return ", ".join(result)

    @admin.display(description="Product Name")
    def get_product_name(self, obj):
        if obj.plan and obj.plan.product:
            return obj.plan.product.name


@admin.register(models.SubscriptionSchedule)
class SubscriptionScheduleAdmin(StripeModelAdmin):
    list_display = ("status", "subscription", "current_phase", "customer")
    list_filter = ("status", "subscription", "customer")
    list_select_related = ("customer", "customer__subscriber", "subscription")

    @admin.display(description="Release Selected Subscription Schedules")
    def _release_subscription_schedule(self, request, queryset):
        """Release a SubscriptionSchedule."""
        context = self.get_admin_action_context(
            queryset, "_release_subscription_schedule", CustomActionForm
        )
        return render(request, "djstripe/admin/confirm_action.html", context)

    @admin.display(description="Cancel Selected Subscription Schedules")
    def _cancel_subscription_schedule(self, request, queryset):
        """Cancel a SubscriptionSchedule."""
        context = self.get_admin_action_context(
            queryset, "_cancel_subscription_schedule", CustomActionForm
        )
        return render(request, "djstripe/admin/confirm_action.html", context)

    def get_actions(self, request):
        # get all actions
        actions = super().get_actions(request)
        actions["_release_subscription_schedule"] = self.get_action(
            "_release_subscription_schedule"
        )
        actions["_cancel_subscription_schedule"] = self.get_action(
            "_cancel_subscription_schedule"
        )
        return actions


@admin.register(models.TaxCode)
class TaxCodeAdmin(StripeModelAdmin):
    list_display = ("name", "description")
    list_filter = ("name",)


@admin.register(models.TaxRate)
class TaxRateAdmin(StripeModelAdmin):
    list_display = ("active", "display_name", "inclusive", "jurisdiction", "percentage")
    list_filter = ("active", "inclusive", "jurisdiction")


@admin.register(models.Transfer)
class TransferAdmin(StripeModelAdmin):
    list_display = ("amount", "description")


@admin.register(models.TransferReversal)
class TransferReversalAdmin(StripeModelAdmin):
    list_display = ("amount", "transfer")


@admin.register(models.ApplicationFee)
class ApplicationFeeAdmin(StripeModelAdmin):
    list_display = ("amount", "account")


@admin.register(models.ApplicationFeeRefund)
class ApplicationFeeReversalAdmin(StripeModelAdmin):
    list_display = ("amount", "fee")


@admin.register(models.UsageRecord)
class UsageRecordAdmin(StripeModelAdmin):
    list_display = ("quantity", "subscription_item", "timestamp")

    def get_queryset(self, request):
        return super().get_queryset(request).select_related("subscription_item")

    def get_actions(self, request):
        """
        Returns _resync_instances only for
        models with a defined model.stripe_class.retrieve
        """
        actions = super().get_actions(request)

        # remove "_sync_all_instances" as UsageRecords cannot be listed
        actions.pop("_sync_all_instances", None)

        return actions


@admin.register(models.UsageRecordSummary)
class UsageRecordSummaryAdmin(StripeModelAdmin):
    list_display = ("invoice", "subscription_item", "total_usage")

    def get_queryset(self, request):
        return (
            super().get_queryset(request).select_related("invoice", "subscription_item")
        )


@admin.register(models.WebhookEndpoint)
class WebhookEndpointAdmin(CustomActionMixin, admin.ModelAdmin):
    change_form_template = "djstripe/admin/webhook_endpoint/change_form.html"
    delete_confirmation_template = (
        "djstripe/admin/webhook_endpoint/delete_confirmation.html"
    )
    add_form_template = "djstripe/admin/webhook_endpoint/add_form.html"
    readonly_fields = ("url",)
    list_display = (
        "__str__",
        "djstripe_owner_account",
        "livemode",
        "created",
        "api_version",
    )
    actions = ("_resync_instances", "_sync_all_instances")

    def get_actions(self, request):
        actions = super().get_actions(request)
        # Disable the mass-delete action for webhook endpoints.
        # We don't want to enable deleting multiple endpoints on Stripe at once.
        if "delete_selected" in actions:
            del actions["delete_selected"]
        return actions

    def get_form(self, request, obj=None, **kwargs):
        if obj:
            return WebhookEndpointAdminEditForm
        return WebhookEndpointAdminCreateForm

    def get_readonly_fields(self, request, obj=None):
        if obj:
            return (
                "id",
                "livemode",
                "api_version",
                "url",
                "created",
                "djstripe_owner_account",
                "djstripe_uuid",
            )
        return super().get_readonly_fields(request, obj=obj)

    def get_fieldsets(self, request, obj=None):
        if obj:
            # if djstripe_uuid is null, this is not a dj-stripe webhook
            header_fields = ["id", "livemode", "djstripe_owner_account", "url"]
            advanced_fields = [
                "enabled_events",
                "metadata",
                "api_version",
                "djstripe_uuid",
            ]
            if obj.djstripe_uuid:
                core_fields = ["enabled", "base_url", "description"]
            else:
                core_fields = ["enabled", "description"]
        else:
            header_fields = ["djstripe_owner_account", "livemode"]
            core_fields = ["description", "base_url", "connect"]
            advanced_fields = ["metadata", "api_version", "enabled_events"]

        return [
            (None, {"fields": header_fields}),
            ("Endpoint configuration", {"fields": core_fields}),
            (
                "Advanced",
                {"fields": advanced_fields, "classes": ["collapse"]},
            ),
        ]

    def get_changeform_initial_data(self, request) -> Dict[str, str]:
        ret = super().get_changeform_initial_data(request)
        base_url = f"{request.scheme}://{request.get_host()}"
        ret.setdefault("base_url", base_url)
        return ret

    def delete_model(self, request, obj: models.WebhookEndpoint):
        try:
            obj._api_delete()
        except InvalidRequestError as e:
            if e.user_message.startswith("No such webhook endpoint: "):
                # Webhook was already deleted in Stripe
                pass
            else:
                raise

        return super().delete_model(request, obj)

    def get_queryset(self, request):
        return super().get_queryset(request).select_related("djstripe_owner_account")


================================================
FILE: djstripe/admin/admin_inline.py
================================================
"""
Django Administration Inline interface definitions
"""
from django.contrib import admin

from djstripe import models

from .utils import get_forward_relation_fields_for_model


class SubscriptionInline(admin.StackedInline):
    """A TabularInline for use models.Subscription."""

    model = models.Subscription
    extra = 0
    readonly_fields = ("id", "created", "djstripe_owner_account")
    raw_id_fields = get_forward_relation_fields_for_model(model)
    show_change_link = True


class SubscriptionScheduleInline(admin.StackedInline):
    """A TabularInline for use models.SubscriptionSchedule."""

    model = models.SubscriptionSchedule
    extra = 0
    readonly_fields = ("id", "created", "djstripe_owner_account")
    raw_id_fields = get_forward_relation_fields_for_model(model)
    show_change_link = True

    def __init__(self, parent_model, admin_site):
        super().__init__(parent_model, admin_site)

        # dynamically set fk_name as SubscriptionScheduleInline is used
        # in CustomerAdmin as well as SubscriptionAdmin
        if parent_model is models.Subscription:
            self.fk_name = "subscription"


class TaxIdInline(admin.TabularInline):
    """A TabularInline for use models.Subscription."""

    model = models.TaxId
    extra = 0
    max_num = 5
    readonly_fields = (
        "id",
        "created",
        "verification",
        "livemode",
        "country",
        "djstripe_owner_account",
    )
    show_change_link = True


class SubscriptionItemInline(admin.StackedInline):
    """A TabularInline for use models.Subscription."""

    model = models.SubscriptionItem
    extra = 0
    readonly_fields = ("id", "created", "djstripe_owner_account")
    raw_id_fields = get_forward_relation_fields_for_model(model)
    show_change_link = True


class InvoiceItemInline(admin.StackedInline):
    """A TabularInline for use InvoiceItem."""

    model = models.InvoiceItem
    extra = 0
    readonly_fields = ("id", "created", "djstripe_owner_account")
    raw_id_fields = get_forward_relation_fields_for_model(model)
    show_change_link = True


class LineItemInline(admin.StackedInline):
    """A TabularInline for LineItem."""

    model = models.LineItem
    extra = 0
    readonly_fields = ("id", "created", "djstripe_owner_account")
    raw_id_fields = get_forward_relation_fields_for_model(model)
    show_change_link = True


================================================
FILE: djstripe/admin/filters.py
================================================
"""
Django Administration Custom Filters Module
"""
from django.contrib import admin

from djstripe import models


class BaseHasSourceListFilter(admin.SimpleListFilter):
    title = "source presence"
    parameter_name = "has_source"

    def lookups(self, request, model_admin):
        """
        Return a list of tuples.

        The first element in each tuple is the coded value for the option that will
        appear in the URL query. The second element is the
        human-readable name for the option that will appear
        in the right sidebar.
        source:
        https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
        """
        return (("yes", "Has a source"), ("no", "Has no source"))

    def queryset(self, request, queryset):
        """
        Return the filtered queryset based on the value provided in the query string.

        source:
        https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
        """
        filter_args = {self._filter_arg_key: None}

        if self.value() == "yes":
            return queryset.exclude(**filter_args)
        if self.value() == "no":
            return queryset.filter(**filter_args)


class CustomerHasSourceListFilter(BaseHasSourceListFilter):
    _filter_arg_key = "default_source"


class InvoiceCustomerHasSourceListFilter(BaseHasSourceListFilter):
    _filter_arg_key = "customer__default_source"


class CustomerSubscriptionStatusListFilter(admin.SimpleListFilter):
    """A SimpleListFilter used with Customer admin."""

    title = "subscription status"
    parameter_name = "sub_status"

    def lookups(self, request, model_admin):
        """
        Return a list of tuples.

        The first element in each tuple is the coded value for the option that will
        appear in the URL query. The second element is the
        human-readable name for the option that will appear
        in the right sidebar.
        source:
        https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
        """
        statuses = [
            [x, x.replace("_", " ").title()]
            for x in models.Subscription.objects.values_list(
                "status", flat=True
            ).distinct()
        ]
        statuses.append(["none", "No Subscription"])
        return statuses

    def queryset(self, request, queryset):
        """
        Return the filtered queryset based on the value provided in the query string.

        source:
        https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
        """
        if self.value() is None:
            return queryset.all()
        else:
            return queryset.filter(subscriptions__status=self.value()).distinct()


================================================
FILE: djstripe/admin/forms.py
================================================
"""
Module for all dj-stripe Admin app forms
"""
from typing import Optional
from urllib.parse import urljoin

from django import forms
from django.contrib.admin import helpers
from django.urls import reverse
from stripe.error import AuthenticationError, InvalidRequestError

from djstripe import enums, models, utils
from djstripe.signals import ENABLED_EVENTS


class CustomActionForm(forms.Form):
    """Form for Custom Django Admin Actions"""

    def __init__(self, *args, **kwargs):
        # remove model_name kwarg
        model_name = kwargs.pop("model_name")

        # remove action_name kwarg
        action_name = kwargs.pop("action_name")

        super().__init__(*args, **kwargs)

        model = utils.get_model(model_name)
        # set choices attribute
        # form field to keep track of all selected instances
        # for the Custom Django Admin Action

        if action_name == "_sync_all_instances":
            self.fields[helpers.ACTION_CHECKBOX_NAME] = forms.MultipleChoiceField(
                widget=forms.MultipleHiddenInput,
                choices=[(action_name, action_name)],
            )
        else:
            self.fields[helpers.ACTION_CHECKBOX_NAME] = forms.MultipleChoiceField(
                widget=forms.MultipleHiddenInput,
                choices=zip(
                    model.objects.values_list("pk", flat=True),
                    model.objects.values_list("pk", flat=True),
                ),
            )


class APIKeyAdminCreateForm(forms.ModelForm):
    class Meta:
        model = models.APIKey
        fields = ["name", "secret"]

    def _post_clean(self):
        super()._post_clean()

        if not self.errors:
            if (
                self.instance.type == enums.APIKeyType.secret
                and self.instance.djstripe_owner_account is None
            ):
                try:
                    self.instance.refresh_account()
                except AuthenticationError as e:
                    self.add_error("secret", str(e))


class WebhookEndpointAdminBaseForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["description"].help_text = ""
        self.fields["description"].widget.attrs["rows"] = 3

    def _get_field_name(self, stripe_field: Optional[str]) -> Optional[str]:
        if stripe_field is None:
            return None
        if stripe_field == "url":
            return "base_url"
        else:
            return stripe_field.partition("[")[0]

    def save(self, commit: bool = False):
        # If we do the following in _post_clean(), the data doesn't save properly.
        if not self._stripe_data:
            raise ValueError("_stripe_data is not present. ")

        # Update scenario
        # Add back secret if endpoint already exists
        if self.instance.pk and not self._stripe_data.get("secret"):
            self._stripe_data["secret"] = self.instance.secret

        # Retrieve the api key that was used to create the endpoint
        api_key = getattr(self, "_stripe_api_key", None)
        if api_key:
            self.instance = models.WebhookEndpoint.sync_from_stripe_data(
                self._stripe_data, api_key=api_key
            )
        else:
            self.instance = models.WebhookEndpoint.sync_from_stripe_data(
                self._stripe_data
            )
        return super().save(commit=commit)


class WebhookEndpointAdminCreateForm(WebhookEndpointAdminBaseForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["djstripe_owner_account"].label = "Stripe account"
        self.fields["djstripe_owner_account"].help_text = ""

    enabled_events = forms.MultipleChoiceField(
        label="Enabled Events",
        required=True,
        help_text=(
            "The list of events to enable for this endpoint. "
            "['*'] indicates that all events are enabled, except those that require explicit selection."
        ),
        choices=zip(ENABLED_EVENTS, ENABLED_EVENTS),
        initial=["*"],
    )
    livemode = forms.BooleanField(
        label="Live mode",
        required=False,
        help_text="Whether to create this endpoint in live mode or test mode",
    )
    base_url = forms.URLField(
        required=True,
        help_text=(
            "Sets the base URL (scheme and host) for the endpoint. "
            "The final full URL will be auto-generated by dj-stripe."
        ),
    )
    connect = forms.BooleanField(
        label="Listen to events on Connected accounts",
        initial=False,
        required=False,
        help_text=(
            "Clients can make requests as connected accounts using the special "
            "header `Stripe-Account` which should contain a Stripe account ID "
            "(usually starting with the prefix `acct_`)."
        ),
    )

    class Meta:
        model = models.WebhookEndpoint
        fields = (
            "enabled_events",
            "livemode",
            "djstripe_owner_account",
            "description",
            "base_url",
            "connect",
            "api_version",
            "metadata",
        )

    # Hook into _post_clean() instead of save().
    # This is used by Django for ModelForm logic. It's internal, but exactly
    # what we need to add errors after the data has been validated locally.
    def _post_clean(self):
        base_url = self.cleaned_data["base_url"]
        url_path = reverse(
            "djstripe:djstripe_webhook_by_uuid",
            kwargs={"uuid": self.instance.djstripe_uuid},
        )
        url = urljoin(base_url, url_path, allow_fragments=False)

        metadata = self.instance.metadata or {}
        metadata["djstripe_uuid"] = str(self.instance.djstripe_uuid)

        _api_key = {}
        account = self.cleaned_data["djstripe_owner_account"]
        livemode = self.cleaned_data["livemode"]
        if account:
            self._stripe_api_key = _api_key["api_key"] = account.get_default_api_key(
                livemode=livemode
            )

        try:
            self._stripe_data = models.WebhookEndpoint._api_create(
                url=url,
                api_version=self.cleaned_data["api_version"] or None,
                description=self.cleaned_data["description"],
                enabled_events=self.cleaned_data.get("enabled_events"),
                metadata=metadata,
                connect=self.cleaned_data["connect"],
                **_api_key,
            )
        except InvalidRequestError as e:
            field_name = self._get_field_name(e.param)
            self.add_error(field_name, e.user_message)

        return super()._post_clean()


class WebhookEndpointAdminEditForm(WebhookEndpointAdminBaseForm):
    enabled_events = forms.MultipleChoiceField(
        label="Enabled Events",
        required=True,
        help_text=(
            "The list of events to enable for this endpoint. "
            "['*'] indicates that all events are enabled, except those that require explicit selection."
        ),
        choices=zip(ENABLED_EVENTS, ENABLED_EVENTS),
    )
    base_url = forms.URLField(
        required=False,
        help_text=(
            "Updating this changes the base URL of the endpoint. "
            "MUST be publicly-accessible."
        ),
    )
    enabled = forms.BooleanField(
        initial=True,
        required=False,
        help_text="When disabled, the endpoint will not receive events.",
    )

    class Meta:
        model = models.WebhookEndpoint
        fields = ("description", "base_url", "enabled_events", "metadata")

    def get_initial_for_field(self, field, field_name):
        if field_name == "base_url":
            metadata = self.instance.metadata or {}
            djstripe_uuid = metadata.get("djstripe_uuid")
            if djstripe_uuid:
                # if a djstripe_uuid is set (for dj-stripe endpoints), set the base_url
                endpoint_path = reverse(
                    "djstripe:djstripe_webhook_by_uuid", kwargs={"uuid": djstripe_uuid}
                )
                return self.instance.url.replace(endpoint_path, "")
        return super().get_initial_for_field(field, field_name)

    def _post_clean(self):
        base_url = self.cleaned_data.get("base_url", "")
        if base_url and self.instance.djstripe_uuid:
            url_path = reverse(
                "djstripe:djstripe_webhook_by_uuid",
                kwargs={"uuid": self.instance.djstripe_uuid},
            )
            url = urljoin(base_url, url_path, allow_fragments=False)
        else:
            url = self.instance.url

        try:
            self._stripe_data = self.instance._api_update(
                url=url,
                description=self.cleaned_data.get("description"),
                enabled_events=self.cleaned_data.get("enabled_events"),
                metadata=self.cleaned_data.get("metadata"),
                disabled=(not self.cleaned_data.get("enabled")),
            )
        except InvalidRequestError as e:
            field_name = self._get_field_name(e.param)
            self.add_error(field_name, e.user_message)

        return super()._post_clean()


================================================
FILE: djstripe/admin/utils.py
================================================
"""
Django Administration Utils Module
"""


class ReadOnlyMixin:
    def has_add_permission(self, request):
        return False

    def has_change_permission(self, request, obj=None):
        return False


def get_forward_relation_fields_for_model(model):
    """Return an iterable of the field names that are forward relations,
    I.E ManyToManyField, OneToOneField, and ForeignKey.

    Useful for perhaps ensuring the admin is always using raw ID fields for
    newly added forward relation fields.
    """
    return [
        field.name
        for field in model._meta.get_fields()
        # Get only relation fields
        if field.is_relation
        # Exclude auto relation fields, like reverse one to one.
        and not field.auto_created
        # We only want forward relations.
        and any((field.many_to_many, field.one_to_one, field.many_to_one))
    ]


================================================
FILE: djstripe/admin/views.py
================================================
"""
dj-stripe - Views related to the djstripe app.
"""
import logging

import stripe
from django.contrib import messages
from django.contrib.admin import helpers, site
from django.core.management import call_command
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views.generic import FormView

from djstripe import utils

from .forms import CustomActionForm

logger = logging.getLogger(__name__)


class ConfirmCustomAction(FormView):
    template_name = "djstripe/admin/confirm_action.html"
    form_class = CustomActionForm

    def form_valid(self, form):
        model_name = self.kwargs.get("model_name")
        action_name = self.kwargs.get("action_name")
        model = utils.get_model(model_name)

        pks = form.cleaned_data.get(helpers.ACTION_CHECKBOX_NAME)

        # get the handler
        handler = getattr(self, action_name)

        if action_name == "_sync_all_instances":
            # Create Empty Queryset to be able to extract the model name
            # as sync all would sync all instances anyway and there is no guarantee
            # that the local db already has all the instances.
            qs = model.objects.none()
        else:
            qs = utils.get_queryset(pks, model_name)

        # Process Request
        handler(self.request, qs)

        return HttpResponseRedirect(
            reverse(
                f"admin:{model._meta.app_label}_{model._meta.model_name}_changelist"
            )
        )

    def form_invalid(self, form):
        model_name = self.kwargs.get("model_name")
        action_name = self.kwargs.get("action_name")

        model = utils.get_model(model_name)
        pks = form.data.getlist(helpers.ACTION_CHECKBOX_NAME)
        pks = list(map(int, pks))

        queryset = utils.get_queryset(pks, model_name)

        model_admin = site._registry.get(model)
        for msg in form.errors.values():
            messages.add_message(self.request, messages.ERROR, msg.as_text())

        return model_admin.get_action(action_name)[0](
            model_admin, self.request, queryset
        )

    def get_form_kwargs(self):
        form_kwargs = super().get_form_kwargs()
        form_kwargs["model_name"] = self.kwargs.get("model_name")
        form_kwargs["action_name"] = self.kwargs.get("action_name")
        return form_kwargs

    def _resync_instances(self, request, queryset):
        for instance in queryset:
            api_key = instance.default_api_key
            try:
                if instance.djstripe_owner_account:
                    stripe_data = instance.api_retrieve(
                        stripe_account=instance.djstripe_owner_account.id,
                        api_key=api_key,
                    )
                else:
                    stripe_data = instance.api_retrieve()
                instance.__class__.sync_from_stripe_data(stripe_data, api_key=api_key)
                messages.success(request, f"Successfully Synced: {instance}")
            except stripe.error.PermissionError as error:
                messages.warning(request, error)
            except stripe.error.InvalidRequestError:
                raise

    def _sync_all_instances(self, request, queryset):
        """Admin Action to Sync All Instances"""
        call_command("djstripe_sync_models", queryset.model.__name__)
        messages.success(request, "Successfully Synced All Instances")

    def _cancel(self, request, queryset):
        """Cancel a subscription."""
        for subscription in queryset:
            try:
                instance = subscription.cancel()
                messages.success(request, f"Successfully Canceled: {instance}")
            except stripe.error.InvalidRequestError as error:
                messages.warning(request, error)

    def _release_subscription_schedule(self, request, queryset):
        """Release a SubscriptionSchedule."""
        for subscription_schedule in queryset:
            try:
                instance = subscription_schedule.release()
                messages.success(request, f"Successfully Released: {instance}")
            except stripe.error.InvalidRequestError as error:
                messages.warning(request, error)

    def _cancel_subscription_schedule(self, request, queryset):
        """Cancel a SubscriptionSchedule."""
        for subscription_schedule in queryset:
            try:
                instance = subscription_schedule.cancel()
                messages.success(request, f"Successfully Canceled: {instance}")
            except stripe.error.InvalidRequestError as error:
                messages.warning(request, error)


================================================
FILE: djstripe/apps.py
================================================
"""
dj-stripe - Django + Stripe Made Easy
"""
import pkg_resources
from django.apps import AppConfig

__version__ = pkg_resources.get_distribution("dj-stripe").version


class DjstripeAppConfig(AppConfig):
    """
    An AppConfig for dj-stripe which loads system checks
    and event handlers once Django is ready.
    """

    name = "djstripe"
    default_auto_field = "django.db.models.AutoField"

    def ready(self):
        import stripe

        from . import checks, event_handlers  # noqa (register event handlers)

        # Set app info
        # https://stripe.com/docs/building-plugins#setappinfo
        stripe.set_app_info(
            "dj-stripe",
            version=__version__,
            url="https://github.com/dj-stripe/dj-stripe",
        )


================================================
FILE: djstripe/checks.py
================================================
"""
dj-stripe System Checks
"""
import re

from django.core import checks
from django.db.utils import DatabaseError

STRIPE_API_VERSION_PATTERN = re.compile(
    r"(?P<year>\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})(; [\w=]*)?$"
)


# 4 possibilities:
# Keys in admin and in settings
# Keys in admin and not in settings
# Keys not in admin but in settings
# Keys not in admin and not in settings
@checks.register("djstripe")
def check_stripe_api_key(app_configs=None, **kwargs):
    """Check the user has configured API live/test keys correctly."""

    def _check_stripe_api_in_settings(messages):
        if djstripe_settings.STRIPE_LIVE_MODE:
            if not djstripe_settings.LIVE_API_KEY.startswith(("sk_live_", "rk_live_")):
                msg = "Bad Stripe live API key."
                hint = 'STRIPE_LIVE_SECRET_KEY should start with "sk_live_"'
                messages.append(checks.Info(msg, hint=hint, id="djstripe.I003"))
        elif not djstripe_settings.TEST_API_KEY.startswith(("sk_test_", "rk_test_")):
            msg = "Bad Stripe test API key."
            hint = 'STRIPE_TEST_SECRET_KEY should start with "sk_test_"'
            messages.append(checks.Info(msg, hint=hint, id="djstripe.I004"))

    from djstripe.models import APIKey

    from .settings import djstripe_settings

    messages = []

    try:
        # get all APIKey objects in the db
        api_qs = APIKey.objects.all()

        if not api_qs.exists():
            msg = "You don't have any API Keys in the database. Did you forget to add them?"
            hint = "Add STRIPE_TEST_SECRET_KEY and STRIPE_LIVE_SECRET_KEY directly from the Django Admin."
            messages.append(checks.Info(msg, hint=hint, id="djstripe.I001"))

            # Keys not in admin but in settings
            if djstripe_settings.STRIPE_SECRET_KEY:
                msg = "Your keys are defined in the settings files. You can now add and manage them directly from the django admin."
                hint = "Add STRIPE_TEST_SECRET_KEY and STRIPE_LIVE_SECRET_KEY directly from the Django Admin."
                messages.append(checks.Info(msg, hint=hint, id="djstripe.I002"))

                # Ensure keys defined in settings files are valid
                _check_stripe_api_in_settings(messages)

        # Keys in admin and in settings
        elif djstripe_settings.STRIPE_SECRET_KEY:
            msg = "Your keys are defined in the settings files and are also in the admin. You can now add and manage them directly from the django admin."
            hint = "We suggest adding STRIPE_TEST_SECRET_KEY and STRIPE_LIVE_SECRET_KEY directly from the Django Admin. And removing them from the settings files."
            messages.append(checks.Info(msg, hint=hint, id="djstripe.I002"))

            # Ensure keys defined in settings files are valid
            _check_stripe_api_in_settings(messages)

    except DatabaseError:
        # Skip the check - Database most likely not migrated yet
        return []

    return messages


def validate_stripe_api_version(version):
    """
    Check the API version is formatted correctly for Stripe.

    The expected format is `YYYY-MM-DD` (an iso8601 date) or
    for access to alpha or beta releases the expected format is: `YYYY-MM-DD; modelname_version=version_number`.
    Ex "2020-08-27; orders_beta=v3"

    :param version: The version to set for the Stripe API.
    :type version: ``str``
    :returns bool: Whether the version is formatted correctly.
    """
    return re.match(STRIPE_API_VERSION_PATTERN, version)


@checks.register("djstripe")
def check_stripe_api_version(app_configs=None, **kwargs):
    """Check the user has configured API version correctly."""
    from .settings import djstripe_settings

    messages = []
    default_version = djstripe_settings.DEFAULT_STRIPE_API_VERSION
    version = djstripe_settings.STRIPE_API_VERSION

    if not validate_stripe_api_version(version):
        msg = f"Invalid Stripe API version: {version!r}"
        hint = "STRIPE_API_VERSION should be formatted as: YYYY-MM-DD"
        messages.append(checks.Critical(msg, hint=hint, id="djstripe.C004"))

    if version != default_version:
        msg = (
            f"The Stripe API version has a non-default value of '{version!r}'. "
            "Non-default versions are not explicitly supported, and may "
            "cause compatibility issues."
        )
        hint = f"Use the dj-stripe default for Stripe API version: {default_version}"
        messages.append(checks.Warning(msg, hint=hint, id="djstripe.W001"))

    return messages


@checks.register("djstripe")
def check_stripe_api_host(app_configs=None, **kwargs):
    """
    Check that STRIPE_API_HOST is not being used in production.
    """
    from django.conf import settings

    messages = []

    if not settings.DEBUG and hasattr(settings, "STRIPE_API_HOST"):
        messages.append(
            checks.Warning(
                "STRIPE_API_HOST should not be set in production! "
                "This is most likely unintended.",
                hint="Remove STRIPE_API_HOST from your Django settings.",
                id="djstripe.W002",
            )
        )

    return messages


@checks.register("djstripe")
def check_webhook_secret(app_configs=None, **kwargs):
    """
    Check that DJSTRIPE_WEBHOOK_SECRET looks correct
    """

    def check_webhook_endpoint_secret(secret, messages, endpoint=None):
        if secret and not secret.startswith("whsec_"):
            if endpoint:
                extra_msg = (
                    f"The secret for Webhook Endpoint: {endpoint} does not look valid"
                )
            else:
                extra_msg = "DJSTRIPE_WEBHOOK_SECRET does not look valid"

            messages.append(
                checks.Warning(
                    extra_msg,
                    hint="It should start with whsec_...",
                    id="djstripe.W003",
                )
            )
        return messages

    from .models import WebhookEndpoint
    from .settings import djstripe_settings

    messages = []
    try:
        webhooks = list(WebhookEndpoint.objects.all())
    except DatabaseError:
        # skip the db-based check (db most likely not migrated yet)
        webhooks = []

    if webhooks:
        for endpoint in webhooks:
            secret = endpoint.secret
            # check secret
            check_webhook_endpoint_secret(secret, messages, endpoint=endpoint)
    else:
        secret = djstripe_settings.WEBHOOK_SECRET
        # check secret
        check_webhook_endpoint_secret(secret, messages)

    return messages


def _check_webhook_endpoint_validation(secret, messages, endpoint=None):
    if not secret:
        if endpoint:
            extra_msg = f"but Webhook Endpoint: {endpoint} has no secret set"
            secret_attr = "secret"
        else:
            extra_msg = "but DJSTRIPE_WEBHOOK_SECRET is not set"
            secret_attr = "DJSTRIPE_WEBHOOK_SECRET"

        messages.append(
            checks.Info(
                f"DJSTRIPE_WEBHOOK_VALIDATION is set to 'verify_signature' {extra_msg}",
                hint=f"Set {secret_attr} from Django shell or set DJSTRIPE_WEBHOOK_VALIDATION='retrieve_event'",
                id="djstripe.I006",
            )
        )
    return messages


@checks.register("djstripe")
def check_webhook_validation(app_configs=None, **kwargs):
    """
    Check that DJSTRIPE_WEBHOOK_VALIDATION is valid
    """
    from .models import WebhookEndpoint
    from .settings import djstripe_settings

    setting_name = "DJSTRIPE_WEBHOOK_VALIDATION"

    messages = []

    validation_options = ("verify_signature", "retrieve_event")

    if djstripe_settings.WEBHOOK_VALIDATION is None:
        messages.append(
            checks.Warning(
                "Webhook validation is disabled, this is a security risk if the "
                "webhook view is enabled",
                hint=f"Set {setting_name} to one of: {validation_options}",
                id="djstripe.W004",
            )
        )
    elif djstripe_settings.WEBHOOK_VALIDATION == "verify_signature":
        try:
            webhooks = list(WebhookEndpoint.objects.all())
        except DatabaseError:
            # Skip the db-based check (database most likely not migrated yet)
            webhooks = []

        if webhooks:
            for endpoint in webhooks:
                secret = endpoint.secret
                # check secret
                _check_webhook_endpoint_validation(secret, messages, endpoint=endpoint)
        else:
            secret = djstripe_settings.WEBHOOK_SECRET
            # check secret
            _check_webhook_endpoint_validation(secret, messages)

    elif djstripe_settings.WEBHOOK_VALIDATION not in validation_options:
        messages.append(
            checks.Critical(
                f"{setting_name} is invalid",
                hint=f"Set {setting_name} to one of: {validation_options} or None",
                id="djstripe.C007",
            )
        )

    return messages


@checks.register("djstripe")
def check_webhook_endpoint_has_secret(app_configs=None, **kwargs):
    """Checks if all Webhook Endpoints have not empty secrets."""
    from djstripe.models import WebhookEndpoint

    messages = []

    try:
        qs = list(WebhookEndpoint.objects.filter(secret="").all())
    except DatabaseError:
        # Skip the check - Database most likely not migrated yet
        return []

    for webhook in qs:
        webhook_url = webhook.get_stripe_dashboard_url()
        messages.append(
            checks.Warning(
                (
                    f"The secret of Webhook Endpoint: {webhook} is not populated "
                    "in the db. Events sent to it will not work properly."
                ),
                hint=(
                    "This can happen if it was deleted and resynced as Stripe "
                    "sends the webhook secret ONLY on the creation call. "
                    "Please use the django shell and update the secret with "
                    f"the value from {webhook_url}"
                ),
                id="djstripe.W005",
            )
        )

    return messages


@checks.register("djstripe")
def check_subscriber_key_length(app_configs=None, **kwargs):
    """
    Check that DJSTRIPE_SUBSCRIBER_CUSTOMER_KEY fits in metadata.

    Docs: https://stripe.com/docs/api#metadata
    """
    from .settings import djstripe_settings

    messages = []

    key = djstripe_settings.SUBSCRIBER_CUSTOMER_KEY
    key_max_length = 40
    if key and len(key) > key_max_length:
        messages.append(
            checks.Error(
                "DJSTRIPE_SUBSCRIBER_CUSTOMER_KEY must be no more than "
                f"{key_max_length} characters long",
                hint=f"Current value: {key!r}",
                id="djstripe.E001",
            )
        )

    return messages


@checks.register("djstripe")
def check_djstripe_settings_foreign_key_to_field(app_configs=None, **kwargs):
    """
    Check that DJSTRIPE_FOREIGN_KEY_TO_FIELD is set to a valid value.
    """
    from django.conf import settings

    setting_name = "DJSTRIPE_FOREIGN_KEY_TO_FIELD"
    hint = (
        f'Set {setting_name} to "id" if this is a new installation, '
        f'otherwise set it to "djstripe_id".'
    )
    messages = []

    if not hasattr(settings, setting_name):
        messages.append(
            checks.Error(
                f"{setting_name} is not set.",
                hint=hint,
                id="djstripe.E002",
            )
        )
    elif getattr(settings, setting_name) not in ("id", "djstripe_id"):
        setting_value = getattr(settings, setting_name)
        messages.append(
            checks.Error(
                f"{setting_value} is not a valid value for {setting_name}.",
                hint=hint,
                id="djstripe.E003",
            )
        )

    return messages


@checks.register("djstripe")
def check_webhook_event_callback_accepts_api_key(app_configs=None, **kwargs):
    """
    Checks if the custom callback accepts atleast 2 mandatory positional arguments
    """
    from inspect import signature

    from .settings import djstripe_settings

    messages = []

    # callable can have exactly 2 arguments or
    # if more than two, the rest need to be optional.
    callable = djstripe_settings.WEBHOOK_EVENT_CALLBACK

    if callable:
        # Deprecated in 2.8.0. Raise a warning.
        messages.append(
            checks.Warning(
                "DJSTRIPE_WEBHOOK_EVENT_CALLBACK is deprecated. See release notes for details.",
                hint=(
                    "If you need to trigger a function during webhook processing, "
                    "you can use djstripe.signals instead.\n"
                    "Available signals:\n"
                    "- djstripe.signals.webhook_pre_validate\n"
                    "- djstripe.signals.webhook_post_validate\n"
                    "- djstripe.signals.webhook_pre_process\n"
                    "- djstripe.signals.webhook_post_process\n"
                    "- djstripe.signals.webhook_processing_error"
                ),
            )
        )

        sig = signature(callable)
        signature_sz = len(sig.parameters.keys())

        if signature_sz < 2:
            messages.append(
                checks.Error(
                    f"{callable} accepts {signature_sz} arguments.",
                    hint="You may have forgotten to add api_key parameter to your custom callback.",
                    id="djstripe.E004",
                )
            )

    return messages


================================================
FILE: djstripe/enums.py
================================================
import operator
from collections import OrderedDict

from django.utils.translation import gettext_lazy as _


class EnumMetaClass(type):
    def __init__(cls, name, bases, classdict):
        def _human_enum_values(enum):
            return cls.__choices__[enum]

        # add a class attribute
        cls.humanize = _human_enum_values

    @classmethod
    def __prepare__(cls, name, bases):
        return OrderedDict()

    def __new__(cls, name, bases, classdict):
        members = []
        keys = {}
        choices = OrderedDict()
        for key, value in classdict.items():
            if key.startswith("__"):
                continue
            members.append(key)
            if isinstance(value, tuple):
                value, alias = value
                keys[alias] = key
            else:
                alias = None
            keys[alias or key] = key
            choices[alias or key] = value

        for k, v in keys.items():
            classdict[v] = k

        classdict["__choices__"] = choices
        classdict["__members__"] = members

        # Note: Differences between Python 2.x and Python 3.x force us to
        # explicitly use unicode here, and to explicitly sort the list. In
        # Python 2.x, class members are unordered and so the ordering will
        # vary on different systems based on internal hashing. Without this
        # Django will continually require new no-op migrations.
        classdict["choices"] = tuple(
            (str(k), str(v))
            for k, v in sorted(choices.items(), key=operator.itemgetter(0))
        )

        return type.__new__(cls, name, bases, classdict)


class Enum(metaclass=EnumMetaClass):
    pass


class APIKeyType(Enum):
    """
    API Key Types (internal model only)
    """

    publishable = _("Publishable key")
    secret = _("Secret key")
    restricted = _("Restricted key")


class ApiErrorCode(Enum):
    """
    Charge failure error codes.

    https://stripe.com/docs/error-codes
    """

    account_already_exists = _("Account already exists")
    account_country_invalid_address = _("Account country invalid address")
    account_invalid = _("Account invalid")
    account_number_invalid = _("Account number invalid")
    alipay_upgrade_required = _("Alipay upgrade required")
    amount_too_large = _("Amount too large")
    amount_too_small = _("Amount too small")
    api_key_expired = _("Api key expired")
    balance_insufficient = _("Balance insufficient")
    bank_account_exists = _("Bank account exists")
    bank_account_unusable = _("Bank account unusable")
    bank_account_unverified = _("Bank account unverified")
    bitcoin_upgrade_required = _("Bitcoin upgrade required")
    card_declined = _("Card was declined")
    charge_already_captured = _("Charge already captured")
    charge_already_refunded = _("Charge already refunded")
    charge_disputed = _("Charge disputed")
    charge_exceeds_source_limit = _("Charge exceeds source limit")
    charge_expired_for_capture = _("Charge expired for capture")
    country_unsupported = _("Country unsupported")
    coupon_expired = _("Coupon expired")
    customer_max_subscriptions = _("Customer max subscriptions")
    email_invalid = _("Email invalid")
    expired_card = _("Expired card")
    idempotency_key_in_use = _("Idempotency key in use")
    incorrect_address = _("Incorrect address")
    incorrect_cvc = _("Incorrect security code")
    incorrect_number = _("Incorrect number")
    incorrect_zip = _("ZIP code failed validation")
    instant_payouts_unsupported = _("Instant payouts unsupported")
    invalid_card_type = _("Invalid card type")
    invalid_charge_amount = _("Invalid charge amount")
    invalid_cvc = _("Invalid security code")
    invalid_expiry_month = _("Invalid expiration month")
    invalid_expiry_year = _("Invalid expiration year")
    invalid_number = _("Invalid number")
    invalid_source_usage = _("Invalid source usage")
    invoice_no_customer_line_items = _("Invoice no customer line items")
    invoice_no_subscription_line_items = _("Invoice no subscription line items")
    invoice_not_editable = _("Invoice not editable")
    invoice_upcoming_none = _("Invoice upcoming none")
    livemode_mismatch = _("Livemode mismatch")
    missing = _("No card being charged")
    not_allowed_on_standard_account = _("Not allowed on standard account")
    order_creation_failed = _("Order creation failed")
    order_required_settings = _("Order required settings")
    order_status_invalid = _("Order status invalid")
    order_upstream_timeout = _("Order upstream timeout")
    out_of_inventory = _("Out of inventory")
    parameter_invalid_empty = _("Parameter invalid empty")
    parameter_invalid_integer = _("Parameter invalid integer")
    parameter_invalid_string_blank = _("Parameter invalid string blank")
    parameter_invalid_string_empty = _("Parameter invalid string empty")
    parameter_missing = _("Parameter missing")
    parameter_unknown = _("Parameter unknown")
    parameters_exclusive = _("Parameters exclusive")
    payment_intent_authentication_failure = _("Payment intent authentication failure")
    payment_intent_incompatible_payment_method = _(
        "Payment intent incompatible payment method"
    )
    payment_intent_invalid_parameter = _("Payment intent invalid parameter")
    payment_intent_payment_attempt_failed = _("Payment intent payment attempt failed")
    payment_intent_unexpected_state = _("Payment intent unexpected state")
    payment_method_unactivated = _("Payment method unactivated")
    payment_method_unexpected_state = _("Payment method unexpected state")
    payouts_not_allowed = _("Payouts not allowed")
    platform_api_key_expired = _("Platform api key expired")
    postal_code_invalid = _("Postal code invalid")
    processing_error = _("Processing error")
    product_inactive = _("Product inactive")
    rate_limit = _("Rate limit")
    resource_already_exists = _("Resource already exists")
    resource_missing = _("Resource missing")
    routing_number_invalid = _("Routing number invalid")
    secret_key_required = _("Secret key required")
    sepa_unsupported_account = _("SEPA unsupported account")
    shipping_calculation_failed = _("Shipping calculation failed")
    sku_inactive = _("SKU inactive")
    state_unsupported = _("State unsupported")
    tax_id_invalid = _("Tax id invalid")
    taxes_calculation_failed = _("Taxes calculation failed")
    testmode_charges_only = _("Testmode charges only")
    tls_version_unsupported = _("TLS version unsupported")
    token_already_used = _("Token already used")
    token_in_use = _("Token in use")
    transfers_not_allowed = _("Transfers not allowed")
    upstream_order_creation_failed = _("Upstream order creation failed")
    url_invalid = _("URL invalid")

    # deprecated
    invalid_swipe_data = _("Invalid swipe data")


class AccountType(Enum):
    standard = _("Standard")
    express = _("Express")
    custom = _("Custom")


class BalanceTransactionReportingCategory(Enum):
    """
    https://stripe.com/docs/reports/reporting-categories
    """

    advance = _("Advance")
    advance_funding = _("Advance funding")
    anticipation_repayment = _("Anticipation loan repayment (BR)")
    charge = _("Charge")
    charge_failure = _("Charge failure")
    connect_collection_transfer = _("Stripe Connect collection transfer")
    connect_reserved_funds = _("Stripe Connect reserved funds")
    dispute = _("Dispute")
    dispute_reversal = _("Dispute reversal")
    fee = _("Stripe fee")
    issuing_authorization_hold = _("Issuing authorization hold")
    issuing_authorization_release = _("Issuing authorization release")
    issuing_dispute = _("Issuing dispute")
    issuing_transaction = _("Issuing transaction")
    other_adjustment = _("Other adjustment")
    partial_capture_reversal = _("Partial capture reversal")
    payout = _("Payout")
    payout_reversal = _("Payout reversal")
    platform_earning = _("Stripe Connect platform earning")
    platform_earning_refund = _("Stripe Connect platform earning refund")
    refund = _("Refund")
    refund_failure = _("Refund failure")
    risk_reserved_funds = _("Risk-reserved funds")
    tax = _("Tax")
    topup = _("Top-up")
    topup_reversal = _("Top-up reversal")
    transfer = _("Stripe Connect transfer")
    transfer_reversal = _("Stripe Connect transfer reversal")


class BalanceTransactionStatus(Enum):
    available = _("Available")
    pending = _("Pending")


class BalanceTransactionType(Enum):
    # https://stripe.com/docs/reports/balance-transaction-types
    adjustment = _("Adjustment")
    advance = _("Advance")
    advance_funding = _("Advance funding")
    anticipation_repayment = _("Anticipation loan repayment")
    application_fee = _("Application fee")
    application_fee_refund = _("Application fee refund")
    balance_transfer_inbound = _("Balance transfer (inbound)")
    balance_transfer_outbound = _("Balance transfer (outbound)")
    charge = _("Charge")
    connect_collection_transfer = _("Connect collection transfer")
    contribution = _("Charitable contribution")
    issuing_authorization_hold = _("Issuing authorization hold")
    issuing_authorization_release = _("Issuing authorization release")
    issuing_dispute = _("Issuing dispute")
    issuing_transaction = _("Issuing transaction")
    network_cost = _("Network cost")
    payment = _("Payment")
    payment_failure_refund = _("Payment failure refund")
    payment_refund = _("Payment refund")
    payout = _("Payout")
    payout_cancel = _("Payout cancellation")
    payout_failure = _("Payout failure")
    refund = _("Refund")
    refund_failure = _("Refund failure")
    reserve_transaction = _("Reserve transaction")
    reserved_funds = _("Reserved funds")
    stripe_fee = _("Stripe fee")
    stripe_fx_fee = _("Stripe currency conversion fee")
    tax_fee = _("Tax fee")
    topup = _("Topup")
    topup_reversal = _("Topup reversal")
    transfer = _("Transfer")
    transfer_cancel = _("Transfer cancel")
    transfer_failure = _("Transfer failure")
    transfer_refund = _("Transfer refund")
    validation = _("Validation")


class BankAccountHolderType(Enum):
    individual = _("Individual")
    company = _("Company")


class BankAccountStatus(Enum):
    new = _("New")
    validated = _("Validated")
    verified = _("Verified")
    verification_failed = _("Verification failed")
    errored = _("Errored")


class BillingScheme(Enum):
    per_unit = _("Per-unit")
    tiered = _("Tiered")


class BusinessType(Enum):
    individual = _("Individual")
    company = _("Company")
    non_profit = _("Non Profit")
    government_entity = _("Government Entity")


class CaptureMethod(Enum):
    automatic = _("Automatic")
    manual = _("Manual")


class CardCheckResult(Enum):
    pass_ = (_("Pass"), "pass")
    fail = _("Fail")
    unavailable = _("Unavailable")
    unchecked = _("Unchecked")


class CardBrand(Enum):
    AmericanExpress = (_("American Express"), "American Express")
    DinersClub = (_("Diners Club"), "Diners Club")
    Discover = _("Discover")
    JCB = _("JCB")
    MasterCard = _("MasterCard")
    UnionPay = _("UnionPay")
    Visa = _("Visa")
    Unknown = _("Unknown")


class CardFundingType(Enum):
    credit = _("Credit")
    debit = _("Debit")
    prepaid = _("Prepaid")
    unknown = _("Unknown")


class CardTokenizationMethod(Enum):
    apple_pay = _("Apple Pay")
    android_pay = _("Android Pay")


class ChargeStatus(Enum):
    succeeded = _("Succeeded")
    pending = _("Pending")
    failed = _("Failed")


class ConfirmationMethod(Enum):
    automatic = _("Automatic")
    manual = _("Manual")


class CouponDuration(Enum):
    once = _("Once")
    repeating = _("Multi-month")
    forever = _("Forever")


class CustomerTaxExempt(Enum):
    none = _("None")
    exempt = _("Exempt")
    reverse = _("Reverse")


class DisputeReason(Enum):
    duplicate = _("Duplicate")
    fraudulent = _("Fraudulent")
    subscription_canceled = _("Subscription canceled")
    product_unacceptable = _("Product unacceptable")
    product_not_received = _("Product not received")
    unrecognized = _("Unrecognized")
    credit_not_processed = _("Credit not processed")
    general = _("General")
    incorrect_account_details = _("Incorrect account details")
    insufficient_funds = _("Insufficient funds")
    bank_cannot_process = _("Bank cannot process")
    debit_not_authorized = _("Debit not authorized")
    customer_initiated = _("Customer-initiated")


class DisputeStatus(Enum):
    warning_needs_response = _("Warning needs response")
    warning_under_review = _("Warning under review")
    warning_closed = _("Warning closed")
    needs_response = _("Needs response")
    under_review = _("Under review")
    charge_refunded = _("Charge refunded")
    won = _("Won")
    lost = _("Lost")


class FilePurpose(Enum):
    account_requirement = _("Account requirement")
    additional_verification = _("Additional verification")
    business_icon = _("Business icon")
    business_logo = _("Business logo")
    customer_signature = _("Customer signature")
    credit_note = _("Credit Note")
    dispute_evidence = _("Dispute evidence")
    document_provider_identity_document = _("Document provider identity document")
    finance_report_run = _("Finance report run")
    identity_document = _("Identity document")
    identity_document_downloadable = _("Identity document (downloadable)")
    invoice_statement = _("Invoice statement")
    pci_document = _("PCI document")
    selfie = _("Selfie (Stripe Identity)")
    sigma_scheduled_query = _("Sigma scheduled query")
    tax_document_user_upload = _("Tax document user upload")


class FileType(Enum):
    pdf = _("PDF")
    jpg = _("JPG")
    png = _("PNG")
    csv = _("CSV")
    xls = _("XLS")
    xlsx = _("XLSX")
    docx = _("DOCX")


class InvoiceBillingReason(Enum):
    subscription_cycle = _("Subscription cycle")
    subscription_create = _("Subscription create")
    subscription_update = _("Subscription update")
    subscription = _("Subscription")
    manual = _("Manual")
    upcoming = _("Upcoming")
    subscription_threshold = _("Subscription threshold")
    automatic_pending_invoice_item_invoice = _("Automatic pending invoice item invoice")


class InvoiceCollectionMethod(Enum):
    charge_automatically = _("Charge automatically")
    send_invoice = _("Send invoice")


class InvoiceStatus(Enum):
    draft = _("Draft")
    open = _("Open")
    paid = _("Paid")
    uncollectible = _("Uncollectible")
    void = _("Void")


class InvoiceorLineItemType(Enum):
    invoice_item = _("Invoice Item")
    line_item = _("Line Item")
    unsupported = _("Unsupported")


class IntentUsage(Enum):
    on_session = _("On session")
    off_session = _("Off session")


class IntentStatus(Enum):
    """
    Status of Intents which apply both to PaymentIntents
    and SetupIntents.
    """

    requires_payment_method = _(
        "Intent created and requires a Payment Method to be attached."
    )
    requires_confirmation = _("Intent is ready to be confirmed.")
    requires_action = _("Payment Method require additional action, such as 3D secure.")
    processing = _("Required actions have been handled.")
    canceled = _(
        "Cancellation invalidates the intent for future confirmation and "
        "cannot be undone."
    )


class LineItem(Enum):
    invoiceitem = _("Invoice Item")
    subscription = _("Subscription")


class MandateStatus(Enum):
    active = _("Active")
    inactive = _("Inactive")
    pending = _("Pending")


class MandateType(Enum):
    multi_use = _("Multi-use")
    single_use = _("Single-use")


class OrderStatus(Enum):
    open = _("Open")
    submitted = _("Submitted")
    processing = _("Processing")
    complete = _("Complete")
    canceled = _("Canceled")


# TODO - maybe refactor Enum so that inheritance works,
#  then PaymentIntentStatus/SetupIntentStatus can inherit from IntentStatus
class PaymentIntentStatus(Enum):
    requires_payment_method = _(
        "Intent created and requires a Payment Method to be attached."
    )
    requires_confirmation = _("Intent is ready to be confirmed.")
    requires_action = _("Payment Method require additional action, such as 3D secure.")
    processing = _("Required actions have been handled.")
    requires_capture = _("Capture the funds on the cards which have been put on holds.")
    canceled = _(
        "Cancellation invalidates the intent for future confirmation and "
        "cannot be undone."
    )
    succeeded = _("The funds are in your account.")


class SetupIntentStatus(Enum):
    requires_payment_method = _(
        "Intent created and requires a Payment Method to be attached."
    )
    requires_confirmation = _("Intent is ready to be confirmed.")
    requires_action = _("Payment Method require additional action, such as 3D secure.")
    processing = _("Required actions have been handled.")
    canceled = _(
        "Cancellation invalidates the intent for future confirmation and "
        "cannot be undone."
    )
    succeeded = _(
        "Setup was successful and the payment method is optimized for future payments."
    )


class PaymentMethodType(Enum):
    acss_debit = _("Acss Dbit")
    affirm = _("Affirm")
    afterpay_clearpay = _("Afterpay Clearpay")
    alipay = _("Alipay")
    au_becs_debit = _("BECS Debit (Australia)")
    bacs_debit = _("Bacs Direct Debit")
    bancontact = _("Bancontact")
    blik = _("BLIK")
    boleto = _("Boleto")
    card = _("Card")
    card_present = _("Card present")
    customer_balance = _("Customer Balance")
    eps = _("EPS")
    fpx = _("FPX")
    giropay = _("Giropay")
    grabpay = _("Grabpay")
    ideal = _("iDEAL")
    interac_present = _("Interac (card present)")
    klarna = _("Klarna")
    konbini = _("Konbini")
    link = _("Link")
    oxxo = _("OXXO")
    p24 = _("Przelewy24")
    paynow = _("PayNow")
    pix = _("Pix")
    promptpay = _("PromptPay")
    sepa_debit = _("SEPA Direct Debit")
    sofort = _("SOFORT")
    us_bank_account = _("ACH Direct Debit")
    wechat_pay = _("Wechat Pay")


class PayoutFailureCode(Enum):
    """
    Payout failure error codes.

    https://stripe.com/docs/api#payout_failures
    """

    account_closed = _("Bank account has been closed.")
    account_frozen = _("Bank account has been frozen.")
    bank_account_restricted = _("Bank account has restrictions on payouts allowed.")
    bank_ownership_changed = _("Destination bank account has changed ownership.")
    could_not_process = _("Bank could not process payout.")
    debit_not_authorized = _("Debit transactions not approved on the bank account.")
    declined = _(
        "The bank has declined this transfer. Please contact the bank before retrying."
    )
    insufficient_funds = _("Stripe account has insufficient funds.")
    invalid_account_number = _("Invalid account number")
    incorrect_account_holder_name = _(
        "Your bank notified us that the bank account holder name on file is incorrect."
    )
    incorrect_account_holder_address = _(
        "Your bank notified us that the bank account holder address on file is incorrect."
    )
    incorrect_account_holder_tax_id = _(
        "Your bank notified us that the bank account holder tax ID on file is incorrect."
    )
    invalid_currency = _("Bank account does not support currency.")
    no_account = _("Bank account could not be located.")
    unsupported_card = _("Card no longer supported.")


class PayoutMethod(Enum):
    standard = _("Standard")
    instant = _("Instant")


class PayoutSourceType(Enum):
    bank_account = _("Bank account")
    fpx = _("Financial Process Exchange (FPX)")
    card = _("Card")


class PayoutStatus(Enum):
    paid = _("Paid")
    pending = _("Pending")
    in_transit = _("In transit")
    canceled = _("Canceled")
    failed = _("Failed")


class PayoutType(Enum):
    bank_account = _("Bank account")
    card = _("Card")


class PaymentIntentCancellationReason(Enum):
    # see also SetupIntentCancellationReason
    # User provided reasons:
    duplicate = _("Duplicate")
    fraudulent = _("Fraudulent")
    abandoned = _("Abandoned")
    requested_by_customer = _("Requested by Customer")
    # Reasons generated by Stripe internally
    failed_invoice = _("Failed invoice")
    void_invoice = _("Void invoice")
    automatic = _("Automatic")


class PlanAggregateUsage(Enum):
    last_during_period = _("Last during period")
    last_ever = _("Last ever")
    max = _("Max")
    sum = _("Sum")


class PlanInterval(Enum):
    day = _("Day")
    week = _("Week")
    month = _("Month")
    year = _("Year")


class PriceTiersMode(Enum):
    graduated = _("Graduated")
    volume = _("Volume-based")


class PriceType(Enum):
    one_time = _("One-time")
    recurring = _("Recurring")


class PriceUsageType(Enum):
    metered = _("Metered")
    licensed = _("Licensed")


# Legacy
PlanTiersMode = PriceTiersMode
PlanUsageType = PriceUsageType


class ProductType(Enum):
    good = _("Good")
    service = _("Service")


class SetupIntentCancellationReason(Enum):
    # see also PaymentIntentCancellationReason
    abandoned = _("Abandoned")
    requested_by_customer = _("Requested by Customer")
    duplicate = _("Duplicate")


class ScheduledQueryRunStatus(Enum):
    canceled = _("Canceled")
    failed = _("Failed")
    timed_out = _("Timed out")


class SourceFlow(Enum):
    redirect = _("Redirect")
    receiver = _("Receiver")
    code_verification = _("Code verification")
    none = _("None")


class SourceStatus(Enum):
    canceled = _("Canceled")
    chargeable = _("Chargeable")
    consumed = _("Consumed")
    failed = _("Failed")
    pending = _("Pending")


class SourceType(Enum):
    ach_credit_transfer = _("ACH Credit Transfer")
    ach_debit = _("ACH Debit")
    acss_debit = _("ACSS Debit")
    alipay = _("Alipay")
    au_becs_debit = _("BECS Debit (AU)")
    bancontact = _("Bancontact")
    bitcoin = _("Bitcoin (Legacy)")
    card = _("Card")
    card_present = _("Card present")
    eps = _("EPS")
    giropay = _("Giropay")
    ideal = _("iDEAL")
    klarna = _("Klarna")
    multibanco = _("Multibanco")
    p24 = _("P24")
    paper_check = _("Paper check")
    sepa_credit_transfer = _("SEPA credit transfer")
    sepa_debit = _("SEPA Direct Debit")
    sofort = _("SOFORT")
    three_d_secure = _("3D Secure")
    wechat = _("WeChat")


class LegacySourceType(Enum):
    card = _("Card")
    bank_account = _("Bank account")
    bitcoin_receiver = _("Bitcoin receiver")
    alipay_account = _("Alipay account")


class RefundFailureReason(Enum):
    lost_or_stolen_card = _("Lost or stolen card")
    expired_or_canceled_card = _("Expired or canceled card")
    unknown = _("Unknown")


class RefundReason(Enum):
    duplicate = _("Duplicate charge")
    fraudulent = _("Fraudulent")
    requested_by_customer = _("Requested by customer")
    expired_uncaptured_charge = _("Expired uncaptured charge")


class RefundStatus(Enum):
    pending = _("Pending")
    succeeded = _("Succeeded")
    failed = _("Failed")
    canceled = _("Canceled")


class SessionBillingAddressCollection(Enum):
    auto = _("Auto")
    required = _("Required")


class SessionMode(Enum):
    payment = _("Payment")
    setup = _("Setup")
    subscription = _("Subscription")


class SourceUsage(Enum):
    reusable = _("Reusable")
    single_use = _("Single-use")


class SourceCodeVerificationStatus(Enum):
    pending = _("Pending")
    succeeded = _("Succeeded")
    failed = _("Failed")


class SourceRedirectFailureReason(Enum):
    user_abort = _("User-aborted")
    declined = _("Declined")
    processing_error = _("Processing error")


class SourceRedirectStatus(Enum):
    pending = _("Pending")
    succeeded = _("Succeeded")
    not_required = _("Not required")
    failed = _("Failed")


class SubmitTypeStatus(Enum):
    auto = _("Auto")
    book = _("Book")
    donate = _("donate")
    pay = _("pay")


class SubscriptionScheduleEndBehavior(Enum):
    release = _("Release")
    cancel = _("Cancel")


class SubscriptionScheduleStatus(Enum):
    not_started = _("Not started")
    active = _("Active")
    completed = _("Completed")
    released = _("Released")
    canceled = _("Canceled")


class SubscriptionStatus(Enum):
    incomplete = _("Incomplete")
    incomplete_expired = _("Incomplete Expired")
    trialing = _("Trialing")
    active = _("Active")
    past_due = _("Past due")
    canceled = _("Canceled")
    unpaid = _("Unpaid")


class SubscriptionProrationBehavior(Enum):
    create_prorations = _("Create prorations")
    always_invoice = _("Always invoice")
    none = _("None")


class ShippingRateType(Enum):
    fixed_amount = _("Fixed Amount")


class ShippingRateTaxBehavior(Enum):
    inclusive = _("Inclusive")
    exclusive = _("Exclusive")
    unspecified = _("Unspecified")


class TaxIdType(Enum):
    ae_trn = _("AE TRN")
    au_abn = _("AU ABN")
    br_cnp = _("BR CNP")
    br_cpf = _("BR CPF")
    ca_bn = _("CA BN")
    ca_qst = _("CA QST")
    ch_vat = _("CH VAT")
    cl_tin = _("CL TIN")
    es_cif = _("ES CIF")
    eu_vat = _("EU VAT")
    hk_br = _("HK BR")
    id_npw = _("ID NPW")
    in_gst = _("IN GST")
    jp_cn = _("JP CN")
    jp_rn = _("JP RN")
    kr_brn = _("KR BRN")
    li_uid = _("LI UID")
    mx_rfc = _("MX RFC")
    my_frp = _("MY FRP")
    my_itn = _("MY ITN")
    my_sst = _("MY SST")
    no_vat = _("NO VAT")
    nz_gst = _("NZ GST")
    ru_inn = _("RU INN")
    ru_kpp = _("RU KPP")
    sa_vat = _("SA VAT")
    sg_gst = _("SG GST")
    sg_uen = _("SG UEN")
    th_vat = _("TH VAT")
    tw_vat = _("TW VAT")
    us_ein = _("US EIN")
    za_vat = _("ZA VAT")
    unknown = _("Unknown")


class UsageAction(Enum):
    increment = _("increment")
    set = _("set")


class WebhookEndpointStatus(Enum):
    enabled = _("enabled")
    disabled = _("disabled")


class DjstripePaymentMethodType(Enum):
    """
    A djstripe-specific enum for the DjStripePaymentMethod model.
    """

    alipay_account = _("Alipay account")
    card = _("Card")
    bank_account = _("Bank account")
    source = _("Source")


================================================
FILE: djstripe/event_handlers.py
================================================
"""
Webhook event handlers for the various models

Stripe docs for Events: https://stripe.com/docs/api/events
Stripe docs for Webhooks: https://stripe.com/docs/webhooks

TODO: Implement webhook event handlers for all the models that need to
      respond to webhook events.

NOTE:
    Event data is not guaranteed to be in the correct API version format.
    See #116. When writing a webhook handler, make sure to first
    re-retrieve the object you wish to process.

"""
import logging
from enum import Enum

from django.core.exceptions import ObjectDoesNotExist

from djstripe.settings import djstripe_settings

from . import models, webhooks
from .enums import PayoutType, SourceType
from .utils import convert_tstamp

logger = logging.getLogger(__name__)


def update_customer_helper(metadata, customer_id, subscriber_key):
    """
    A helper function that updates customer's subscriber and metadata fields
    """

    # only update customer.subscriber if both the customer and subscriber already exist
    subscriber_id = metadata.get(subscriber_key, "")
    if subscriber_key not in ("", None) and subscriber_id and customer_id:
        subscriber_model = djstripe_settings.get_subscriber_model()

        try:
            subscriber = subscriber_model.objects.get(id=subscriber_id)
            customer = models.Customer.objects.get(id=customer_id)
        except ObjectDoesNotExist:
            pass
        else:
            customer.subscriber = subscriber
            customer.metadata = metadata
            customer.save()


@webhooks.handler("customer")
def customer_webhook_handler(event):
    """Handle updates to customer objects.

    First determines the crud_type and then handles the event if a customer
    exists locally.
    As customers are tied to local users, djstripe will not create customers that
    do not already exist locally.

    And updates to the subscriber model and metadata fields of customer if present
    in checkout.sessions metadata key.

    Docs and an example customer webhook response:
    https://stripe.com/docs/api#customer_object
    """
    # will recieve all events of the type customer.X.Y so
    # need to ensure the data object is related to Customer Object
    target_object_type = event.data.get("object", {}).get("object", {})

    if event.customer and target_object_type == "customer":
        metadata = event.data.get("object", {}).get("metadata", {})
        customer_id = event.data.get("object", {}).get("id", "")
        subscriber_key = djstripe_settings.SUBSCRIBER_CUSTOMER_KEY

        # only update customer.subscriber if both the customer and subscriber already exist
        update_customer_helper(metadata, customer_id, subscriber_key)

        _handle_crud_like_event(target_cls=models.Customer, event=event)


@webhooks.handler("customer.discount")
def customer_discount_webhook_handler(event):
    """Handle updates to customer discount objects.

    Docs: https://stripe.com/docs/api#discounts

    Because there is no concept of a "Discount" model in dj-stripe (due to the
    lack of a stripe id on them), this is a little different to the other
    handlers.
    """

    crud_type = CrudType.determine(event=event)
    discount_data = event.data.get("object", {})
    coupon_data = discount_data.get("coupon", {})
    customer = event.customer

    if crud_type is CrudType.DELETED:
        coupon = None
        coupon_start = None
        coupon_end = None
    else:
        coupon = _handle_crud_like_event(
            target_cls=models.Coupon,
            event=event,
            data=coupon_data,
            id=coupon_data.get("id"),
        )
        coupon_start = discount_data.get("start")
        coupon_end = discount_data.get("end")

    customer.coupon = coupon
    customer.coupon_start = convert_tstamp(coupon_start)
    customer.coupon_end = convert_tstamp(coupon_end)
    customer.save()


@webhooks.handler("customer.source")
def customer_source_webhook_handler(event):
    """Handle updates to customer payment-source objects.

    Docs: https://stripe.com/docs/api/sources
    """
    customer_data = event.data.get("object", {})
    source_type = customer_data.get("object", {})

    # TODO: handle other types of sources
    #  (https://stripe.com/docs/api/sources)
    if source_type == SourceType.card:
        if event.verb.endswith("deleted") and customer_data:
            # On customer.source.deleted, we do not delete the object,
            # we merely unlink it.
            # customer = Customer.objects.get(id=customer_data["id"])
            # NOTE: for now, customer.sources still points to Card
            # Also, https://github.com/dj-stripe/dj-stripe/issues/576
            models.Card.objects.filter(id=customer_data.get("id", "")).delete()
            models.DjstripePaymentMethod.objects.filter(
                id=customer_data.get("id", "")
            ).delete()
        else:
            _handle_crud_like_event(target_cls=models.Card, event=event)


@webhooks.handler("customer.subscription")
def customer_subscription_webhook_handler(event):
    """Handle updates to customer subscription objects.

    Docs an example subscription webhook response:
    https://stripe.com/docs/api#subscription_object
    """

    # customer.subscription.deleted doesn't actually delete the subscription
    # on the stripe side, it updates it to canceled status, so override
    # crud_type to update to match.
    crud_type = CrudType.determine(event=event)
    if crud_type is CrudType.DELETED:
        crud_type = CrudType.UPDATED
    _handle_crud_like_event(
        target_cls=models.Subscription, event=event, crud_type=crud_type
    )


@webhooks.handler("customer.tax_id")
def customer_tax_id_webhook_handler(event):
    """
    Handle updates to customer tax ID objects.
    """
    _handle_crud_like_event(
        target_cls=models.TaxId, event=event, crud_type=CrudType.determine(event=event)
    )


@webhooks.handler("payment_method")
def payment_method_handler(event):
    """
    Handle updates to payment_method objects
    :param event:
    :return:

    Docs for:
    - payment_method: https://stripe.com/docs/api/payment_methods
    """
    # will recieve all events of the type payment_method.X.Y so
    # need to ensure the data object is related to PaymentMethod Object
    target_object_type = event.data.get("object", {}).get("object", {})

    if target_object_type == "payment_method":
        id_ = event.data.get("object", {}).get("id", None)

        if (
            event.parts == ["payment_method", "detached"]
            and id_
            and id_.startswith("card_")
        ):
            # Special case to handle a quirk in stripe's wrapping of legacy "card" objects
            # with payment_methods - card objects are deleted on detach, so treat this as
            # a delete event
            _handle_crud_like_event(
                target_cls=models.PaymentMethod,
                event=event,
                crud_type=CrudType.DELETED,
            )
        else:
            _handle_crud_like_event(target_cls=models.PaymentMethod, event=event)


@webhooks.handler("account.external_account")
def account_application_webhook_handler(event):
    """
    Handles updates to Connected Accounts External Accounts
    """
    source_type = event.data.get("object", {}).get("object")
    if source_type == PayoutType.card:
        _handle_crud_like_event(target_cls=models.Card, event=event)

    if source_type == PayoutType.bank_account:
        _handle_crud_like_event(target_cls=models.BankAccount, event=event)


@webhooks.handler("account.updated")
def account_updated_webhook_handler(event):
    """
    Handles updates to Connected Accounts
        - account: https://stripe.com/docs/api/accounts
    """
    _handle_crud_like_event(
        target_cls=models.Account,
        event=event,
        crud_type=CrudType.UPDATED,
    )


@webhooks.handler("charge")
def charge_webhook_handler(event):
    """Handle updates to Charge objects
    - charge: https://stripe.com/docs/api/charges
    """
    # will recieve all events of the type charge.X.Y so
    # need to ensure the data object is related to Charge Object
    target_object_type = event.data.get("object", {}).get("object", {})

    if target_object_type == "charge":
        _handle_crud_like_event(target_cls=models.Charge, event=event)


@webhooks.handler("charge.dispute")
def dispute_webhook_handler(event):
    """Handle updates to Dispute objects
    - dispute: https://stripe.com/docs/api/disputes
    """
    # will recieve all events of the type charge.dispute.Y so
    # need to ensure the data object is related to Dispute Object
    target_object_type = event.data.get("object", {}).get("object", {})

    if target_object_type == "dispute":
        _handle_crud_like_event(target_cls=models.Dispute, event=event)


@webhooks.handler(
    "checkout",
    "coupon",
    "file",
    "invoice",
    "invoiceitem",
    "order",
    "payment_intent",
    "payout",
    "plan",
    "price",
    "product",
    "setup_intent",
    "subscription_schedule",
    "source",
    "tax_rate",
    "transfer",
)
def other_object_webhook_handler(event):
    """
    Handle updates to checkout, coupon, file, invoice, invoiceitem, payment_intent,
    plan, product, setup_intent, subscription_schedule, source, tax_rate
    and transfer objects.

    Docs for:
    - checkout: https://stripe.com/docs/api/checkout/sessions
    - coupon: https://stripe.com/docs/api/coupons
    - file: https://stripe.com/docs/api/files
    - invoice: https://stripe.com/docs/api/invoices
    - invoiceitem: https://stripe.com/docs/api/invoiceitems
    - order: https://stripe.com/docs/api/orders_v2
    - payment_intent: https://stripe.com/docs/api/payment_intents
    - payout: https://stripe.com/docs/api/payouts
    - plan: https://stripe.com/docs/api/plans
    - price: https://stripe.com/docs/api/prices
    - product: https://stripe.com/docs/api/products
    - setup_intent: https://stripe.com/docs/api/setup_intents
    - subscription_schedule: https://stripe.com/docs/api/subscription_schedules
    - source: https://stripe.com/docs/api/sources
    - tax_rate: https://stripe.com/docs/api/tax_rates/
    - transfer: https://stripe.com/docs/api/transfers
    """

    target_cls = {
        "checkout": models.Session,
        "coupon": models.Coupon,
        "file": models.File,
        "invoice": models.Invoice,
        "invoiceitem": models.InvoiceItem,
        "order": models.Order,
        "payment_intent": models.PaymentIntent,
        "payout": models.Payout,
        "plan": models.Plan,
        "price": models.Price,
        "product": models.Product,
        "transfer": models.Transfer,
        "setup_intent": models.SetupIntent,
        "subscription_schedule": models.SubscriptionSchedule,
        "source": models.Source,
        "tax_rate": models.TaxRate,
    }.get(event.category)

    _handle_crud_like_event(target_cls=target_cls, event=event)


#
# Helpers
#


class CrudType(Enum):
    """Helper object to determine CRUD-like event state."""

    UPDATED = "updated"
    DELETED = "deleted"

    @classmethod
    def determine(cls, event, verb=None):
        """
        Determine if the event verb is a crud_type (without the 'R') event.

        :param event:
        :type event: models.Event
        :param verb: The event verb to examine.
        :type verb: str
        :returns: The CrudType state object.
        :rtype: CrudType
        """
        verb = verb or event.verb

        for enum in CrudType:
            if verb.endswith(enum.value):
                return enum

        # in case nothing matches
        return


def _handle_crud_like_event(
    target_cls, event: "models.Event", data=None, id: str = None, crud_type=None
):
    """
    Helper to process crud_type-like events for objects.

    Non-deletes (creates, updates and "anything else" events) are treated as
    update_or_create events - The object will be retrieved locally, then it is
    synchronised with the Stripe API for parity.

    Deletes only occur for delete events and cause the object to be deleted
    from the local database, if it existed.  If it doesn't exist then it is
    ignored (but the event processing still succeeds).

    :param target_cls: The djstripe model being handled.
    :type target_cls: Type[models.StripeModel]
    :param event: The event object
    :param data: The event object data (defaults to ``event.data``).
    :param id: The object Stripe ID (defaults to ``object.id``).
    :param crud_type: The CrudType object (determined by default).
    :returns: The object (if any) and the event CrudType.
    :rtype: Tuple[models.StripeModel, CrudType]
    """
    data = data or event.data
    id = id or data.get("object", {}).get("id", None)
    stripe_account = getattr(event.djstripe_owner_account, "id", None)

    if not id:
        # We require an object when applying CRUD-like events, so if there's
        # no ID the event is ignored/dropped. This happens in events such as
        # invoice.upcoming, which refer to a future (non-existant) invoice.
        logger.debug("Ignoring Stripe event %r without object ID", event.id)
        return

    crud_type = crud_type or CrudType.determine(event=event, verb=event.verb)

    if crud_type is CrudType.DELETED:
        qs = target_cls.objects.filter(id=id)
        if target_cls is models.Customer and qs.exists():
            qs.get().purge()
            obj = None
        else:
            obj = target_cls.objects.filter(id=id).delete()
    else:
        # Any other event type (creates, updates, etc.) - This can apply to
        # verbs that aren't strictly CRUD but Stripe do intend an update.  Such
        # as invoice.payment_failed.
        kwargs = {"id": id}
        if hasattr(target_cls, "customer"):
            kwargs["customer"] = event.customer

        # For account.external_account.* events
        if event.parts[:2] == ["account", "external_account"] and stripe_account:
            kwargs["account"] = models.Account._get_or_retrieve(id=stripe_account)

        # Stripe doesn't allow retrieval of Discount Objects
        if target_cls not in (models.Discount,):
            data = target_cls(**kwargs).api_retrieve(
                stripe_account=stripe_account, api_key=event.default_api_key
            )
        else:
            data = data.get("object")

        # create or update the object from the retrieved Stripe Data
        obj = target_cls.sync_from_stripe_data(data, api_key=event.default_api_key)

    return obj


================================================
FILE: djstripe/exceptions.py
================================================
"""
dj-stripe Exceptions.
"""


class MultipleSubscriptionException(Exception):
    """Raised when a Customer has multiple Subscriptions and only one is expected."""

    pass


class StripeObjectManipulationException(Exception):
    """
    Raised when an attempt to manipulate a non-standalone stripe object is made
     not through its parent object.
    """

    pass


class InvalidStripeAPIKey(ValueError):
    """
    Raised when a clearly-invalid Stripe API key is used.
    """

    pass


class ImpossibleAPIRequest(Exception):
    """
    Raised when dj-stripe attempts to make an impossible API request
    """

    pass


================================================
FILE: djstripe/fields.py
================================================
"""
dj-stripe Custom Field Definitions
"""
import decimal

from django.conf import SettingsReference, settings
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.db.models import JSONField as BaseJSONField

from .utils import convert_tstamp


class FieldDeconstructMixin:
    IGNORED_ATTRS = [
        "verbose_name",
        "help_text",
        "choices",
        "get_latest_by",
        "ordering",
    ]

    def deconstruct(self):
        """Remove field attributes that have nothing to
        do with the database. Otherwise unencessary migrations are generated."""
        name, path, args, kwargs = super().deconstruct()
        for attr in self.IGNORED_ATTRS:
            kwargs.pop(attr, None)
        return name, path, args, kwargs


class StripeForeignKey(models.ForeignKey):
    setting_name = "DJSTRIPE_FOREIGN_KEY_TO_FIELD"

    def __init__(self, *args, **kwargs):
        # The default value will only come into play if the check for
        # that setting has been disabled.
        kwargs["to_field"] = getattr(settings, self.setting_name, "id")
        super().__init__(*args, **kwargs)

    def deconstruct(self):
        name, path, args, kwargs = super().deconstruct()
        kwargs["to_field"] = SettingsReference(
            getattr(settings, self.setting_name, "id"), self.setting_name
        )
        return name, path, args, kwargs

    def get_default(self):
        # Override to bypass a weird bug in Django
        # https://stackoverflow.com/a/14390402/227443
        if isinstance(self.remote_field.model, str):
            return self._get_default()
        return super().get_default()


class PaymentMethodForeignKey(FieldDeconstructMixin, models.ForeignKey):
    def __init__(self, **kwargs):
        kwargs.setdefault("to", "DjstripePaymentMethod")
        super().__init__(**kwargs)


class InvoiceOrLineItemForeignKey(models.ForeignKey):
    def __init__(self, **kwargs):
        kwargs.setdefault("to", "InvoiceOrLineItem")
        super().__init__(**kwargs)


class StripePercentField(FieldDeconstructMixin, models.DecimalField):
    """A field used to define a percent according to djstripe logic."""

    def __init__(self, *args, **kwargs):
        """Assign default args to this field."""
        defaults = {
            "decimal_places": 2,
            "max_digits": 5,
            "validators": [MinValueValidator(1), MaxValueValidator(100)],
        }
        defaults.update(kwargs)
        super().__init__(*args, **defaults)


class StripeCurrencyCodeField(FieldDeconstructMixin, models.CharField):
    """
    A field used to store a three-letter currency code (eg. usd, eur, ...)
    """

    def __init__(self, *args, **kwargs):
        defaults = {"max_length": 3, "help_text": "Three-letter ISO currency code"}
        defaults.update(kwargs)
        super().__init__(*args, **defaults)


class StripeQuantumCurrencyAmountField(FieldDeconstructMixin, models.BigIntegerField):
    """
    A field used to store currency amounts in cents (etc) as per stripe.
    By contacting stripe support, some accounts will have their limit raised to 11
    digits, hence the use of BigIntegerField instead of IntegerField
    """

    pass


class StripeDecimalCurrencyAmountField(FieldDeconstructMixin, models.DecimalField):
    """
    A legacy field to store currency amounts in dollars (etc).

    Stripe is always in cents. Historically djstripe stored everything in dollars.

    Note: Don't use this for new fields, use StripeQuantumCurrencyAmountField instead.
    We're planning on migrating existing fields in dj-stripe 3.0,
    see https://github.com/dj-stripe/dj-stripe/issues/955
    """

    def __init__(self, *args, **kwargs):
        """
        Assign default args to this field. By contacting stripe support, some accounts
        will have their limit raised to 11 digits
        """
        defaults = {"decimal_places": 2, "max_digits": 11}
        defaults.update(kwargs)
        super().__init__(*args, **defaults)

    def stripe_to_db(self, data):
        """Convert the raw value to decimal representation."""
        val = data.get(self.name)

        # If already a string, it's decimal in the API (eg. Prices).
        if isinstance(val, str):
            return decimal.Decimal(val)

        # Note: 0 is a possible return value, which is 'falseish'
        if val is not None:
            return val / decimal.Decimal("100")


class StripeEnumField(FieldDeconstructMixin, models.CharField):
    def __init__(self, enum, *args, **kwargs):
        self.enum = enum
        choices = enum.choices
        defaults = {"choices": choices, "max_length": max(len(k) for k, v in choices)}
        defaults.update(kwargs)
        super().__init__(*args, **defaults)

    def deconstruct(self):
        name, path, args, kwargs = super().deconstruct()
        kwargs["enum"] = self.enum
        return name, path, args, kwargs


class StripeIdField(FieldDeconstructMixin, models.CharField):
    """A field with enough space to hold any stripe ID."""

    def __init__(self, *args, **kwargs):
        """
        Assign default args to this field.

        As per: https://stripe.com/docs/upgrades
        You can safely assume object IDs we generate will never exceed 255
        characters, but you should be able to handle IDs of up to that
        length.
        """
        defaults = {"max_length": 255, "blank": False, "null": False}
        defaults.update(kwargs)
        super().__init__(*args, **defaults)


class StripeDateTimeField(FieldDeconstructMixin, models.DateTimeField):
    """A field used to define a DateTimeField value according to djstripe logic."""

    def stripe_to_db(self, data):
        """Convert the raw timestamp value to a DateTime representation."""
        val = data.get(self.name)

        # Note: 0 is a possible return value, which is 'falseish'
        if val is not None:
            return convert_tstamp(val)


class JSONField(FieldDeconstructMixin, BaseJSONField):
    """A field used to define a JSONField value according to djstripe logic."""

    pass


================================================
FILE: djstripe/locale/fr/LC_MESSAGES/django.po
================================================
msgid ""
msgstr ""
"Project-Id-Version: 1.3.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-01-28 12:02+1300\n"
"Last-Translator: Jerome Leclanche <jerome@leclan.ch>\n"
"Language-Team: French <jerome@leclan.ch>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

#: enums.py:57
msgid "Account already exists"
msgstr ""

#: enums.py:58
msgid "Account country invalid address"
msgstr ""

#: enums.py:59
msgid "Account invalid"
msgstr ""

#: enums.py:60
msgid "Account number invalid"
msgstr ""

#: enums.py:61
msgid "Alipay upgrade required"
msgstr ""

#: enums.py:62
msgid "Amount too large"
msgstr ""

#: enums.py:63
msgid "Amount too small"
msgstr ""

#: enums.py:64
msgid "Api key expired"
msgstr ""

#: enums.py:65
msgid "Balance insufficient"
msgstr ""

#: enums.py:66
#, fuzzy
#| msgid "Bank account"
msgid "Bank account exists"
msgstr "Compte bancaire"

#: enums.py:67
#, fuzzy
#| msgid "Bank account"
msgid "Bank account unusable"
msgstr "Compte bancaire"

#: enums.py:68
#, fuzzy
#| msgid "Bank account"
msgid "Bank account unverified"
msgstr "Compte bancaire"

#: enums.py:69
#, fuzzy
#| msgid "Bitcoin receiver"
msgid "Bitcoin upgrade required"
msgstr "Récipient Bitcoin"

#: enums.py:70
msgid "Card was declined"
msgstr "Carte rejetée"

#: enums.py:71
#, fuzzy
#| msgid "Charge refunded"
msgid "Charge already captured"
msgstr "Charge remboursée"

#: enums.py:72
#, fuzzy
#| msgid "Charge refunded"
msgid "Charge already refunded"
msgstr "Charge remboursée"

#: enums.py:73
#, fuzzy
#| msgid "Charge refunded"
msgid "Charge disputed"
msgstr "Charge remboursée"

#: enums.py:74
msgid "Charge exceeds source limit"
msgstr ""

#: enums.py:75
msgid "Charge expired for capture"
msgstr ""

#: enums.py:76
#, fuzzy
#| msgid "Card no longer supported."
msgid "Country unsupported"
msgstr "La carte n'est plus supportée."

#: enums.py:77
msgid "Coupon expired"
msgstr ""

#: enums.py:78
msgid "Customer max subscriptions"
msgstr ""

#: enums.py:79
msgid "Email invalid"
msgstr ""

#: enums.py:80
msgid "Expired card"
msgstr "Carte expirée"

#: enums.py:81
msgid "Idempotency key in use"
msgstr ""

#: enums.py:82
#, fuzzy
#| msgid "Incorrect account details"
msgid "Incorrect address"
msgstr "Détails de compte incorrects"

#: enums.py:83
msgid "Incorrect security code"
msgstr "Code de sécurité incorrect"

#: enums.py:84
msgid "Incorrect number"
msgstr "Numéro incorrect"

#: enums.py:85
msgid "ZIP code failed validation"
msgstr "Validation du code postal échouée"

#: enums.py:86
msgid "Instant payouts unsupported"
msgstr ""

#: enums.py:87
#, fuzzy
#| msgid "Invalid security code"
msgid "Invalid card type"
msgstr "Code de sécurité invalide"

#: enums.py:88
#, fuzzy
#| msgid "Invalid expiration month"
msgid "Invalid charge amount"
msgstr "Mois d'expiration invalide"

#: enums.py:89
msgid "Invalid security code"
msgstr "Code de sécurité invalide"

#: enums.py:90
msgid "Invalid expiration month"
msgstr "Mois d'expiration invalide"

#: enums.py:91
msgid "Invalid expiration year"
msgstr "Année d'expiration invalide"

#: enums.py:92
msgid "Invalid number"
msgstr "Numéro invalide"

#: enums.py:93
#, fuzzy
#| msgid "Invalid security code"
msgid "Invalid source usage"
msgstr "Code de sécurité invalide"

#: enums.py:94
msgid "Invoice no customer line items"
msgstr ""

#: enums.py:95
msgid "Invoice no subscription line items"
msgstr ""

#: enums.py:96
msgid "Invoice not editable"
msgstr ""

#: enums.py:97
msgid "Invoice upcoming none"
msgstr ""

#: enums.py:98
msgid "Livemode mismatch"
msgstr ""

#: enums.py:99
msgid "No card being charged"
msgstr "Aucune carte chargée"

#: enums.py:100
msgid "Not allowed on standard account"
msgstr ""

#: enums.py:101
#, fuzzy
#| msgid "Verification failed"
msgid "Order creation failed"
msgstr "Vérification échouée"

#: enums.py:102
msgid "Order required settings"
msgstr ""

#: enums.py:103
msgid "Order status invalid"
msgstr ""

#: enums.py:104
msgid "Order upstream timeout"
msgstr ""

#: enums.py:105
msgid "Out of inventory"
msgstr ""

#: enums.py:106
msgid "Parameter invalid empty"
msgstr ""

#: enums.py:107
msgid "Parameter invalid integer"
msgstr ""

#: enums.py:108
msgid "Parameter invalid string blank"
msgstr ""

#: enums.py:109
msgid "Parameter invalid string empty"
msgstr ""

#: enums.py:110
msgid "Parameter missing"
msgstr ""

#: enums.py:111
msgid "Parameter unknown"
msgstr ""

#: enums.py:112
msgid "Parameters exclusive"
msgstr ""

#: enums.py:113
msgid "Payment intent authentication failure"
msgstr ""

#: enums.py:114
msgid "Payment intent incompatible payment method"
msgstr ""

#: enums.py:115
msgid "Payment intent invalid parameter"
msgstr ""

#: enums.py:116
msgid "Payment intent payment attempt failed"
msgstr ""

#: enums.py:117
msgid "Payment intent unexpected state"
msgstr ""

#: enums.py:118
#, fuzzy
#| msgid "Payment refund"
msgid "Payment method unactivated"
msgstr "Remboursement de paiment"

#: enums.py:119
msgid "Payment method unexpected state"
msgstr ""

#: enums.py:120
#, fuzzy
#| msgid "Payout failure"
msgid "Payouts not allowed"
msgstr "Échec de virement"

#: enums.py:121
msgid "Platform api key expired"
msgstr ""

#: enums.py:122
msgid "Postal code invalid"
msgstr ""

#: enums.py:123 enums.py:433
msgid "Processing error"
msgstr "Erreur de traitement"

#: enums.py:124
#, fuzzy
#| msgid "Product unacceptable"
msgid "Product inactive"
msgstr "Produit inacceptable"

#: enums.py:125
msgid "Rate limit"
msgstr ""

#: enums.py:126
msgid "Resource already exists"
msgstr ""

#: enums.py:127
msgid "Resource missing"
msgstr ""

#: enums.py:128
msgid "Routing number invalid"
msgstr ""

#: enums.py:129
#, fuzzy
#| msgid "Not required"
msgid "Secret key required"
msgstr "Non requis"

#: enums.py:130
msgid "SEPA unsupported account"
msgstr ""

#: enums.py:131
#, fuzzy
#| msgid "Verification failed"
msgid "Shipping calculation failed"
msgstr "Vérification échouée"

#: enums.py:132
msgid "SKU inactive"
msgstr ""

#: enums.py:133
msgid "State unsupported"
msgstr ""

#: enums.py:134
msgid "Tax id invalid"
msgstr ""

#: enums.py:135
#, fuzzy
#| msgid "Verification failed"
msgid "Taxes calculation failed"
msgstr "Vérification échouée"

#: enums.py:136
msgid "Testmode charges only"
msgstr ""

#: enums.py:137
msgid "TLS version unsupported"
msgstr ""

#: enums.py:138
msgid "Token already used"
msgstr ""

#: enums.py:139
msgid "Token in use"
msgstr ""

#: enums.py:140
#, fuzzy
#| msgid "Transfer refund"
msgid "Transfers not allowed"
msgstr "Remboursement de transfert"

#: enums.py:141
#, fuzzy
#| msgid "Verification failed"
msgid "Upstream order creation failed"
msgstr "Vérification échouée"

#: enums.py:142
msgid "URL invalid"
msgstr ""

#: enums.py:145
msgid "Invalid swipe data"
msgstr "Données swipe invalide"

#: enums.py:149 enums.py:302
msgid "Standard"
msgstr "Standard"

#: enums.py:150
msgid "Express"
msgstr "Express"

#: enums.py:151
msgid "Custom"
msgstr "Custom"

#: enums.py:155
msgid "Available"
msgstr "Disponible"

#: enums.py:156 enums.py:223 enums.py:308 enums.py:371 enums.py:413
#: enums.py:425 enums.py:437
msgid "Pending"
msgstr "En attente"

#: enums.py:160
msgid "Adjustment"
msgstr "Ajustement"

#: enums.py:161
msgid "Application fee"
msgstr "Frais d'application"

#: enums.py:162
msgid "Application fee refund"
msgstr "Remboursement de frais d'application"

#: enums.py:163
msgid "Charge"
msgstr "Charge"

#: enums.py:164
msgid "Network cost"
msgstr "Coût de réseau"

#: enums.py:165
msgid "Payment"
msgstr "Paiment"

#: enums.py:166
msgid "Payment failure refund"
msgstr "Remboursement d'échec de paiment"

#: enums.py:167
msgid "Payment refund"
msgstr "Remboursement de paiment"

#: enums.py:168
msgid "Payout"
msgstr "Virement"

#: enums.py:169
msgid "Payout cancellation"
msgstr "Annulation de virement"

#: enums.py:170
msgid "Payout failure"
msgstr "Échec de virement"

#: enums.py:171
msgid "Refund"
msgstr "Remboursement"

#: enums.py:172
msgid "Stripe fee"
msgstr "Frais Stripe"

#: enums.py:173
msgid "Transfer"
msgstr "Transfert"

#: enums.py:174
msgid "Transfer refund"
msgstr "Remboursement de transfert"

#: enums.py:175
msgid "Validation"
msgstr "Validation"

#: enums.py:179
msgid "Individual"
msgstr "Particulier"

#: enums.py:180
msgid "Company"
msgstr "Companie"

#: enums.py:184
msgid "New"
msgstr "Nouveau"

#: enums.py:185
msgid "Validated"
msgstr "Validé"

#: enums.py:186
msgid "Verified"
msgstr "Vérifié"

#: enums.py:187
msgid "Verification failed"
msgstr "Vérification échouée"

#: enums.py:188
msgid "Errored"
msgstr "Erreur"

#: enums.py:192
msgid "Pass"
msgstr "OK"

#: enums.py:193
msgid "Fail"
msgstr "Échoué"

#: enums.py:194
msgid "Unavailable"
msgstr "Indisponible"

#: enums.py:195
msgid "Unchecked"
msgstr "Non vérifié"

#: enums.py:199
msgid "American Express"
msgstr "American Express"

#: enums.py:200
msgid "Diners Club"
msgstr "Diners Club"

#: enums.py:201
msgid "Discover"
msgstr "Discover"

#: enums.py:202
msgid "JCB"
msgstr "JCB"

#: enums.py:203
msgid "MasterCard"
msgstr "masterCard"

#: enums.py:204
msgid "UnionPay"
msgstr ""

#: enums.py:205
msgid "Visa"
msgstr "Visa"

#: enums.py:206 enums.py:213 enums.py:403
msgid "Unknown"
msgstr "Inconnu"

#: enums.py:210
msgid "Credit"
msgstr "Crédit"

#: enums.py:211
msgid "Debit"
msgstr "Débit"

#: enums.py:212
msgid "Prepaid"
msgstr "Prépayée"

#: enums.py:217
msgid "Apple Pay"
msgstr "Apple Pay"

#: enums.py:218
msgid "Android Pay"
msgstr "Android Pay"

#: enums.py:222 enums.py:414 enums.py:426 enums.py:438
msgid "Succeeded"
msgstr "Réussi"

#: enums.py:224 enums.py:311 enums.py:355 enums.py:370 enums.py:415
#: enums.py:427 enums.py:440
msgid "Failed"
msgstr "Échoué"

#: enums.py:228
msgid "Once"
msgstr "Simple"

#: enums.py:229
msgid "Multi-month"
msgstr "Multi-mois"

#: enums.py:230
msgid "Forever"
msgstr "Illimité"

#: enums.py:234
msgid "Duplicate"
msgstr "Doublon"

#: enums.py:235 enums.py:408
msgid "Fraudulent"
msgstr "Frauduleux"

#: enums.py:236
msgid "Subscription canceled"
msgstr "Abonnement annulé"

#: enums.py:237
msgid "Product unacceptable"
msgstr "Produit inacceptable"

#: enums.py:238
msgid "Product not received"
msgstr "Produit non reçu"

#: enums.py:239
msgid "Unrecognized"
msgstr "Non reconnu"

#: enums.py:240
msgid "Credit not processed"
msgstr "Crédit non traité"

#: enums.py:241
msgid "General"
msgstr "Général"

#: enums.py:242
msgid "Incorrect account details"
msgstr "Détails de compte incorrects"

#: enums.py:243
msgid "Insufficient funds"
msgstr "Fonds insuffisants"

#: enums.py:244
msgid "Bank cannot process"
msgstr "Banque ne peut traiter"

#: enums.py:245
msgid "Debit not authorized"
msgstr "Débit interdit"

#: enums.py:246
msgid "Customer-initiated"
msgstr "Initié par le client"

#: enums.py:250
msgid "Warning needs response"
msgstr "Avertissement en attente de réponse"

#: enums.py:251
msgid "Warning under review"
msgstr "Avertissement en revue"

#: enums.py:252
msgid "Warning closed"
msgstr "Avertissement "

#: enums.py:253
msgid "Needs response"
msgstr "En attente de réponse"

#: enums.py:254
msgid "Under review"
msgstr "En revue"

#: enums.py:255
msgid "Charge refunded"
msgstr "Charge remboursée"

#: enums.py:256
msgid "Won"
msgstr "Gagnée"

#: enums.py:257
msgid "Lost"
msgstr "Perdue"

#: enums.py:261
msgid "Dispute evidence"
msgstr "Preuve de dispute"

#: enums.py:262
msgid "Identity document"
msgstr "Document d'identité"

#: enums.py:263
msgid "Tax document user upload"
msgstr "Document de taxes de l'utilisateur"

#: enums.py:267
msgid "PDF"
msgstr "PDF"

#: enums.py:268
msgid "JPG"
msgstr "JPG"

#: enums.py:269
msgid "PNG"
msgstr "PNG"

#: enums.py:270
msgid "CSV"
msgstr "CSV"

#: enums.py:271
msgid "XLS"
msgstr "XLS"

#: enums.py:272
msgid "XLSX"
msgstr "XLSX"

#: enums.py:273
msgid "DOCX"
msgstr "DOCX"

#: enums.py:277
msgid "Charge automatically"
msgstr "Débit automatique"

#: enums.py:278
msgid "Send invoice"
msgstr "Envoi de facture"

#: enums.py:288
msgid "Bank account has been closed."
msgstr "Compte bancaire fermé"

#: enums.py:289
msgid "Bank account has been frozen."
msgstr "Compte bancaire gelé"

#: enums.py:290
msgid "Bank account has restrictions on payouts allowed."
msgstr "Le compte bancaire a des restrictions sur les virements autorisés"

#: enums.py:291
msgid "Destination bank account has changed ownership."
msgstr "Le compte bancaire destinataire a changé de propriétaire."

#: enums.py:292
msgid "Bank could not process payout."
msgstr "Le compte bancaire n'a pas pu traiter le virement."

#: enums.py:293
msgid "Debit transactions not approved on the bank account."
msgstr ""
"Les transactions de débit ne sont pas autorisées sur le compte bancaire."

#: enums.py:294
msgid "Stripe account has insufficient funds."
msgstr "Stripe n'a pas suffisamment de fonds."

#: enums.py:295
msgid "Invalid account number"
msgstr "Numéro de compte invalide"

#: enums.py:296
msgid "Bank account does not support currency."
msgstr "Le compte bancaire ne supporte pas la monnaie."

#: enums.py:297
msgid "Bank account could not be located."
msgstr "Le compte bancaire n'a pas été trouvé."

#: enums.py:298
msgid "Card no longer supported."
msgstr "La carte n'est plus supportée."

#: enums.py:303
msgid "Instant"
msgstr "Instant"

#: enums.py:307
msgid "Paid"
msgstr "Payé"

#: enums.py:309
msgid "In transit"
msgstr "En cours"

#: enums.py:310 enums.py:354 enums.py:367 enums.py:416 enums.py:447
msgid "Canceled"
msgstr "Annulé"

#: enums.py:315 enums.py:395 enums.py:457
msgid "Bank account"
msgstr "Compte bancaire"

#: enums.py:316 enums.py:380 enums.py:394 enums.py:456
msgid "Card"
msgstr "Carte"

#: enums.py:320
msgid "Last during period"
msgstr "Dernier cette période"

#: enums.py:321
msgid "Last ever"
msgstr "Dernier"

#: enums.py:322
msgid "Max"
msgstr "Max"

#: enums.py:323
msgid "Sum"
msgstr "Somme"

#: enums.py:327
msgid "Per unit"
msgstr "Par unité"

#: enums.py:328
msgid "Tiered"
msgstr "En tiers"

#: enums.py:332
msgid "Day"
msgstr "Jour"

#: enums.py:333
msgid "Week"
msgstr "Semaine"

#: enums.py:334
msgid "Month"
msgstr "Mois"

#: enums.py:335
msgid "Year"
msgstr "Année"

#: enums.py:339
msgid "Metered"
msgstr "Compté"

#: enums.py:340
msgid "Licensed"
msgstr "Sous license"

#: enums.py:344
msgid "Graduated"
msgstr "Gradué"

#: enums.py:345
msgid "Volume-based"
msgstr "Par volume"

#: enums.py:349
msgid "Good"
msgstr "Bien"

#: enums.py:350
msgid "Service"
msgstr "Service"

#: enums.py:356
msgid "Timed out"
msgstr ""

#: enums.py:360
msgid "Redirect"
msgstr "Redirection"

#: enums.py:361
msgid "Receiver"
msgstr "Récipient"

#: enums.py:362
msgid "Code verification"
msgstr "Vérification de code"

#: enums.py:363
msgid "None"
msgstr "Aucune"

#: enums.py:368
msgid "Chargeable"
msgstr "Prête a débiter"

#: enums.py:369
msgid "Consumed"
msgstr "Consommée"

#: enums.py:375
msgid "ACH Credit Transfer"
msgstr "Transfert crédit ACH"

#: enums.py:376
msgid "ACH Debit"
msgstr "Débit ACH"

#: enums.py:377
msgid "Alipay"
msgstr "Alipay"

#: enums.py:378
msgid "Bancontact"
msgstr "Bancontact"

#: enums.py:379
msgid "Bitcoin"
msgstr "Bitcoin"

#: enums.py:381
msgid "Card present"
msgstr "Carte présentée"

#: enums.py:382
msgid "EPS"
msgstr "EPS"

#: enums.py:383
msgid "Giropay"
msgstr "Giropay"

#: enums.py:384
msgid "iDEAL"
msgstr "iDEAL"

#: enums.py:385
msgid "P24"
msgstr "P24"

#: enums.py:386
msgid "Paper check"
msgstr "Cheque papier"

#: enums.py:387
msgid "SEPA Direct Debit"
msgstr "Débit direct SEPA"

#: enums.py:388
msgid "SEPA credit transfer"
msgstr "Transfert crédit SEPA"

#: enums.py:389
msgid "SOFORT"
msgstr "SOFORT"

#: enums.py:390
msgid "3D Secure"
msgstr "3D Secure"

#: enums.py:396
msgid "Bitcoin receiver"
msgstr "Récipient Bitcoin"

#: enums.py:397
msgid "Alipay account"
msgstr "Compte Alipay"

#: enums.py:401
msgid "Lost or stolen card"
msgstr "Carte perdue ou volée"

#: enums.py:402
msgid "Expired or canceled card"
msgstr "Carte expirée ou annulée"

#: enums.py:407
msgid "Duplicate charge"
msgstr "Charge double"

#: enums.py:409
msgid "Requested by customer"
msgstr "Demandé par le client"

#: enums.py:420
msgid "Reusable"
msgstr "Réutilisable"

#: enums.py:421
msgid "Single-use"
msgstr "Usage unique"

#: enums.py:431
msgid "User-aborted"
msgstr "Annulé par l'utilisateur"

#: enums.py:432
msgid "Declined"
msgstr "Rejeté"

#: enums.py:439
msgid "Not required"
msgstr "Non requis"

#: enums.py:444
msgid "Trialing"
msgstr "En période d'essai"

#: enums.py:445
msgid "Active"
msgstr "Active"

#: enums.py:446
msgid "Past due"
msgstr "Arriéré dû"

#: enums.py:448
msgid "Unpaid"
msgstr "Non payé"

#: enums.py:458
msgid "Source"
msgstr "Source"

#: models/billing.py:863
msgid "day"
msgstr "jour"

#: models/billing.py:864
msgid "week"
msgstr "semaine"

#: models/billing.py:865
msgid "month"
msgstr "mois"

#: models/billing.py:866
msgid "year"
msgstr "an"

#: models/billing.py:868
#, python-brace-format
msgid "{amount}/{interval}"
msgstr "{amount}/{interval}"

#: models/billing.py:871
msgid "days"
msgstr "jours"

#: models/billing.py:872
msgid "weeks"
msgstr "semaines"

#: models/billing.py:873
msgid "months"
msgstr "mois"

#: models/billing.py:874
msgid "years"
msgstr "ans"

#: models/billing.py:876
#, python-brace-format
msgid "{amount} every {interval_count} {interval}"
msgstr "{amount} tous les {interval_count} {interval}"

#: templates/djstripe/admin/change_form.html:8
msgid "View on Stripe Dashboard"
msgstr "Voir sur l'administration Stripe"


================================================
FILE: djstripe/locale/ru/LC_MESSAGES/django.po
================================================
msgid ""
msgstr ""
"Project-Id-Version: 1.3.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-01-28 12:02+1300\n"
"Last-Translator: Kirill Shilimanov <mawile@hackerdom.ru>\n"
"Language-Team: Russian <mawile@hackerdom.ru>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

#: enums.py:57
msgid "Account already exists"
msgstr ""

#: enums.py:58
msgid "Account country invalid address"
msgstr ""

#: enums.py:59
msgid "Account invalid"
msgstr ""

#: enums.py:60
msgid "Account number invalid"
msgstr ""

#: enums.py:61
msgid "Alipay upgrade required"
msgstr ""

#: enums.py:62
msgid "Amount too large"
msgstr ""

#: enums.py:63
msgid "Amount too small"
msgstr ""

#: enums.py:64
msgid "Api key expired"
msgstr ""

#: enums.py:65
msgid "Balance insufficient"
msgstr ""

#: enums.py:66
#, fuzzy
#| msgid "Bank account"
msgid "Bank account exists"
msgstr "Банковский счет"

#: enums.py:67
#, fuzzy
#| msgid "Bank account"
msgid "Bank account unusable"
msgstr "Банковский счет"

#: enums.py:68
#, fuzzy
#| msgid "Bank account"
msgid "Bank account unverified"
msgstr "Банковский счет"

#: enums.py:69
#, fuzzy
#| msgid "Bitcoin receiver"
msgid "Bitcoin upgrade required"
msgstr "Получатель Bitcoin"

#: enums.py:70
msgid "Card was declined"
msgstr "Карта отклонена"

#: enums.py:71
#, fuzzy
#| msgid "Charge refunded"
msgid "Charge already captured"
msgstr "Платеж возвращен"

#: enums.py:72
#, fuzzy
#| msgid "Charge refunded"
msgid "Charge already refunded"
msgstr "Платеж возвращен"

#: enums.py:73
#, fuzzy
#| msgid "Charge refunded"
msgid "Charge disputed"
msgstr "Платеж возвращен"

#: enums.py:74
msgid "Charge exceeds source limit"
msgstr ""

#: enums.py:75
msgid "Charge expired for capture"
msgstr ""

#: enums.py:76
#, fuzzy
#| msgid "Card no longer supported."
msgid "Country unsupported"
msgstr "Карта не поддерживается."

#: enums.py:77
msgid "Coupon expired"
msgstr ""

#: enums.py:78
msgid "Customer max subscriptions"
msgstr ""

#: enums.py:79
msgid "Email invalid"
msgstr ""

#: enums.py:80
msgid "Expired card"
msgstr "Срок действия карты истек"

#: enums.py:81
msgid "Idempotency key in use"
msgstr ""

#: enums.py:82
#, fuzzy
#| msgid "Incorrect account details"
msgid "Incorrect address"
msgstr "Неверные данные счета"

#: enums.py:83
msgid "Incorrect security code"
msgstr "Неверный код безопасности"

#: enums.py:84
msgid "Incorrect number"
msgstr "Неверный номер"

#: enums.py:85
msgid "ZIP code failed validation"
msgstr "Ошибка проверки почтового индекса"

#: enums.py:86
msgid "Instant payouts unsupported"
msgstr ""

#: enums.py:87
#, fuzzy
#| msgid "Invalid security code"
msgid "Invalid card type"
msgstr "Недействительный код безопасности"

#: enums.py:88
#, fuzzy
#| msgid "Invalid expiration month"
msgid "Invalid charge amount"
msgstr "Неверный месяц истечения"

#: enums.py:89
msgid "Invalid security code"
msgstr "Недействительный код безопасности"

#: enums.py:90
msgid "Invalid expiration month"
msgstr "Неверный месяц истечения"

#: enums.py:91
msgid "Invalid expiration year"
msgstr "Неверный год истечения"

#: enums.py:92
msgid "Invalid number"
msgstr "Неверный номер"

#: enums.py:93
#, fuzzy
#| msgid "Invalid security code"
msgid "Invalid source usage"
msgstr "Недействительный код безопасности"

#: enums.py:94
msgid "Invoice no customer line items"
msgstr ""

#: enums.py:95
msgid "Invoice no subscription line items"
msgstr ""

#: enums.py:96
msgid "Invoice not editable"
msgstr ""

#: enums.py:97
msgid "Invoice upcoming none"
msgstr ""

#: enums.py:98
msgid "Livemode mismatch"
msgstr ""

#: enums.py:99
msgid "No card being charged"
msgstr "Деньги с карты не сняты"

#: enums.py:100
msgid "Not allowed on standard account"
msgstr ""

#: enums.py:101
#, fuzzy
#| msgid "Verification failed"
msgid "Order creation failed"
msgstr "Проверка не удалась"

#: enums.py:102
msgid "Order required settings"
msgstr ""

#: enums.py:103
msgid "Order status invalid"
msgstr ""

#: enums.py:104
msgid "Order upstream timeout"
msgstr ""

#: enums.py:105
msgid "Out of inventory"
msgstr ""

#: enums.py:106
msgid "Parameter invalid empty"
msgstr ""

#: enums.py:107
msgid "Parameter invalid integer"
msgstr ""

#: enums.py:108
msgid "Parameter invalid string blank"
msgstr ""

#: enums.py:109
msgid "Parameter invalid string empty"
msgstr ""

#: enums.py:110
msgid "Parameter missing"
msgstr ""

#: enums.py:111
msgid "Parameter unknown"
msgstr ""

#: enums.py:112
msgid "Parameters exclusive"
msgstr ""

#: enums.py:113
msgid "Payment intent authentication failure"
msgstr ""

#: enums.py:114
msgid "Payment intent incompatible payment method"
msgstr ""

#: enums.py:115
msgid "Payment intent invalid parameter"
msgstr ""

#: enums.py:116
msgid "Payment intent payment attempt failed"
msgstr ""

#: enums.py:117
msgid "Payment intent unexpected state"
msgstr ""

#: enums.py:118
#, fuzzy
#| msgid "Payment refund"
msgid "Payment method unactivated"
msgstr "Возврат платежа"

#: enums.py:119
msgid "Payment method unexpected state"
msgstr ""

#: enums.py:120
#, fuzzy
#| msgid "Payout failure"
msgid "Payouts not allowed"
msgstr "Сбой выплаты"

#: enums.py:121
msgid "Platform api key expired"
msgstr ""

#: enums.py:122
msgid "Postal code invalid"
msgstr ""

#: enums.py:123 enums.py:433
msgid "Processing error"
msgstr "Ошибка обработки"

#: enums.py:124
#, fuzzy
#| msgid "Product unacceptable"
msgid "Product inactive"
msgstr "Продукт неприемлем"

#: enums.py:125
msgid "Rate limit"
msgstr ""

#: enums.py:126
msgid "Resource already exists"
msgstr ""

#: enums.py:127
msgid "Resource missing"
msgstr ""

#: enums.py:128
msgid "Routing number invalid"
msgstr ""

#: enums.py:129
#, fuzzy
#| msgid "Not required"
msgid "Secret key required"
msgstr "Не требуется"

#: enums.py:130
msgid "SEPA unsupported account"
msgstr ""

#: enums.py:131
#, fuzzy
#| msgid "Verification failed"
msgid "Shipping calculation failed"
msgstr "Проверка не удалась"

#: enums.py:132
msgid "SKU inactive"
msgstr ""

#: enums.py:133
msgid "State unsupported"
msgstr ""

#: enums.py:134
msgid "Tax id invalid"
msgstr ""

#: enums.py:135
#, fuzzy
#| msgid "Verification failed"
msgid "Taxes calculation failed"
msgstr "Проверка не удалась"

#: enums.py:136
msgid "Testmode charges only"
msgstr ""

#: enums.py:137
msgid "TLS version unsupported"
msgstr ""

#: enums.py:138
msgid "Token already used"
msgstr ""

#: enums.py:139
msgid "Token in use"
msgstr ""

#: enums.py:140
#, fuzzy
#| msgid "Transfer refund"
msgid "Transfers not allowed"
msgstr "Возврат перевода"

#: enums.py:141
#, fuzzy
#| msgid "Verification failed"
msgid "Upstream order creation failed"
msgstr "Проверка не удалась"

#: enums.py:142
msgid "URL invalid"
msgstr ""

#: enums.py:145
msgid "Invalid swipe data"
msgstr "Ошибка чтения магнитной ленты"

#: enums.py:149 enums.py:302
msgid "Standard"
msgstr "Standard"

#: enums.py:150
msgid "Express"
msgstr "Express"

#: enums.py:151
msgid "Custom"
msgstr "На заказ"

#: enums.py:155
msgid "Available"
msgstr "Доступно"

#: enums.py:156 enums.py:223 enums.py:308 enums.py:371 enums.py:413
#: enums.py:425 enums.py:437
msgid "Pending"
msgstr "в ожидании"

#: enums.py:160
msgid "Adjustment"
msgstr "Корректировка"

#: enums.py:161
msgid "Application fee"
msgstr "Абонентская плата"

#: enums.py:162
msgid "Application fee refund"
msgstr "Возврат абонентской платы"

#: enums.py:163
msgid "Charge"
msgstr "Расход"

#: enums.py:164
msgid "Network cost"
msgstr "Сетевая стоимость"

#: enums.py:165
msgid "Payment"
msgstr "Платеж"

#: enums.py:166
msgid "Payment failure refund"
msgstr "Возврат неудачного платежа"

#: enums.py:167
msgid "Payment refund"
msgstr "Возврат платежа"

#: enums.py:168
msgid "Payout"
msgstr "Выплата"

#: enums.py:169
msgid "Payout cancellation"
msgstr "Отмена выплаты"

#: enums.py:170
msgid "Payout failure"
msgstr "Сбой выплаты"

#: enums.py:171
msgid "Refund"
msgstr "Возврат"

#: enums.py:172
msgid "Stripe fee"
msgstr "Взнос в Stripe"

#: enums.py:173
msgid "Transfer"
msgstr "Перевод"

#: enums.py:174
msgid "Transfer refund"
msgstr "Возврат перевода"

#: enums.py:175
msgid "Validation"
msgstr "Проверка"

#: enums.py:179
msgid "Individual"
msgstr "Частное лицо"

#: enums.py:180
msgid "Company"
msgstr "Компания"

#: enums.py:184
msgid "New"
msgstr "Новый"

#: enums.py:185
msgid "Validated"
msgstr "Подтвержденный"

#: enums.py:186
msgid "Verified"
msgstr "Проверенный"

#: enums.py:187
msgid "Verification failed"
msgstr "Проверка не удалась"

#: enums.py:188
msgid "Errored"
msgstr "Ошибочный"

#: enums.py:192
msgid "Pass"
msgstr "Успех"

#: enums.py:193
msgid "Fail"
msgstr "Отказ"

#: enums.py:194
msgid "Unavailable"
msgstr "Недоступен"

#: enums.py:195
msgid "Unchecked"
msgstr "Не проверен"

#: enums.py:199
msgid "American Express"
msgstr "American Express"

#: enums.py:200
msgid "Diners Club"
msgstr "Diners Club"

#: enums.py:201
msgid "Discover"
msgstr "Discover"

#: enums.py:202
msgid "JCB"
msgstr "JCB"

#: enums.py:203
msgid "MasterCard"
msgstr "MasterCard"

#: enums.py:204
msgid "UnionPay"
msgstr ""

#: enums.py:205
msgid "Visa"
msgstr "Visa"

#: enums.py:206 enums.py:213 enums.py:403
msgid "Unknown"
msgstr "Неизвестная"

#: enums.py:210
msgid "Credit"
msgstr "Кредитная"

#: enums.py:211
msgid "Debit"
msgstr "Дебитовая"

#: enums.py:212
msgid "Prepaid"
msgstr "Предоплаченная"

#: enums.py:217
msgid "Apple Pay"
msgstr "Apple Pay"

#: enums.py:218
msgid "Android Pay"
msgstr "Android Pay"

#: enums.py:222 enums.py:414 enums.py:426 enums.py:438
msgid "Succeeded"
msgstr "Успешно"

#: enums.py:224 enums.py:311 enums.py:355 enums.py:370 enums.py:415
#: enums.py:427 enums.py:440
msgid "Failed"
msgstr "Не удалось"

#: enums.py:228
msgid "Once"
msgstr "Единоразовый"

#: enums.py:229
msgid "Multi-month"
msgstr "Многомесячный"

#: enums.py:230
msgid "Forever"
msgstr "Постоянный"

#: enums.py:234
msgid "Duplicate"
msgstr "Повторный"

#: enums.py:235 enums.py:408
msgid "Fraudulent"
msgstr "Мошеннический"

#: enums.py:236
msgid "Subscription canceled"
msgstr "Подписка отменена"

#: enums.py:237
msgid "Product unacceptable"
msgstr "Продукт неприемлем"

#: enums.py:238
msgid "Product not received"
msgstr "Продукт не получен"

#: enums.py:239
msgid "Unrecognized"
msgstr "Не распознано"

#: enums.py:240
msgid "Credit not processed"
msgstr "Кредит не обработан"

#: enums.py:241
msgid "General"
msgstr "Основной"

#: enums.py:242
msgid "Incorrect account details"
msgstr "Неверные данные счета"

#: enums.py:243
msgid "Insufficient funds"
msgstr "Недостаточно средств"

#: enums.py:244
msgid "Bank cannot process"
msgstr "Банк не может обработать"

#: enums.py:245
msgid "Debit not authorized"
msgstr "Дебит не разрешен"

#: enums.py:246
msgid "Customer-initiated"
msgstr "По инициативе заказчика"

#: enums.py:250
msgid "Warning needs response"
msgstr "Предупреждение требует ответа"

#: enums.py:251
msgid "Warning under review"
msgstr "Предупреждение в рассмотрении"

#: enums.py:252
msgid "Warning closed"
msgstr "Предупреждение закрыто"

#: enums.py:253
msgid "Needs response"
msgstr "Требуется ответ"

#: enums.py:254
msgid "Under review"
msgstr "В рассмотрении"

#: enums.py:255
msgid "Charge refunded"
msgstr "Платеж возвращен"

#: enums.py:256
msgid "Won"
msgstr "Выиграл"

#: enums.py:257
msgid "Lost"
msgstr "Проиграл"

#: enums.py:261
msgid "Dispute evidence"
msgstr "Доказательства по спору"

#: enums.py:262
msgid "Identity document"
msgstr "Удостоверение личности"

#: enums.py:263
msgid "Tax document user upload"
msgstr ""

#: enums.py:267
msgid "PDF"
msgstr "PDF"

#: enums.py:268
msgid "JPG"
msgstr "JPG"

#: enums.py:269
msgid "PNG"
msgstr "PNG"

#: enums.py:270
msgid "CSV"
msgstr "CSV"

#: enums.py:271
msgid "XLS"
msgstr "XLS"

#: enums.py:272
msgid "XLSX"
msgstr "XLSX"

#: enums.py:273
msgid "DOCX"
msgstr "DOCX"

#: enums.py:277
msgid "Charge automatically"
msgstr "Снимать автоматически"

#: enums.py:278
msgid "Send invoice"
msgstr "Отправить счет-фактуру"

#: enums.py:288
msgid "Bank account has been closed."
msgstr "Банковский счет закрыт."

#: enums.py:289
msgid "Bank account has been frozen."
msgstr "Банковский счет заморожен."

#: enums.py:290
msgid "Bank account has restrictions on payouts allowed."
msgstr "Банковский счет имеет ограничения по платежам."

#: enums.py:291
msgid "Destination bank account has changed ownership."
msgstr "Банковский счет назначения сменил владельца."

#: enums.py:292
msgid "Bank could not process payout."
msgstr "Банк не может обработать платеж."

#: enums.py:293
msgid "Debit transactions not approved on the bank account."
msgstr "Дебетовые транзакции не утверждены на банковском счете."

#: enums.py:294
msgid "Stripe account has insufficient funds."
msgstr "На счете Stripe недостаточно средств."

#: enums.py:295
msgid "Invalid account number"
msgstr "Неверный номер счета"

#: enums.py:296
msgid "Bank account does not support currency."
msgstr "Валюта не поддерживается банковским счетом."

#: enums.py:297
msgid "Bank account could not be located."
msgstr "Банковский счет не найден."

#: enums.py:298
msgid "Card no longer supported."
msgstr "Карта не поддерживается."

#: enums.py:303
msgid "Instant"
msgstr "Мгновенный"

#: enums.py:307
msgid "Paid"
msgstr "Оплачено"

#: enums.py:309
msgid "In transit"
msgstr "В пути"

#: enums.py:310 enums.py:354 enums.py:367 enums.py:416 enums.py:447
msgid "Canceled"
msgstr "Отменен"

#: enums.py:315 enums.py:395 enums.py:457
msgid "Bank account"
msgstr "Банковский счет"

#: enums.py:316 enums.py:380 enums.py:394 enums.py:456
msgid "Card"
msgstr "Карта"

#: enums.py:320
msgid "Last during period"
msgstr "Последний за период"

#: enums.py:321
msgid "Last ever"
msgstr "Последний"

#: enums.py:322
msgid "Max"
msgstr "Максимум"

#: enums.py:323
msgid "Sum"
msgstr "Сумма"

#: enums.py:327
msgid "Per unit"
msgstr "За единицу"

#: enums.py:328
msgid "Tiered"
msgstr "Многоуровневый"

#: enums.py:332
msgid "Day"
msgstr "День"

#: enums.py:333
msgid "Week"
msgstr "Неделя"

#: enums.py:334
msgid "Month"
msgstr "Месяц"

#: enums.py:335
msgid "Year"
msgstr "Год"

#: enums.py:339
msgid "Metered"
msgstr "Измеряемый"

#: enums.py:340
msgid "Licensed"
msgstr "Лицензированный"

#: enums.py:344
msgid "Graduated"
msgstr "Гарантированный"

#: enums.py:345
msgid "Volume-based"
msgstr "По объему"

#: enums.py:349
msgid "Good"
msgstr "Хороший"

#: enums.py:350
msgid "Service"
msgstr "Сервис"

#: enums.py:356
msgid "Timed out"
msgstr ""

#: enums.py:360
msgid "Redirect"
msgstr "Перенаправить"

#: enums.py:361
msgid "Receiver"
msgstr "Получатель"

#: enums.py:362
msgid "Code verification"
msgstr "Проверка кода"

#: enums.py:363
msgid "None"
msgstr "Отсутствует"

#: enums.py:368
msgid "Chargeable"
msgstr "Подлежащий оплате"

#: enums.py:369
msgid "Consumed"
msgstr "Потребленный"

#: enums.py:375
msgid "ACH Credit Transfer"
msgstr "Кредитный перевод ACH"

#: enums.py:376
msgid "ACH Debit"
msgstr "Дебит ACH"

#: enums.py:377
msgid "Alipay"
msgstr "Alipay"

#: enums.py:378
msgid "Bancontact"
msgstr "Bancontact"

#: enums.py:379
msgid "Bitcoin"
msgstr "Bitcoin"

#: enums.py:381
msgid "Card present"
msgstr "Подарочная карта"

#: enums.py:382
msgid "EPS"
msgstr "EPS"

#: enums.py:383
msgid "Giropay"
msgstr "Giropay"

#: enums.py:384
msgid "iDEAL"
msgstr "iDEAL"

#: enums.py:385
msgid "P24"
msgstr "P24"

#: enums.py:386
msgid "Paper check"
msgstr "Бумажный чек"

#: enums.py:387
msgid "SEPA Direct Debit"
msgstr "Прямой дебет SEPA"

#: enums.py:388
msgid "SEPA credit transfer"
msgstr "Кредитный перевод SEPA"

#: enums.py:389
msgid "SOFORT"
msgstr "SOFORT"

#: enums.py:390
msgid "3D Secure"
msgstr "3D Secure"

#: enums.py:396
msgid "Bitcoin receiver"
msgstr "Получатель Bitcoin"

#: enums.py:397
msgid "Alipay account"
msgstr "Счет Alipay"

#: enums.py:401
msgid "Lost or stolen card"
msgstr "Утерянная/украденная карта"

#: enums.py:402
msgid "Expired or canceled card"
msgstr "Истекшая/отозванная карта"

#: enums.py:407
msgid "Duplicate charge"
msgstr "Дублированный платеж"

#: enums.py:409
msgid "Requested by customer"
msgstr "По запросу покупателя"

#: enums.py:420
msgid "Reusable"
msgstr "Многоразовый"

#: enums.py:421
msgid "Single-use"
msgstr "Одноразовый"

#: enums.py:431
msgid "User-aborted"
msgstr "Отменен пользователем"

#: enums.py:432
msgid "Declined"
msgstr "Отказано"

#: enums.py:439
msgid "Not required"
msgstr "Не требуется"

#: enums.py:444
msgid "Trialing"
msgstr "Пробный период"

#: enums.py:445
msgid "Active"
msgstr "Активен"

#: enums.py:446
msgid "Past due"
msgstr "Просроченный"

#: enums.py:448
msgid "Unpaid"
msgstr "Не оплачен"

#: enums.py:458
msgid "Source"
msgstr "Источник"

#: models/billing.py:863
msgid "day"
msgstr "день"

#: models/billing.py:864
msgid "week"
msgstr "неделя"

#: models/billing.py:865
msgid "month"
msgstr "месяц"

#: models/billing.py:866
msgid "year"
msgstr "год"

#: models/billing.py:868
#, python-brace-format
msgid "{amount}/{interval}"
msgstr "{amount}/{interval}"

#: models/billing.py:871
msgid "days"
msgstr "дней"

#: models/billing.py:872
msgid "weeks"
msgstr "недель"

#: models/billing.py:873
msgid "months"
msgstr "месяцев"

#: models/billing.py:874
msgid "years"
msgstr "лет"

#: models/billing.py:876
#, python-brace-format
msgid "{amount} every {interval_count} {interval}"
msgstr "{amount} за {interval_count} {interval}"

#: templates/djstripe/admin/change_form.html:8
msgid "View on Stripe Dashboard"
msgstr "Посмотреть в панели управления Stripe"

#~ msgid "Загрузка налогового документа пользователя"
#~ msgstr "Document de taxes de l'utilisateur"


================================================
FILE: djstripe/management/__init__.py
================================================


================================================
FILE: djstripe/management/commands/__init__.py
================================================


================================================
FILE: djstripe/management/commands/djstripe_clear_expired_idempotency_keys.py
================================================
from django.core.management.base import BaseCommand

from ...utils import clear_expired_idempotency_keys


class Command(BaseCommand):
    help = "Deleted expired Stripe idempotency keys."

    def handle(self, *args, **options):
        clear_expired_idempotency_keys()


================================================
FILE: djstripe/management/commands/djstripe_init_customers.py
================================================
"""
init_customers command.
"""
from django.core.management.base import BaseCommand

from ...models import Customer
from ...settings import djstripe_settings


class Command(BaseCommand):
    """Create customer objects for existing subscribers that don't have one."""

    help = "Create customer objects for existing subscribers that don't have one"

    def handle(self, *args, **options):
        """
        Create Customer objects for Subscribers without Customer objects associated.
        """
        subscriber_qs = djstripe_settings.get_subscriber_model().objects.filter(
            djstripe_customers=None
        )
        if subscriber_qs:
            for subscriber in subscriber_qs:
                # use get_or_create in case of race conditions on large subscriber bases
                Customer.get_or_create(subscriber=subscriber)
                self.stdout.write(f"Created subscriber for {subscriber.email}")
        else:
            self.stdout.write("All Customers already have subscribers")


================================================
FILE: djstripe/management/commands/djstripe_process_events.py
================================================
from django.core.management.base import BaseCommand

from ... import models
from ...mixins import VerbosityAwareOutputMixin
from ...settings import djstripe_settings


class Command(VerbosityAwareOutputMixin, BaseCommand):
    """Command to process all Events.

    Optional arguments are provided to limit the number of Events processed.

    Note: this is only guaranteed go back at most 30 days based on the
    current limitation of stripe's events API. See: https://stripe.com/docs/api/events
    """

    help = (
        "Process all Events. Use optional arguments to limit the Events to process. "
        "Note: this is only guaranteed go back at most 30 days based on the current "
        "limitation of stripe's events API. See:  https://stripe.com/docs/api/events"
    )

    def add_arguments(self, parser):
        """Add optional arguments to filter Events by."""
        # Use a mutually exclusive group to prevent multiple arguments being
        # specified together.
        group = parser.add_mutually_exclusive_group()
        group.add_argument(
            "--ids",
            nargs="*",
            help="An optional space separated list of specific Event IDs to sync.",
        )
        group.add_argument(
            "--failed",
            action="store_true",
            help="Syncs and processes only the events that have failed webhooks.",
        )
        group.add_argument(
            "--type",
            help=(
                "A string containing a specific event name,"
                " or group of events using * as a wildcard."
                " The list will be filtered to include only"
                " events with a matching event property."
            ),
        )

    def handle(self, *args, **options):
        """Try to process Events listed from the API."""
        # Set the verbosity to determine how much we output, if at all.
        self.set_verbosity(options)

        event_ids = options["ids"]
        failed = options["failed"]
        type_filter = options["type"]

        # Args are mutually exclusive,
        # so output what we are doing based on that assumption.
        if failed:
            self.output("Processing all failed events")
        elif type_filter:
            self.output(f"Processing all events that match {type_filter}")
        elif event_ids:
            self.output(f"Processing specific events {event_ids}")
        else:
            self.output("Processing all available events")

        # Either use the specific event IDs to retrieve data, or use the api_list
        # if no specific event IDs are specified.
        if event_ids:
            listed_events = (
                models.Event.stripe_class.retrieve(
                    id=event_id,
                    api_key=djstripe_settings.STRIPE_SECRET_KEY,
                    stripe_version=djstripe_settings.STRIPE_API_VERSION,
                )
                for event_id in event_ids
            )
        else:
            list_kwargs = {}
            if failed:
                list_kwargs["delivery_success"] = False

            if type_filter:
                list_kwargs["type"] = type_filter

            listed_events = models.Event.api_list(**list_kwargs)

        self.process_events(listed_events)

    def process_events(self, listed_events):
        # Process each listed event. Capture failures and continue,
        # outputting debug information as verbosity dictates.
        count = 0
        total = 0
        for event_data in listed_events:
            try:
                total += 1
                event = models.Event.process(data=event_data)
                count += 1
                self.verbose_output(f"\tSynced Event {event.id}")
            except Exception as exception:
                self.verbose_output(f"\tFailed processing Event {event_data['id']}")
                self.output(f"\t{exception}")
                self.verbose_traceback()

        if total == 0:
            self.output("\t(no results)")
        else:
            self.output(f"\tProcessed {count} out of {total} Events")


================================================
FILE: djstripe/management/commands/djstripe_sync_customers.py
================================================
"""
sync_customer command.
"""
from django.core.management.base import BaseCommand

from ...settings import djstripe_settings
from ...sync import sync_subscriber


class Command(BaseCommand):
    """Sync subscriber data with stripe."""

    help = "Sync subscriber data with stripe."

    def handle(self, *args, **options):
        """Call sync_subscriber on Subscribers without customers associated to them."""
        qs = djstripe_settings.get_subscriber_model().objects.filter(
            djstripe_customers__isnull=True
        )
        count = 0
        total = qs.count()
        for subscriber in qs:
            count += 1
            pc = int(round(100 * (float(count) / float(total))))
            print(
                f"[{count}/{total} {pc}%] Syncing {subscriber.email} [{subscriber.pk}]"
            )
            sync_subscriber(subscriber)


================================================
FILE: djstripe/management/commands/djstripe_sync_models.py
================================================
"""Module for the djstripe_sync_model management command to sync
all Stripe objects to the local db.

Invoke like so:
    1) To sync all Objects for all API keys:
        python manage.py djstripe_sync_models

    2) To sync all Objects only for sk_test_XXX API key:
        python manage.py djstripe_sync_models --api-keys sk_test_XXX

    3) To sync all Objects only for sk_test_XXX and sk_test_YYY API keys:
        python manage.py djstripe_sync_models --api-keys sk_test_XXX sk_test_XXX
                                    OR
        python manage.py djstripe_sync_models --api-keys sk_test_XXX --api-keys sk_test_XXX

    4) To only sync Stripe Accounts for all API keys:
        python manage.py djstripe_sync_models Account

    5) To only sync Stripe Accounts for sk_test_XXX API key:
        python manage.py djstripe_sync_models Account --api-keys sk_test_XXX

    6) To only sync Stripe Accounts for sk_test_XXX and sk_test_YYY API keys:
        python manage.py djstripe_sync_models Account --api-keys sk_test_XXX sk_test_YYY

    7) To only sync Stripe Accounts and Charges for sk_test_XXX and sk_test_YYY API keys:
        python manage.py djstripe_sync_models Account Charge --api-keys sk_test_XXX sk_test_YYY
"""
import typing

from django.apps import apps
from django.core.exceptions import FieldDoesNotExist
from django.core.management.base import BaseCommand, CommandError
from django.db import models as django_models

from ... import enums, models
from ...models.base import StripeBaseModel
from ...settings import djstripe_settings

# TODO Improve performance using multiprocessing


class Command(BaseCommand):
    """Sync models from stripe."""

    help = "Sync models from stripe."

    def add_arguments(self, parser):
        parser.add_argument(
            "args",
            metavar="ModelName",
            nargs="*",
            help="restricts sync to these model names (default is to sync all "
            "supported models)",
        )
        # Named (optional) arguments
        parser.add_argument(
            "--api-keys",
            metavar="ApiKeys",
            nargs="*",
            type=str,
            action="extend",
            help="Specify the api_keys you would like to perform this sync for.",
        )

    def handle(self, *args, api_keys: typing.List[str], **options):
        app_label = "djstripe"
        app_config = apps.get_app_config(app_label)
        model_list: typing.List[models.StripeModel] = []

        if args:
            for model_label in args:
                try:
                    model = app_config.get_model(model_label)
                except LookupError:
                    raise CommandError(f"Unknown model: {app_label}.{model_label}")

                model_list.append(model)
        else:
            model_list = app_config.get_models()

        if api_keys is not None:
            for api_key in api_keys:
                try:
                    # check to ensure the given key is in the DB
                    models.APIKey.objects.get(secret=api_key)
                except models.APIKey.DoesNotExist:
                    raise CommandError(f"APIKey: {api_key} is not in the database.")

            api_qs = models.APIKey.objects.filter(secret__in=api_keys)
        else:
            # get all APIKey objects in the db
            api_qs = models.APIKey.objects.all()

            if not api_qs.exists():
                self.stderr.write(
                    "You don't have any API Keys in the database. Did you forget to add them?"
                )
                return

        for model in model_list:
            for api_key in api_qs:
                self.sync_model(model, api_key=api_key)

    def _should_sync_model(self, model):
        if not issubclass(model, StripeBaseModel):
            return False, "not a StripeModel"

        if model.stripe_class is None:
            return False, "no stripe_class"

        if not hasattr(model.stripe_class, "list"):
            if model in (
                models.ApplicationFeeRefund,
                models.LineItem,
                models.Source,
                models.TransferReversal,
                models.TaxId,
                models.UsageRecordSummary,
            ):
                return True, ""
            return False, "no stripe_class.list"

        if model is models.UpcomingInvoice:
            return False, "Upcoming Invoices are virtual only"

        if not djstripe_settings.STRIPE_LIVE_MODE:
            if model is models.ScheduledQueryRun:
                return False, "only available in live mode"

        return True, ""

    def sync_model(self, model, api_key: str):
        model_name = model.__name__

        should_sync, reason = self._should_sync_model(model)
        if not should_sync:
            self.stderr.write(f"Skipping {model}: {reason}")
            return

        self.stdout.write(f"Syncing {model_name} for key {api_key}:")

        count = 0
        try:
            # todo convert get_list_kwargs into a generator to make the code memory effecient.
            for list_kwargs in self.get_list_kwargs(model, api_key=api_key.secret):
                stripe_account = list_kwargs.get("stripe_account", "")

                if (
                    model is models.Account
                    and stripe_account
                    == models.Account.get_default_account(api_key=api_key.secret).id
                ):
                    # special case, since own account isn't returned by Account.api_list
                    stripe_obj = models.Account.stripe_class.retrieve(
                        api_key=api_key.secret,
                        stripe_version=djstripe_settings.STRIPE_API_VERSION,
                    )

                    djstripe_obj = model.sync_from_stripe_data(
                        stripe_obj, api_key=api_key.secret
                    )
                    self.stdout.write(
                        f"  id={djstripe_obj.id}, pk={djstripe_obj.pk} ({djstripe_obj} on {stripe_account} for {api_key})"
                    )

                    # syncing BankAccount and Card objects of Stripe Connected Express and Custom Accounts
                    self.sync_bank_accounts_and_cards(
                        djstripe_obj,
                        stripe_account=stripe_account,
                        api_key=api_key.secret,
                    )
                    count += 1

                try:
                    for stripe_obj in model.api_list(**list_kwargs):
                        # Skip model instances that throw an error
                        try:
                            djstripe_obj = model.sync_from_stripe_data(
                                stripe_obj, api_key=api_key.secret
                            )
                            self.stdout.write(
                                f"  id={djstripe_obj.id}, pk={djstripe_obj.pk} ({djstripe_obj} on {stripe_account} for {api_key})"
                            )
                            # syncing BankAccount and Card objects of Stripe Connected Express and Custom Accounts
                            self.sync_bank_accounts_and_cards(
                                djstripe_obj,
                                stripe_account=stripe_account,
                                api_key=api_key.secret,
                            )
                            count += 1
                        except Exception as e:
                            self.stderr.write(f"Skipping {stripe_obj.get('id')}: {e}")

                            continue
                except Exception as e:
                    self.stderr.write(f"Skipping: {e}")

            if count == 0:
                self.stdout.write("  (no results)")
            else:
                self.stdout.write(f"  Synced {count} {model_name} for {api_key}")

        except Exception as e:
            self.stderr.write(str(e))

    @classmethod
    def get_stripe_account(cls, api_key: str, *args, **kwargs):
        """Get set of all stripe account ids including the Platform Acccount"""
        accs_set = set()

        # special case, since own account isn't returned by Account.api_list
        stripe_platform_obj = models.Account.stripe_class.retrieve(
            api_key=api_key,
            stripe_version=djstripe_settings.STRIPE_API_VERSION,
        )
        accs_set.add(stripe_platform_obj.id)

        for stripe_connected_obj in models.Account.api_list(api_key=api_key, **kwargs):
            accs_set.add(stripe_connected_obj.id)

        return accs_set

    # todo simplfy this code by spliting into 1-2 functions
    @staticmethod
    def get_default_list_kwargs(model, accounts_set, api_key: str):
        """Returns default sequence of kwargs to sync
        all Stripe Accounts"""
        expand = []

        try:
            # get all forward and reverse relations for given cls
            for field in model.expand_fields:
                # add expand_field on the current model
                expand.append(f"data.{field}")

                try:
                    field_inst = model._meta.get_field(field)

                    # get expand_fields on Forward FK and OneToOneField relations on the current model
                    if isinstance(
                        field_inst,
                        (django_models.ForeignKey, django_models.OneToOneField),
                    ):
                        try:
                            for (
                                related_model_expand_field
                            ) in field_inst.related_model.expand_fields:
                                # add expand_field on the current model
                                expand.append(
                                    f"data.{field}.{related_model_expand_field}"
                                )

                                related_model_expand_field_inst = (
                                    field_inst.related_model._meta.get_field(
                                        related_model_expand_field
                                    )
                                )

                                # get expand_fields on Forward FK and OneToOneField relations on the current model
                                if isinstance(
                                    related_model_expand_field_inst,
                                    (
                                        django_models.ForeignKey,
                                        django_models.OneToOneField,
                                    ),
                                ):
                                    try:
                                        # need to prepend "field_name." to each of the entry in the expand_fields list
                                        related_model_expand_fields = map(
                                            lambda i: f"data.{field_inst.name}.{related_model_expand_field}.{i}",
                                            related_model_expand_field_inst.related_model.expand_fields,
                                        )

                                        expand = [
                                            *expand,
                                            *related_model_expand_fields,
                                        ]
                                    except AttributeError:
                                        continue
                        except AttributeError:
                            continue
                except FieldDoesNotExist:
                    pass
        except AttributeError:
            pass

        if expand:
            default_list_kwargs = [
                {
                    "expand": expand,
                    "stripe_account": account,
                    "api_key": api_key,
                }
                for account in accounts_set
            ]

        else:
            default_list_kwargs = [
                {
                    "stripe_account": account,
                    "api_key": api_key,
                }
                for account in accounts_set
            ]

        return default_list_kwargs

    @staticmethod
    def get_list_kwargs_il(default_list_kwargs):
        """Returns sequence of kwargs to sync Line Items for
        all Stripe Accounts"""

        all_list_kwargs = []

        for def_kwarg in default_list_kwargs:
            stripe_account = def_kwarg.get("stripe_account")
            api_key = def_kwarg.get("api_key")
            for stripe_invoice in models.Invoice.api_list(
                stripe_account=stripe_account, api_key=api_key
            ):
                all_list_kwargs.append({"id": stripe_invoice.id, **def_kwarg})

        return all_list_kwargs

    @staticmethod
    def get_list_kwargs_pm(default_list_kwargs):
        """Returns sequence of kwargs to sync Payment Methods for
        all Stripe Accounts"""

        all_list_kwargs = []
        payment_method_types = enums.PaymentMethodType.__members__

        for def_kwarg in default_list_kwargs:
            stripe_account = def_kwarg.get("stripe_account")
            api_key = def_kwarg.get("api_key")
            for stripe_customer in models.Customer.api_list(
                stripe_account=stripe_account, api_key=api_key
            ):
                for type in payment_method_types:
                    all_list_kwargs.append(
                        {"customer": stripe_customer.id, "type": type, **def_kwarg}
                    )

        return all_list_kwargs

    @staticmethod
    def get_list_kwargs_src(default_list_kwargs):
        """Returns sequence of kwargs to sync Sources for
        all Stripe Accounts"""

        all_list_kwargs = []
        for def_kwarg in default_list_kwargs:
            stripe_account = def_kwarg.get("stripe_account")
            api_key = def_kwarg.get("api_key")
            for stripe_customer in models.Customer.api_list(
                stripe_account=stripe_account, api_key=api_key
            ):
                all_list_kwargs.append({"id": stripe_customer.id, **def_kwarg})

        return all_list_kwargs

    @staticmethod
    def get_list_kwargs_si(default_list_kwargs):
        """Returns sequence of kwargs to sync Subscription Items for
        all Stripe Accounts"""

        all_list_kwargs = []
        for def_kwarg in default_list_kwargs:
            stripe_account = def_kwarg.get("stripe_account")
            api_key = def_kwarg.get("api_key")
            for subscription in models.Subscription.api_list(
                stripe_account=stripe_account, api_key=api_key
            ):
                all_list_kwargs.append({"subscription": subscription.id, **def_kwarg})
        return all_list_kwargs

    @staticmethod
    def get_list_kwargs_country_spec(default_list_kwargs):
        """Returns sequence of kwargs to sync Country Specs for
        all Stripe Accounts"""

        all_list_kwargs = []
        for def_kwarg in default_list_kwargs:
            all_list_kwargs.append({"limit": 50, **def_kwarg})

        return all_list_kwargs

    @staticmethod
    def get_list_kwargs_txcd(default_list_kwargs):
        """Returns sequence of kwargs to sync Tax Codes for
        all Stripe Accounts"""

        # tax codes are the same for all Stripe Accounts
        return [{}]

    @staticmethod
    def get_list_kwargs_trr(default_list_kwargs):
        """Returns sequence of kwargs to sync Transfer Reversals for
        all Stripe Accounts"""
        all_list_kwargs = []
        for def_kwarg in default_list_kwargs:
            stripe_account = def_kwarg.get("stripe_account")
            api_key = def_kwarg.get("api_key")
            for transfer in models.Transfer.api_list(
                stripe_account=stripe_account, api_key=api_key
            ):
                all_list_kwargs.append({"id": transfer.id, **def_kwarg})

        return all_list_kwargs

    @staticmethod
    def get_list_kwargs_fee_refund(default_list_kwargs):
        """Returns sequence of kwargs to sync Application Fee Refunds for
        all Stripe Accounts"""
        all_list_kwargs = []
        for def_kwarg in default_list_kwargs:
            stripe_account = def_kwarg.get("stripe_account")
            api_key = def_kwarg.get("api_key")
            for fee in models.ApplicationFee.api_list(
                stripe_account=stripe_account, api_key=api_key
            ):
                all_list_kwargs.append({"id": fee.id, **def_kwarg})

        return all_list_kwargs

    @staticmethod
    def get_list_kwargs_tax_id(default_list_kwargs):
        """Returns sequence of kwargs to sync Tax Ids for
        all Stripe Accounts"""
        all_list_kwargs = []
        for def_kwarg in default_list_kwargs:
            stripe_account = def_kwarg.get("stripe_account")
            api_key = def_kwarg.get("api_key")
            for customer in models.Customer.api_list(
                stripe_account=stripe_account, api_key=api_key
            ):
                all_list_kwargs.append({"id": customer.id, **def_kwarg})

        return all_list_kwargs

    @staticmethod
    def get_list_kwargs_sis(default_list_kwargs):
        """Returns sequence of kwargs to sync Usage Record Summarys for
        all Stripe Accounts"""
        all_list_kwargs = []
        for def_kwarg in default_list_kwargs:
            stripe_account = def_kwarg.get("stripe_account")
            api_key = def_kwarg.get("api_key")
            for subscription in models.Subscription.api_list(
                stripe_account=stripe_account, api_key=api_key
            ):
                for subscription_item in models.SubscriptionItem.api_list(
                    subscription=subscription.id,
                    stripe_account=stripe_account,
                    api_key=api_key,
                ):
                    all_list_kwargs.append({"id": subscription_item.id, **def_kwarg})

        return all_list_kwargs

    # todo handle supoorting double + nested fields like data.invoice.subscriptions.customer etc?
    def get_list_kwargs(self, model, api_key: str):
        """
        Returns a sequence of kwargs dicts to pass to model.api_list

        This allows us to sync models that require parameters to api_list

        :param model:
        :return: Sequence[dict]
        """

        list_kwarg_handlers_dict = {
            "LineItem": self.get_list_kwargs_il,
            "PaymentMethod": self.get_list_kwargs_pm,
            "Source": self.get_list_kwargs_src,
            "SubscriptionItem": self.get_list_kwargs_si,
            "CountrySpec": self.get_list_kwargs_country_spec,
            "TransferReversal": self.get_list_kwargs_trr,
            "ApplicationFeeRefund": self.get_list_kwargs_fee_refund,
            "TaxCode": self.get_list_kwargs_txcd,
            "TaxId": self.get_list_kwargs_tax_id,
            "UsageRecordSummary": self.get_list_kwargs_sis,
        }

        # get all Stripe Accounts for the given platform account.
        # note that we need to fetch from Stripe as we have no way of knowing that the ones in the local db are up to date
        # as this can also be the first time the user runs sync.
        accs_set = self.get_stripe_account(api_key=api_key)

        default_list_kwargs = self.get_default_list_kwargs(
            model, accs_set, api_key=api_key
        )

        handler = list_kwarg_handlers_dict.get(
            model.__name__, lambda _: default_list_kwargs
        )

        return handler(default_list_kwargs)

    def sync_bank_accounts_and_cards(self, instance, *, stripe_account, api_key):
        """
        Syncs Bank Accounts and Cards for both customers and all external accounts
        """
        type = getattr(instance, "type", None)
        kwargs = {
            "id": instance.id,
            "api_key": api_key,
            "stripe_account": stripe_account,
            "stripe_version": djstripe_settings.STRIPE_API_VERSION,
        }

        if type in (enums.AccountType.custom, enums.AccountType.express) and isinstance(
            instance, models.Account
        ):
            # fetch all Card and BankAccount objects associated with the instance
            items = models.Account.stripe_class.list_external_accounts(
                **kwargs
            ).auto_paging_iter()

            self.start_sync(items, instance, api_key=api_key)
        elif isinstance(instance, models.Customer):
            for object in ("card", "bank_account"):
                kwargs["object"] = object

                # fetch all Card and BankAccount objects associated with the instance
                items = models.Customer.stripe_class.list_sources(
                    **kwargs
                ).auto_paging_iter()

                self.start_sync(items, instance, api_key=api_key)

    def start_sync(self, items, instance, api_key: str):
        bank_count = 0
        card_count = 0
        for item in items:
            if item.object == "bank_account":
                model = models.BankAccount
                bank_count += 1
            elif item.object == "card":
                model = models.Card
                card_count += 1

            item_obj = model.sync_from_stripe_data(item, api_key=api_key)

            self.stdout.write(
                f"\tSyncing {model._meta.verbose_name} ({instance}): id={item_obj.id}, pk={item_obj.pk}"
            )

        if bank_count + card_count > 0:
            self.stdout.write(
                f"\tSynced {bank_count} BankAccounts and {card_count} Cards"
            )


================================================
FILE: djstripe/management/commands/djstripe_update_invoiceitem_ids.py
================================================
from django.core.management.base import BaseCommand
from django.db import transaction

from ...models.billing import InvoiceItem

no_results_msg = (
    "There are no more potential InvoiceItems to migrate. "
    "You do not need to run this command anymore."
)


class Command(BaseCommand):
    help = "Update old InvoiceItem IDs to the new, 2019-12-03 format."

    def add_arguments(self, parser):
        """Add optional arguments to filter Events by."""
        # Use a mutually exclusive group to prevent multiple arguments being
        # specified together.
        group = parser.add_mutually_exclusive_group()
        group.add_argument(
            "--i-understand",
            action="store_true",
            help="Run the command, once you've read the warning and understand it.",
        )

    def handle(self, *args, **options):
        invoice_items = InvoiceItem.objects.filter(id__contains="-il_")
        count = invoice_items.count()

        if not options["i_understand"]:
            self.stderr.write(
                "In Stripe API 2019-12-03, the format of invoice line items changed. "
                "This means that existing InvoiceItem objects with the old ID format "
                "may still be in the database and need to be migrated.\n"
                "This is a destructive migration, but this command will attempt to "
                "perform it as safely as possible.\n"
                "More information: https://stripe.com/docs/upgrades#2019-12-03\n\n"
            )
            if count:
                first_few_ids = invoice_items[:10].values_list("id", flat=True)
                self.stdout.write(f"I have found {count} InvoiceItems to migrate:")
                self.stdout.write(
                    "    " + ", ".join(first_few_ids) + f", … (and {count-10} more)"
                    if count > 10
                    else ""
                )
                self.stderr.write(
                    "To perform this migration, run this again with `--i-understand`."
                )
            else:
                self.stdout.write(no_results_msg)
            return

        if not count:
            self.stdout.write(no_results_msg)
            return

        for ii in invoice_items:
            old_id = ii.id
            new_id = old_id.partition("-")[2]
            if "-" in new_id or not new_id.startswith("il_"):
                self.stderr.write(
                    f"Don't know how to migrate {old_id!r}. This is a bug. "
                    "Could you report it?\n https://github.com/dj-stripe/dj-stripe"
                )
                continue

            self.stdout.write(f"Migrating {old_id} => {new_id}")
            with transaction.atomic():
                ii.id = new_id
                stripe_data = ii.api_retrieve()
                ii.save()
                InvoiceItem.sync_from_stripe_data(stripe_data)


================================================
FILE: djstripe/managers.py
================================================
"""
dj-stripe model managers
"""
import decimal

from django.db import models


class StripeModelManager(models.Manager):
    """Manager used in StripeModel."""

    pass


class SubscriptionManager(models.Manager):
    """Manager used in models.Subscription."""

    def started_during(self, year, month):
        """Return Subscriptions not in trial status between a certain time range."""
        return self.exclude(status="trialing").filter(
            start_date__year=year, start_date__month=month
        )

    def active(self):
        """Return active Subscriptions."""
        return self.filter(status="active")

    def canceled(self):
        """Return canceled Subscriptions."""
        return self.filter(status="canceled")

    def canceled_during(self
Download .txt
gitextract_rkwri8yg/

├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── api-change-notice.md
│   │   ├── bug_report.md
│   │   ├── documentation-issue-request.md
│   │   ├── feature-or-enhancement-proposal.md
│   │   ├── general-bug.md
│   │   ├── how-to-usage-question.md
│   │   ├── issue-with-webhooks-or-sync.md
│   │   ├── migration-upgrade-issue.md
│   │   └── other-issue.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   ├── install_poetry_action/
│   │   └── action.yaml
│   └── workflows/
│       ├── ci.yml
│       ├── codeql-analysis.yml
│       ├── docs.yml
│       └── linting.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .readthedocs.yml
├── LICENSE
├── djstripe/
│   ├── __init__.py
│   ├── admin/
│   │   ├── __init__.py
│   │   ├── actions.py
│   │   ├── admin.py
│   │   ├── admin_inline.py
│   │   ├── filters.py
│   │   ├── forms.py
│   │   ├── utils.py
│   │   └── views.py
│   ├── apps.py
│   ├── checks.py
│   ├── enums.py
│   ├── event_handlers.py
│   ├── exceptions.py
│   ├── fields.py
│   ├── locale/
│   │   ├── fr/
│   │   │   └── LC_MESSAGES/
│   │   │       └── django.po
│   │   └── ru/
│   │       └── LC_MESSAGES/
│   │           └── django.po
│   ├── management/
│   │   ├── __init__.py
│   │   └── commands/
│   │       ├── __init__.py
│   │       ├── djstripe_clear_expired_idempotency_keys.py
│   │       ├── djstripe_init_customers.py
│   │       ├── djstripe_process_events.py
│   │       ├── djstripe_sync_customers.py
│   │       ├── djstripe_sync_models.py
│   │       └── djstripe_update_invoiceitem_ids.py
│   ├── managers.py
│   ├── migrations/
│   │   ├── 0001_initial.py
│   │   ├── 0008_2_5.py
│   │   ├── 0009_2_6.py
│   │   ├── 0010_alter_customer_balance.py
│   │   ├── 0011_2_7.py
│   │   ├── 0012_auto_20221217_0559.py
│   │   ├── 0013_product_default_price.py
│   │   ├── 0014_lineitem.py
│   │   ├── 0015_alter_payout_destination.py
│   │   ├── 0016_alter_payout_destination.py
│   │   ├── 0017_invoiceorlineitem.py
│   │   ├── 0018_discount.py
│   │   ├── 0019_add_customer_discount.py
│   │   ├── __init__.py
│   │   └── sql/
│   │       ├── migrate_mysql_backward.sql
│   │       ├── migrate_mysql_forward.sql
│   │       ├── migrate_postgresql_backward.sql
│   │       ├── migrate_postgresql_forward.sql
│   │       ├── migrate_sqlite_backward.sql
│   │       └── migrate_sqlite_forward.sql
│   ├── mixins.py
│   ├── models/
│   │   ├── __init__.py
│   │   ├── account.py
│   │   ├── api.py
│   │   ├── base.py
│   │   ├── billing.py
│   │   ├── checkout.py
│   │   ├── connect.py
│   │   ├── core.py
│   │   ├── fraud.py
│   │   ├── orders.py
│   │   ├── payment_methods.py
│   │   ├── sigma.py
│   │   └── webhooks.py
│   ├── settings.py
│   ├── signals.py
│   ├── sync.py
│   ├── templates/
│   │   └── djstripe/
│   │       └── admin/
│   │           ├── add_form.html
│   │           ├── change_form.html
│   │           ├── confirm_action.html
│   │           └── webhook_endpoint/
│   │               ├── add_form.html
│   │               ├── change_form.html
│   │               └── delete_confirmation.html
│   ├── urls.py
│   ├── utils.py
│   ├── views.py
│   └── webhooks.py
├── docs/
│   ├── CONTRIBUTING.md
│   ├── README.md
│   ├── __init__.py
│   ├── api_keys.md
│   ├── api_versions.md
│   ├── history/
│   │   ├── 0_x.md
│   │   ├── 1_x.md
│   │   ├── 2_4_0.md
│   │   ├── 2_4_x.md
│   │   ├── 2_5_0.md
│   │   ├── 2_5_x.md
│   │   ├── 2_6_0.md
│   │   ├── 2_6_x.md
│   │   ├── 2_7_0.md
│   │   ├── 2_7_x.md
│   │   ├── 2_8_0.md
│   │   └── 2_x.md
│   ├── installation.md
│   ├── project/
│   │   ├── authors.md
│   │   ├── release_process.md
│   │   ├── sponsors.md
│   │   ├── support.md
│   │   └── test_fixtures.md
│   ├── reference/
│   │   ├── enums.md
│   │   ├── managers.md
│   │   ├── models.md
│   │   ├── project.md
│   │   ├── settings.md
│   │   └── utils.md
│   ├── stripe_elements_js.md
│   └── usage/
│       ├── creating_individual_charges.md
│       ├── creating_usage_record.md
│       ├── local_webhook_testing.md
│       ├── managing_subscriptions.md
│       ├── manually_syncing_with_stripe.md
│       ├── subscribing_customers.md
│       ├── using_stripe_checkout.md
│       ├── using_with_docker.md
│       └── webhooks.md
├── manage.py
├── mkdocs.yml
├── pyproject.toml
├── tests/
│   ├── __init__.py
│   ├── apps/
│   │   ├── __init__.py
│   │   ├── example/
│   │   │   ├── __init__.py
│   │   │   ├── forms.py
│   │   │   ├── management/
│   │   │   │   ├── __init__.py
│   │   │   │   └── commands/
│   │   │   │       ├── __init__.py
│   │   │   │       └── regenerate_test_fixtures.py
│   │   │   ├── templates/
│   │   │   │   ├── checkout.html
│   │   │   │   ├── checkout_success.html
│   │   │   │   ├── example_base.html
│   │   │   │   ├── payment_intent.html
│   │   │   │   ├── purchase_subscription.html
│   │   │   │   └── purchase_subscription_success.html
│   │   │   ├── urls.py
│   │   │   └── views.py
│   │   ├── testapp/
│   │   │   ├── __init__.py
│   │   │   ├── models.py
│   │   │   └── urls.py
│   │   ├── testapp_content/
│   │   │   ├── README.md
│   │   │   ├── __init__.py
│   │   │   ├── models.py
│   │   │   └── urls.py
│   │   └── testapp_namespaced/
│   │       ├── __init__.py
│   │       ├── models.py
│   │       └── urls.py
│   ├── conftest.py
│   ├── fields/
│   │   ├── admin.py
│   │   └── models.py
│   ├── fixtures/
│   │   ├── account_custom_acct_1IuHosQveW0ONQsd.json
│   │   ├── account_express_acct_1IuHosQveW0ONQsd.json
│   │   ├── account_standard_acct_1Fg9jUA3kq9o1aTc.json
│   │   ├── balance_transaction_txn_fake_ch_fakefakefakefakefake0001.json
│   │   ├── bank_account_ba_fakefakefakefakefake0003.json
│   │   ├── bank_account_ba_fakefakefakefakefake0004.json
│   │   ├── card_card_fakefakefakefakefake0001.json
│   │   ├── card_card_fakefakefakefakefake0002.json
│   │   ├── card_card_fakefakefakefakefake0003.json
│   │   ├── card_card_fakefakefakefakefake0004.json
│   │   ├── charge_ch_fakefakefakefakefake0001.json
│   │   ├── customer_cus_4QWKsZuuTHcs7X.json
│   │   ├── customer_cus_4UbFSo9tl62jqj.json
│   │   ├── customer_cus_6lsBvm5rJ0zyHc.json
│   │   ├── customer_cus_example_with_bank_account.json
│   │   ├── dispute_ch_fakefakefakefake01.json
│   │   ├── dispute_dp_fakefakefakefake01.json
│   │   ├── dispute_dp_fakefakefakefake02.json
│   │   ├── dispute_dp_funds_reinstated_full.json
│   │   ├── dispute_pi_fakefakefakefake01.json
│   │   ├── dispute_pm_fakefakefakefake01.json
│   │   ├── dispute_txn_fakefakefakefake01.json
│   │   ├── event_account_application_authorized.json
│   │   ├── event_account_application_deauthorized.json
│   │   ├── event_account_updated_custom.json
│   │   ├── event_account_updated_express.json
│   │   ├── event_account_updated_standard.json
│   │   ├── event_external_account_bank_account_created.json
│   │   ├── event_external_account_bank_account_deleted.json
│   │   ├── event_external_account_bank_account_updated.json
│   │   ├── event_external_account_card_created.json
│   │   ├── event_external_account_card_deleted.json
│   │   ├── event_external_account_card_updated.json
│   │   ├── invoice_in_fakefakefakefakefake0001.json
│   │   ├── invoice_in_fakefakefakefakefake0004.json
│   │   ├── line_item_il_invoice_item_fakefakefakefakefake0001.json
│   │   ├── line_item_il_invoice_item_fakefakefakefakefake0002.json
│   │   ├── order_order_fakefakefakefake0001.json
│   │   ├── payment_intent_pi_destination_charge.json
│   │   ├── payment_intent_pi_fakefakefakefakefake0001.json
│   │   ├── payment_method_card_fakefakefakefakefake0001.json
│   │   ├── payment_method_pm_fakefakefakefake0001.json
│   │   ├── payout_custom_bank_account.json
│   │   ├── payout_custom_card.json
│   │   ├── plan_gold21323.json
│   │   ├── plan_silver41294.json
│   │   ├── price_gold21323.json
│   │   ├── price_silver41294.json
│   │   ├── product_prod_fake1.json
│   │   ├── setup_intent_pi_destination_charge.json
│   │   ├── shipping_rate_shr_fakefakefakefakefake0001.json
│   │   ├── shipping_rate_shr_fakefakefakefakefake0002.json
│   │   ├── source_src_fakefakefakefakefake0001.json
│   │   ├── subscription_sub_fakefakefakefakefake0001.json
│   │   ├── subscription_sub_fakefakefakefakefake0002.json
│   │   ├── subscription_sub_fakefakefakefakefake0003.json
│   │   ├── subscription_sub_fakefakefakefakefake0004.json
│   │   ├── tax_code_txcd_fakefakefakefakefake0001.json
│   │   ├── tax_id_txi_fakefakefakefakefake0001.json
│   │   ├── tax_rate_txr_fakefakefakefakefake0001.json
│   │   ├── tax_rate_txr_fakefakefakefakefake0002.json
│   │   ├── usage_record_summary_sis_fakefakefakefakefake0001.json
│   │   └── webhook_endpoint_fake0001.json
│   ├── settings.py
│   ├── templates/
│   │   └── base.html
│   ├── test_account.py
│   ├── test_admin.py
│   ├── test_api_keys.py
│   ├── test_apikey.py
│   ├── test_balance_transaction.py
│   ├── test_bank_account.py
│   ├── test_card.py
│   ├── test_charge.py
│   ├── test_checks.py
│   ├── test_coupon.py
│   ├── test_customer.py
│   ├── test_discount.py
│   ├── test_dispute.py
│   ├── test_django.py
│   ├── test_enums.py
│   ├── test_event.py
│   ├── test_event_handlers.py
│   ├── test_fields.py
│   ├── test_file_link.py
│   ├── test_file_upload.py
│   ├── test_forms.py
│   ├── test_idempotency_keys.py
│   ├── test_integrations/
│   │   ├── README.md
│   │   └── __init__.py
│   ├── test_invoice.py
│   ├── test_invoiceitem.py
│   ├── test_line_item.py
│   ├── test_managers.py
│   ├── test_migrations.py
│   ├── test_mixins.py
│   ├── test_order.py
│   ├── test_payment_intent.py
│   ├── test_payment_method.py
│   ├── test_payout.py
│   ├── test_plan.py
│   ├── test_price.py
│   ├── test_product.py
│   ├── test_refund.py
│   ├── test_session.py
│   ├── test_settings.py
│   ├── test_setup_intent.py
│   ├── test_shipping_rate.py
│   ├── test_source.py
│   ├── test_stripe_model.py
│   ├── test_subscription.py
│   ├── test_subscription_item.py
│   ├── test_subscription_schedule.py
│   ├── test_sync.py
│   ├── test_tax_code.py
│   ├── test_tax_id.py
│   ├── test_tax_rates.py
│   ├── test_transfer.py
│   ├── test_transfer_reversal.py
│   ├── test_usage_record.py
│   ├── test_usage_record_summary.py
│   ├── test_utils.py
│   ├── test_views.py
│   ├── test_webhooks.py
│   └── urls.py
└── tox.ini
Download .txt
SYMBOL INDEX (1597 symbols across 124 files)

FILE: djstripe/admin/actions.py
  class CustomActionMixin (line 16) | class CustomActionMixin:
    method get_urls (line 21) | def get_urls(self):
    method get_admin_action_context (line 31) | def get_admin_action_context(self, queryset, action_name, form_class):
    method get_actions (line 74) | def get_actions(self, request):
    method _resync_instances (line 89) | def _resync_instances(self, request, queryset):
    method _sync_all_instances (line 97) | def _sync_all_instances(self, request, queryset):
    method changelist_view (line 104) | def changelist_view(self, request, extra_context=None):

FILE: djstripe/admin/admin.py
  class IdempotencyKeyAdmin (line 33) | class IdempotencyKeyAdmin(ReadOnlyMixin, admin.ModelAdmin):
  class WebhookEventTriggerAdmin (line 40) | class WebhookEventTriggerAdmin(ReadOnlyMixin, admin.ModelAdmin):
    method reprocess (line 56) | def reprocess(self, request, queryset):
    method get_queryset (line 64) | def get_queryset(self, request):
  class StripeModelAdmin (line 72) | class StripeModelAdmin(CustomActionMixin, admin.ModelAdmin):
    method __init__ (line 79) | def __init__(self, *args, **kwargs):
    method get_list_display (line 84) | def get_list_display(self, request):
    method get_list_filter (line 91) | def get_list_filter(self, request):
    method get_readonly_fields (line 94) | def get_readonly_fields(self, request, obj=None):
    method get_search_fields (line 97) | def get_search_fields(self, request):
    method get_fieldsets (line 100) | def get_fieldsets(self, request, obj=None):
    method get_queryset (line 110) | def get_queryset(self, request):
  class AccountAdmin (line 115) | class AccountAdmin(StripeModelAdmin):
  class APIKeyAdmin (line 122) | class APIKeyAdmin(admin.ModelAdmin):
    method get_readonly_fields (line 130) | def get_readonly_fields(self, request, obj=None):
    method get_fields (line 135) | def get_fields(self, request, obj=None):
    method get_form (line 140) | def get_form(self, request, obj=None, **kwargs):
    method get_queryset (line 145) | def get_queryset(self, request):
    method save_model (line 148) | def save_model(self, request: Any, obj, form: Any, change: Any) -> None:
  class BalanceTransactionAdmin (line 161) | class BalanceTransactionAdmin(ReadOnlyMixin, StripeModelAdmin):
  class ChargeAdmin (line 175) | class ChargeAdmin(StripeModelAdmin):
    method get_queryset (line 191) | def get_queryset(self, request):
  class CouponAdmin (line 206) | class CouponAdmin(StripeModelAdmin):
  class CustomerAdmin (line 221) | class CustomerAdmin(StripeModelAdmin):
    method get_queryset (line 241) | def get_queryset(self, request):
  class DiscountAdmin (line 252) | class DiscountAdmin(ReadOnlyMixin, StripeModelAdmin):
    method get_actions (line 262) | def get_actions(self, request):
  class DisputeAdmin (line 276) | class DisputeAdmin(ReadOnlyMixin, StripeModelAdmin):
  class EventAdmin (line 282) | class EventAdmin(ReadOnlyMixin, StripeModelAdmin):
  class FileAdmin (line 289) | class FileAdmin(StripeModelAdmin):
  class FileLinkAdmin (line 296) | class FileLinkAdmin(StripeModelAdmin):
    method get_queryset (line 300) | def get_queryset(self, request):
  class OrderAdmin (line 305) | class OrderAdmin(StripeModelAdmin):
  class PaymentIntentAdmin (line 319) | class PaymentIntentAdmin(StripeModelAdmin):
    method get_queryset (line 333) | def get_queryset(self, request):
  class PayoutAdmin (line 344) | class PayoutAdmin(StripeModelAdmin):
    method get_queryset (line 356) | def get_queryset(self, request):
  class SetupIntentAdmin (line 365) | class SetupIntentAdmin(StripeModelAdmin):
    method get_queryset (line 378) | def get_queryset(self, request):
  class SessionAdmin (line 393) | class SessionAdmin(StripeModelAdmin):
    method get_queryset (line 398) | def get_queryset(self, request):
  class InvoiceAdmin (line 403) | class InvoiceAdmin(StripeModelAdmin):
    method get_default_tax_rates (line 426) | def get_default_tax_rates(self, obj):
    method get_queryset (line 431) | def get_queryset(self, request):
  class LineItemAdmin (line 441) | class LineItemAdmin(StripeModelAdmin):
  class MandateAdmin (line 454) | class MandateAdmin(StripeModelAdmin):
    method get_queryset (line 459) | def get_queryset(self, request):
    method get_actions (line 462) | def get_actions(self, request):
  class PlanAdmin (line 476) | class PlanAdmin(StripeModelAdmin):
    method get_readonly_fields (line 479) | def get_readonly_fields(self, request, obj=None):
    method get_queryset (line 494) | def get_queryset(self, request):
  class PriceAdmin (line 504) | class PriceAdmin(StripeModelAdmin):
    method get_queryset (line 511) | def get_queryset(self, request):
  class ProductAdmin (line 521) | class ProductAdmin(StripeModelAdmin):
    method get_queryset (line 533) | def get_queryset(self, request):
  class RefundAdmin (line 538) | class RefundAdmin(StripeModelAdmin):
    method get_queryset (line 550) | def get_queryset(self, request):
  class SourceAdmin (line 555) | class SourceAdmin(StripeModelAdmin):
    method get_queryset (line 559) | def get_queryset(self, request):
  class PaymentMethodAdmin (line 568) | class PaymentMethodAdmin(StripeModelAdmin):
    method get_queryset (line 573) | def get_queryset(self, request):
  class CardAdmin (line 582) | class CardAdmin(StripeModelAdmin):
    method get_queryset (line 586) | def get_queryset(self, request):
  class BankAccountAdmin (line 600) | class BankAccountAdmin(StripeModelAdmin):
    method get_queryset (line 604) | def get_queryset(self, request):
  class ShippingRateAdmin (line 618) | class ShippingRateAdmin(StripeModelAdmin):
  class SubscriptionAdmin (line 625) | class SubscriptionAdmin(StripeModelAdmin):
    method get_actions (line 631) | def get_actions(self, request):
    method _cancel (line 638) | def _cancel(self, request, queryset):
    method get_queryset (line 643) | def get_queryset(self, request):
    method get_default_tax_rates (line 661) | def get_default_tax_rates(self, obj):
    method get_product_name (line 667) | def get_product_name(self, obj):
  class SubscriptionScheduleAdmin (line 673) | class SubscriptionScheduleAdmin(StripeModelAdmin):
    method _release_subscription_schedule (line 679) | def _release_subscription_schedule(self, request, queryset):
    method _cancel_subscription_schedule (line 687) | def _cancel_subscription_schedule(self, request, queryset):
    method get_actions (line 694) | def get_actions(self, request):
  class TaxCodeAdmin (line 707) | class TaxCodeAdmin(StripeModelAdmin):
  class TaxRateAdmin (line 713) | class TaxRateAdmin(StripeModelAdmin):
  class TransferAdmin (line 719) | class TransferAdmin(StripeModelAdmin):
  class TransferReversalAdmin (line 724) | class TransferReversalAdmin(StripeModelAdmin):
  class ApplicationFeeAdmin (line 729) | class ApplicationFeeAdmin(StripeModelAdmin):
  class ApplicationFeeReversalAdmin (line 734) | class ApplicationFeeReversalAdmin(StripeModelAdmin):
  class UsageRecordAdmin (line 739) | class UsageRecordAdmin(StripeModelAdmin):
    method get_queryset (line 742) | def get_queryset(self, request):
    method get_actions (line 745) | def get_actions(self, request):
  class UsageRecordSummaryAdmin (line 759) | class UsageRecordSummaryAdmin(StripeModelAdmin):
    method get_queryset (line 762) | def get_queryset(self, request):
  class WebhookEndpointAdmin (line 769) | class WebhookEndpointAdmin(CustomActionMixin, admin.ModelAdmin):
    method get_actions (line 785) | def get_actions(self, request):
    method get_form (line 793) | def get_form(self, request, obj=None, **kwargs):
    method get_readonly_fields (line 798) | def get_readonly_fields(self, request, obj=None):
    method get_fieldsets (line 811) | def get_fieldsets(self, request, obj=None):
    method get_changeform_initial_data (line 839) | def get_changeform_initial_data(self, request) -> Dict[str, str]:
    method delete_model (line 845) | def delete_model(self, request, obj: models.WebhookEndpoint):
    method get_queryset (line 857) | def get_queryset(self, request):

FILE: djstripe/admin/admin_inline.py
  class SubscriptionInline (line 11) | class SubscriptionInline(admin.StackedInline):
  class SubscriptionScheduleInline (line 21) | class SubscriptionScheduleInline(admin.StackedInline):
    method __init__ (line 30) | def __init__(self, parent_model, admin_site):
  class TaxIdInline (line 39) | class TaxIdInline(admin.TabularInline):
  class SubscriptionItemInline (line 56) | class SubscriptionItemInline(admin.StackedInline):
  class InvoiceItemInline (line 66) | class InvoiceItemInline(admin.StackedInline):
  class LineItemInline (line 76) | class LineItemInline(admin.StackedInline):

FILE: djstripe/admin/filters.py
  class BaseHasSourceListFilter (line 9) | class BaseHasSourceListFilter(admin.SimpleListFilter):
    method lookups (line 13) | def lookups(self, request, model_admin):
    method queryset (line 26) | def queryset(self, request, queryset):
  class CustomerHasSourceListFilter (line 41) | class CustomerHasSourceListFilter(BaseHasSourceListFilter):
  class InvoiceCustomerHasSourceListFilter (line 45) | class InvoiceCustomerHasSourceListFilter(BaseHasSourceListFilter):
  class CustomerSubscriptionStatusListFilter (line 49) | class CustomerSubscriptionStatusListFilter(admin.SimpleListFilter):
    method lookups (line 55) | def lookups(self, request, model_admin):
    method queryset (line 75) | def queryset(self, request, queryset):

FILE: djstripe/admin/forms.py
  class CustomActionForm (line 16) | class CustomActionForm(forms.Form):
    method __init__ (line 19) | def __init__(self, *args, **kwargs):
  class APIKeyAdminCreateForm (line 48) | class APIKeyAdminCreateForm(forms.ModelForm):
    class Meta (line 49) | class Meta:
    method _post_clean (line 53) | def _post_clean(self):
  class WebhookEndpointAdminBaseForm (line 67) | class WebhookEndpointAdminBaseForm(forms.ModelForm):
    method __init__ (line 68) | def __init__(self, *args, **kwargs):
    method _get_field_name (line 73) | def _get_field_name(self, stripe_field: Optional[str]) -> Optional[str]:
    method save (line 81) | def save(self, commit: bool = False):
  class WebhookEndpointAdminCreateForm (line 104) | class WebhookEndpointAdminCreateForm(WebhookEndpointAdminBaseForm):
    method __init__ (line 105) | def __init__(self, *args, **kwargs):
    class Meta (line 143) | class Meta:
    method _post_clean (line 159) | def _post_clean(self):
  class WebhookEndpointAdminEditForm (line 195) | class WebhookEndpointAdminEditForm(WebhookEndpointAdminBaseForm):
    class Meta (line 218) | class Meta:
    method get_initial_for_field (line 222) | def get_initial_for_field(self, field, field_name):
    method _post_clean (line 234) | def _post_clean(self):

FILE: djstripe/admin/utils.py
  class ReadOnlyMixin (line 6) | class ReadOnlyMixin:
    method has_add_permission (line 7) | def has_add_permission(self, request):
    method has_change_permission (line 10) | def has_change_permission(self, request, obj=None):
  function get_forward_relation_fields_for_model (line 14) | def get_forward_relation_fields_for_model(model):

FILE: djstripe/admin/views.py
  class ConfirmCustomAction (line 21) | class ConfirmCustomAction(FormView):
    method form_valid (line 25) | def form_valid(self, form):
    method form_invalid (line 52) | def form_invalid(self, form):
    method get_form_kwargs (line 70) | def get_form_kwargs(self):
    method _resync_instances (line 76) | def _resync_instances(self, request, queryset):
    method _sync_all_instances (line 94) | def _sync_all_instances(self, request, queryset):
    method _cancel (line 99) | def _cancel(self, request, queryset):
    method _release_subscription_schedule (line 108) | def _release_subscription_schedule(self, request, queryset):
    method _cancel_subscription_schedule (line 117) | def _cancel_subscription_schedule(self, request, queryset):

FILE: djstripe/apps.py
  class DjstripeAppConfig (line 10) | class DjstripeAppConfig(AppConfig):
    method ready (line 19) | def ready(self):

FILE: djstripe/checks.py
  function check_stripe_api_key (line 20) | def check_stripe_api_key(app_configs=None, **kwargs):
  function validate_stripe_api_version (line 74) | def validate_stripe_api_version(version):
  function check_stripe_api_version (line 90) | def check_stripe_api_version(app_configs=None, **kwargs):
  function check_stripe_api_host (line 116) | def check_stripe_api_host(app_configs=None, **kwargs):
  function check_webhook_secret (line 138) | def check_webhook_secret(app_configs=None, **kwargs):
  function _check_webhook_endpoint_validation (line 184) | def _check_webhook_endpoint_validation(secret, messages, endpoint=None):
  function check_webhook_validation (line 204) | def check_webhook_validation(app_configs=None, **kwargs):
  function check_webhook_endpoint_has_secret (line 256) | def check_webhook_endpoint_has_secret(app_configs=None, **kwargs):
  function check_subscriber_key_length (line 290) | def check_subscriber_key_length(app_configs=None, **kwargs):
  function check_djstripe_settings_foreign_key_to_field (line 316) | def check_djstripe_settings_foreign_key_to_field(app_configs=None, **kwa...
  function check_webhook_event_callback_accepts_api_key (line 351) | def check_webhook_event_callback_accepts_api_key(app_configs=None, **kwa...

FILE: djstripe/enums.py
  class EnumMetaClass (line 7) | class EnumMetaClass(type):
    method __init__ (line 8) | def __init__(cls, name, bases, classdict):
    method __prepare__ (line 16) | def __prepare__(cls, name, bases):
    method __new__ (line 19) | def __new__(cls, name, bases, classdict):
  class Enum (line 54) | class Enum(metaclass=EnumMetaClass):
  class APIKeyType (line 58) | class APIKeyType(Enum):
  class ApiErrorCode (line 68) | class ApiErrorCode(Enum):
  class AccountType (line 168) | class AccountType(Enum):
  class BalanceTransactionReportingCategory (line 174) | class BalanceTransactionReportingCategory(Enum):
  class BalanceTransactionStatus (line 209) | class BalanceTransactionStatus(Enum):
  class BalanceTransactionType (line 214) | class BalanceTransactionType(Enum):
  class BankAccountHolderType (line 254) | class BankAccountHolderType(Enum):
  class BankAccountStatus (line 259) | class BankAccountStatus(Enum):
  class BillingScheme (line 267) | class BillingScheme(Enum):
  class BusinessType (line 272) | class BusinessType(Enum):
  class CaptureMethod (line 279) | class CaptureMethod(Enum):
  class CardCheckResult (line 284) | class CardCheckResult(Enum):
  class CardBrand (line 291) | class CardBrand(Enum):
  class CardFundingType (line 302) | class CardFundingType(Enum):
  class CardTokenizationMethod (line 309) | class CardTokenizationMethod(Enum):
  class ChargeStatus (line 314) | class ChargeStatus(Enum):
  class ConfirmationMethod (line 320) | class ConfirmationMethod(Enum):
  class CouponDuration (line 325) | class CouponDuration(Enum):
  class CustomerTaxExempt (line 331) | class CustomerTaxExempt(Enum):
  class DisputeReason (line 337) | class DisputeReason(Enum):
  class DisputeStatus (line 353) | class DisputeStatus(Enum):
  class FilePurpose (line 364) | class FilePurpose(Enum):
  class FileType (line 383) | class FileType(Enum):
  class InvoiceBillingReason (line 393) | class InvoiceBillingReason(Enum):
  class InvoiceCollectionMethod (line 404) | class InvoiceCollectionMethod(Enum):
  class InvoiceStatus (line 409) | class InvoiceStatus(Enum):
  class InvoiceorLineItemType (line 417) | class InvoiceorLineItemType(Enum):
  class IntentUsage (line 423) | class IntentUsage(Enum):
  class IntentStatus (line 428) | class IntentStatus(Enum):
  class LineItem (line 446) | class LineItem(Enum):
  class MandateStatus (line 451) | class MandateStatus(Enum):
  class MandateType (line 457) | class MandateType(Enum):
  class OrderStatus (line 462) | class OrderStatus(Enum):
  class PaymentIntentStatus (line 472) | class PaymentIntentStatus(Enum):
  class SetupIntentStatus (line 487) | class SetupIntentStatus(Enum):
  class PaymentMethodType (line 503) | class PaymentMethodType(Enum):
  class PayoutFailureCode (line 536) | class PayoutFailureCode(Enum):
  class PayoutMethod (line 568) | class PayoutMethod(Enum):
  class PayoutSourceType (line 573) | class PayoutSourceType(Enum):
  class PayoutStatus (line 579) | class PayoutStatus(Enum):
  class PayoutType (line 587) | class PayoutType(Enum):
  class PaymentIntentCancellationReason (line 592) | class PaymentIntentCancellationReason(Enum):
  class PlanAggregateUsage (line 605) | class PlanAggregateUsage(Enum):
  class PlanInterval (line 612) | class PlanInterval(Enum):
  class PriceTiersMode (line 619) | class PriceTiersMode(Enum):
  class PriceType (line 624) | class PriceType(Enum):
  class PriceUsageType (line 629) | class PriceUsageType(Enum):
  class ProductType (line 639) | class ProductType(Enum):
  class SetupIntentCancellationReason (line 644) | class SetupIntentCancellationReason(Enum):
  class ScheduledQueryRunStatus (line 651) | class ScheduledQueryRunStatus(Enum):
  class SourceFlow (line 657) | class SourceFlow(Enum):
  class SourceStatus (line 664) | class SourceStatus(Enum):
  class SourceType (line 672) | class SourceType(Enum):
  class LegacySourceType (line 696) | class LegacySourceType(Enum):
  class RefundFailureReason (line 703) | class RefundFailureReason(Enum):
  class RefundReason (line 709) | class RefundReason(Enum):
  class RefundStatus (line 716) | class RefundStatus(Enum):
  class SessionBillingAddressCollection (line 723) | class SessionBillingAddressCollection(Enum):
  class SessionMode (line 728) | class SessionMode(Enum):
  class SourceUsage (line 734) | class SourceUsage(Enum):
  class SourceCodeVerificationStatus (line 739) | class SourceCodeVerificationStatus(Enum):
  class SourceRedirectFailureReason (line 745) | class SourceRedirectFailureReason(Enum):
  class SourceRedirectStatus (line 751) | class SourceRedirectStatus(Enum):
  class SubmitTypeStatus (line 758) | class SubmitTypeStatus(Enum):
  class SubscriptionScheduleEndBehavior (line 765) | class SubscriptionScheduleEndBehavior(Enum):
  class SubscriptionScheduleStatus (line 770) | class SubscriptionScheduleStatus(Enum):
  class SubscriptionStatus (line 778) | class SubscriptionStatus(Enum):
  class SubscriptionProrationBehavior (line 788) | class SubscriptionProrationBehavior(Enum):
  class ShippingRateType (line 794) | class ShippingRateType(Enum):
  class ShippingRateTaxBehavior (line 798) | class ShippingRateTaxBehavior(Enum):
  class TaxIdType (line 804) | class TaxIdType(Enum):
  class UsageAction (line 840) | class UsageAction(Enum):
  class WebhookEndpointStatus (line 845) | class WebhookEndpointStatus(Enum):
  class DjstripePaymentMethodType (line 850) | class DjstripePaymentMethodType(Enum):

FILE: djstripe/event_handlers.py
  function update_customer_helper (line 30) | def update_customer_helper(metadata, customer_id, subscriber_key):
  function customer_webhook_handler (line 52) | def customer_webhook_handler(event):
  function customer_discount_webhook_handler (line 82) | def customer_discount_webhook_handler(event):
  function customer_source_webhook_handler (line 118) | def customer_source_webhook_handler(event):
  function customer_subscription_webhook_handler (line 144) | def customer_subscription_webhook_handler(event):
  function customer_tax_id_webhook_handler (line 163) | def customer_tax_id_webhook_handler(event):
  function payment_method_handler (line 173) | def payment_method_handler(event):
  function account_application_webhook_handler (line 207) | def account_application_webhook_handler(event):
  function account_updated_webhook_handler (line 220) | def account_updated_webhook_handler(event):
  function charge_webhook_handler (line 233) | def charge_webhook_handler(event):
  function dispute_webhook_handler (line 246) | def dispute_webhook_handler(event):
  function other_object_webhook_handler (line 276) | def other_object_webhook_handler(event):
  class CrudType (line 328) | class CrudType(Enum):
    method determine (line 335) | def determine(cls, event, verb=None):
  function _handle_crud_like_event (line 356) | def _handle_crud_like_event(

FILE: djstripe/exceptions.py
  class MultipleSubscriptionException (line 6) | class MultipleSubscriptionException(Exception):
  class StripeObjectManipulationException (line 12) | class StripeObjectManipulationException(Exception):
  class InvalidStripeAPIKey (line 21) | class InvalidStripeAPIKey(ValueError):
  class ImpossibleAPIRequest (line 29) | class ImpossibleAPIRequest(Exception):

FILE: djstripe/fields.py
  class FieldDeconstructMixin (line 14) | class FieldDeconstructMixin:
    method deconstruct (line 23) | def deconstruct(self):
  class StripeForeignKey (line 32) | class StripeForeignKey(models.ForeignKey):
    method __init__ (line 35) | def __init__(self, *args, **kwargs):
    method deconstruct (line 41) | def deconstruct(self):
    method get_default (line 48) | def get_default(self):
  class PaymentMethodForeignKey (line 56) | class PaymentMethodForeignKey(FieldDeconstructMixin, models.ForeignKey):
    method __init__ (line 57) | def __init__(self, **kwargs):
  class InvoiceOrLineItemForeignKey (line 62) | class InvoiceOrLineItemForeignKey(models.ForeignKey):
    method __init__ (line 63) | def __init__(self, **kwargs):
  class StripePercentField (line 68) | class StripePercentField(FieldDeconstructMixin, models.DecimalField):
    method __init__ (line 71) | def __init__(self, *args, **kwargs):
  class StripeCurrencyCodeField (line 82) | class StripeCurrencyCodeField(FieldDeconstructMixin, models.CharField):
    method __init__ (line 87) | def __init__(self, *args, **kwargs):
  class StripeQuantumCurrencyAmountField (line 93) | class StripeQuantumCurrencyAmountField(FieldDeconstructMixin, models.Big...
  class StripeDecimalCurrencyAmountField (line 103) | class StripeDecimalCurrencyAmountField(FieldDeconstructMixin, models.Dec...
    method __init__ (line 114) | def __init__(self, *args, **kwargs):
    method stripe_to_db (line 123) | def stripe_to_db(self, data):
  class StripeEnumField (line 136) | class StripeEnumField(FieldDeconstructMixin, models.CharField):
    method __init__ (line 137) | def __init__(self, enum, *args, **kwargs):
    method deconstruct (line 144) | def deconstruct(self):
  class StripeIdField (line 150) | class StripeIdField(FieldDeconstructMixin, models.CharField):
    method __init__ (line 153) | def __init__(self, *args, **kwargs):
  class StripeDateTimeField (line 167) | class StripeDateTimeField(FieldDeconstructMixin, models.DateTimeField):
    method stripe_to_db (line 170) | def stripe_to_db(self, data):
  class JSONField (line 179) | class JSONField(FieldDeconstructMixin, BaseJSONField):

FILE: djstripe/management/commands/djstripe_clear_expired_idempotency_keys.py
  class Command (line 6) | class Command(BaseCommand):
    method handle (line 9) | def handle(self, *args, **options):

FILE: djstripe/management/commands/djstripe_init_customers.py
  class Command (line 10) | class Command(BaseCommand):
    method handle (line 15) | def handle(self, *args, **options):

FILE: djstripe/management/commands/djstripe_process_events.py
  class Command (line 8) | class Command(VerbosityAwareOutputMixin, BaseCommand):
    method add_arguments (line 23) | def add_arguments(self, parser):
    method handle (line 48) | def handle(self, *args, **options):
    method process_events (line 91) | def process_events(self, listed_events):

FILE: djstripe/management/commands/djstripe_sync_customers.py
  class Command (line 10) | class Command(BaseCommand):
    method handle (line 15) | def handle(self, *args, **options):

FILE: djstripe/management/commands/djstripe_sync_models.py
  class Command (line 42) | class Command(BaseCommand):
    method add_arguments (line 47) | def add_arguments(self, parser):
    method handle (line 65) | def handle(self, *args, api_keys: typing.List[str], **options):
    method _should_sync_model (line 104) | def _should_sync_model(self, model):
    method sync_model (line 132) | def sync_model(self, model, api_key: str):
    method get_stripe_account (line 207) | def get_stripe_account(cls, api_key: str, *args, **kwargs):
    method get_default_list_kwargs (line 225) | def get_default_list_kwargs(model, accounts_set, api_key: str):
    method get_list_kwargs_il (line 309) | def get_list_kwargs_il(default_list_kwargs):
    method get_list_kwargs_pm (line 326) | def get_list_kwargs_pm(default_list_kwargs):
    method get_list_kwargs_src (line 347) | def get_list_kwargs_src(default_list_kwargs):
    method get_list_kwargs_si (line 363) | def get_list_kwargs_si(default_list_kwargs):
    method get_list_kwargs_country_spec (line 378) | def get_list_kwargs_country_spec(default_list_kwargs):
    method get_list_kwargs_txcd (line 389) | def get_list_kwargs_txcd(default_list_kwargs):
    method get_list_kwargs_trr (line 397) | def get_list_kwargs_trr(default_list_kwargs):
    method get_list_kwargs_fee_refund (line 412) | def get_list_kwargs_fee_refund(default_list_kwargs):
    method get_list_kwargs_tax_id (line 427) | def get_list_kwargs_tax_id(default_list_kwargs):
    method get_list_kwargs_sis (line 442) | def get_list_kwargs_sis(default_list_kwargs):
    method get_list_kwargs (line 462) | def get_list_kwargs(self, model, api_key: str):
    method sync_bank_accounts_and_cards (line 500) | def sync_bank_accounts_and_cards(self, instance, *, stripe_account, ap...
    method start_sync (line 532) | def start_sync(self, items, instance, api_key: str):

FILE: djstripe/management/commands/djstripe_update_invoiceitem_ids.py
  class Command (line 12) | class Command(BaseCommand):
    method add_arguments (line 15) | def add_arguments(self, parser):
    method handle (line 26) | def handle(self, *args, **options):

FILE: djstripe/managers.py
  class StripeModelManager (line 9) | class StripeModelManager(models.Manager):
  class SubscriptionManager (line 15) | class SubscriptionManager(models.Manager):
    method started_during (line 18) | def started_during(self, year, month):
    method active (line 24) | def active(self):
    method canceled (line 28) | def canceled(self):
    method canceled_during (line 32) | def canceled_during(self, year, month):
    method started_plan_summary_for (line 36) | def started_plan_summary_for(self, year, month):
    method active_plan_summary (line 45) | def active_plan_summary(self):
    method canceled_plan_summary_for (line 51) | def canceled_plan_summary_for(self, year, month):
    method churn (line 62) | def churn(self):
  class TransferManager (line 69) | class TransferManager(models.Manager):
    method during (line 72) | def during(self, year, month):
    method paid_totals_for (line 76) | def paid_totals_for(self, year, month):
  class ChargeManager (line 83) | class ChargeManager(models.Manager):
    method during (line 86) | def during(self, year, month):
    method paid_totals_for (line 90) | def paid_totals_for(self, year, month):

FILE: djstripe/migrations/0001_initial.py
  class Migration (line 41) | class Migration(migrations.Migration):

FILE: djstripe/migrations/0008_2_5.py
  class Migration (line 11) | class Migration(migrations.Migration):

FILE: djstripe/migrations/0009_2_6.py
  class Migration (line 14) | class Migration(migrations.Migration):

FILE: djstripe/migrations/0010_alter_customer_balance.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: djstripe/migrations/0011_2_7.py
  class Migration (line 11) | class Migration(migrations.Migration):

FILE: djstripe/migrations/0012_auto_20221217_0559.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: djstripe/migrations/0013_product_default_price.py
  class Migration (line 10) | class Migration(migrations.Migration):

FILE: djstripe/migrations/0014_lineitem.py
  class Migration (line 11) | class Migration(migrations.Migration):

FILE: djstripe/migrations/0015_alter_payout_destination.py
  function get_sql_for_connection (line 8) | def get_sql_for_connection(schema_editor, direction: str) -> str:
  function forwards_func (line 28) | def forwards_func(apps, schema_editor):
  function reverse_func (line 37) | def reverse_func(apps, schema_editor):
  class Migration (line 46) | class Migration(migrations.Migration):

FILE: djstripe/migrations/0016_alter_payout_destination.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: djstripe/migrations/0017_invoiceorlineitem.py
  class Migration (line 11) | class Migration(migrations.Migration):

FILE: djstripe/migrations/0018_discount.py
  class Migration (line 10) | class Migration(migrations.Migration):

FILE: djstripe/migrations/0019_add_customer_discount.py
  class Migration (line 10) | class Migration(migrations.Migration):

FILE: djstripe/migrations/sql/migrate_mysql_backward.sql
  type `djstripe_payout_destination_id_a5fa55c2` (line 9) | CREATE INDEX `djstripe_payout_destination_id_a5fa55c2` ON `djstripe_payo...

FILE: djstripe/migrations/sql/migrate_mysql_forward.sql
  type `djstripe_payout_destination_clone_id_ff0fec04` (line 5) | CREATE INDEX `djstripe_payout_destination_clone_id_ff0fec04` ON `djstrip...

FILE: djstripe/migrations/sql/migrate_postgresql_backward.sql
  type "djstripe_payout" (line 13) | CREATE INDEX "djstripe_payout_destination_id_a5fa55c2" ON "djstripe_payo...

FILE: djstripe/migrations/sql/migrate_postgresql_forward.sql
  type "djstripe_payout" (line 7) | CREATE INDEX "djstripe_payout_destination_clone_id_ff0fec04" ON "djstrip...
  type "djstripe_payout" (line 8) | CREATE INDEX "djstripe_payout_destination_clone_id_ff0fec04_like" ON "dj...

FILE: djstripe/migrations/sql/migrate_sqlite_backward.sql
  type "new__djstripe_payout" (line 4) | CREATE TABLE "new__djstripe_payout" ("destination_clone_id" varchar(255)...
  type "djstripe_payout" (line 8) | CREATE INDEX "djstripe_payout_destination_clone_id_ff0fec04" ON "djstrip...
  type "djstripe_payout" (line 9) | CREATE INDEX "djstripe_payout_balance_transaction_id_a9393fb6" ON "djstr...
  type "djstripe_payout" (line 10) | CREATE INDEX "djstripe_payout_failure_balance_transaction_id_77d442db" O...
  type "djstripe_payout" (line 11) | CREATE INDEX "djstripe_payout_djstripe_owner_account_id_8aac4e8e" ON "dj...
  type "djstripe_payout" (line 17) | CREATE INDEX "djstripe_payout_destination_id_a5fa55c2" ON "djstripe_payo...
  type "new__djstripe_payout" (line 31) | CREATE TABLE "new__djstripe_payout" ("djstripe_id" integer NOT NULL PRIM...
  type "djstripe_payout" (line 35) | CREATE INDEX "djstripe_payout_destination_id_a5fa55c2" ON "djstripe_payo...
  type "djstripe_payout" (line 36) | CREATE INDEX "djstripe_payout_balance_transaction_id_a9393fb6" ON "djstr...
  type "djstripe_payout" (line 37) | CREATE INDEX "djstripe_payout_failure_balance_transaction_id_77d442db" O...
  type "djstripe_payout" (line 38) | CREATE INDEX "djstripe_payout_djstripe_owner_account_id_8aac4e8e" ON "dj...

FILE: djstripe/migrations/sql/migrate_sqlite_forward.sql
  type "djstripe_payout" (line 5) | CREATE INDEX "djstripe_payout_destination_clone_id_ff0fec04" ON "djstrip...
  type "new__djstripe_payout" (line 18) | CREATE TABLE "new__djstripe_payout" ("destination_id" varchar(255) NULL ...
  type "djstripe_payout" (line 22) | CREATE INDEX "djstripe_payout_destination_id_a5fa55c2" ON "djstripe_payo...
  type "djstripe_payout" (line 23) | CREATE INDEX "djstripe_payout_balance_transaction_id_a9393fb6" ON "djstr...
  type "djstripe_payout" (line 24) | CREATE INDEX "djstripe_payout_failure_balance_transaction_id_77d442db" O...
  type "djstripe_payout" (line 25) | CREATE INDEX "djstripe_payout_djstripe_owner_account_id_8aac4e8e" ON "dj...

FILE: djstripe/mixins.py
  class PaymentsContextMixin (line 11) | class PaymentsContextMixin:
    method get_context_data (line 14) | def get_context_data(self, **kwargs):
  class SubscriptionMixin (line 26) | class SubscriptionMixin(PaymentsContextMixin):
    method get_context_data (line 29) | def get_context_data(self, *args, **kwargs):
  class VerbosityAwareOutputMixin (line 40) | class VerbosityAwareOutputMixin:
    method set_verbosity (line 45) | def set_verbosity(self, options):
    method output (line 49) | def output(self, arg):
    method verbose_output (line 54) | def verbose_output(self, arg):
    method verbose_traceback (line 59) | def verbose_traceback(self):

FILE: djstripe/models/account.py
  class Account (line 12) | class Account(StripeModel):
    method get_stripe_dashboard_url (line 92) | def get_stripe_dashboard_url(self) -> str:
    method default_api_key (line 100) | def default_api_key(self) -> str:
    method get_default_api_key (line 103) | def get_default_api_key(self, livemode: bool = None) -> str:
    method business_url (line 119) | def business_url(self) -> str:
    method get_default_account (line 128) | def get_default_account(cls, api_key=djstripe_settings.STRIPE_SECRET_K...
    method get_or_retrieve_for_api_key (line 141) | def get_or_retrieve_for_api_key(cls, api_key: str):
    method __str__ (line 149) | def __str__(self):
    method api_reject (line 158) | def api_reject(self, api_key=None, stripe_account=None, **kwargs):
    method _create_from_stripe_object (line 183) | def _create_from_stripe_object(
    method branding_icon (line 212) | def branding_icon(self):
    method branding_logo (line 219) | def branding_logo(self):
    method _attach_objects_post_save_hook (line 225) | def _attach_objects_post_save_hook(

FILE: djstripe/models/api.py
  function generate_api_key_id (line 19) | def generate_api_key_id() -> str:
  function get_api_key_details_by_prefix (line 25) | def get_api_key_details_by_prefix(api_key: str):
  class APIKeyManager (line 40) | class APIKeyManager(models.Manager):
    method get_or_create_by_api_key (line 41) | def get_or_create_by_api_key(self, secret: str):
  class APIKey (line 48) | class APIKey(StripeModel):
    method get_stripe_dashboard_url (line 73) | def get_stripe_dashboard_url(self):
    method __str__ (line 76) | def __str__(self):
    method clean (line 79) | def clean(self):
    method refresh_account (line 86) | def refresh_account(self, commit=True):
    method secret_redacted (line 117) | def secret_redacted(self) -> str:

FILE: djstripe/models/base.py
  class StripeBaseModel (line 27) | class StripeBaseModel(models.Model):
    class Meta (line 33) | class Meta:
    method api_list (line 37) | def api_list(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kwargs):
  class StripeModel (line 57) | class StripeModel(StripeBaseModel):
    class Meta (line 104) | class Meta(StripeBaseModel.Meta):
    method _get_base_stripe_dashboard_url (line 108) | def _get_base_stripe_dashboard_url(self):
    method get_stripe_dashboard_url (line 117) | def get_stripe_dashboard_url(self) -> str:
    method default_api_key (line 127) | def default_api_key(self) -> str:
    method _get_stripe_account_id (line 134) | def _get_stripe_account_id(self, api_key=None) -> Optional[str]:
    method api_retrieve (line 183) | def api_retrieve(self, api_key=None, stripe_account=None):
    method _api_create (line 207) | def _api_create(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kw...
    method _api_delete (line 222) | def _api_delete(self, api_key=None, stripe_account=None, **kwargs):
    method _api_update (line 246) | def _api_update(self, api_key=None, stripe_account=None, **kwargs):
    method _manipulate_stripe_object_hook (line 271) | def _manipulate_stripe_object_hook(cls, data):
    method _find_owner_account (line 280) | def _find_owner_account(cls, data, api_key=djstripe_settings.STRIPE_SE...
    method _stripe_object_to_record (line 312) | def _stripe_object_to_record(
    method _stripe_object_field_to_foreign_key (line 416) | def _stripe_object_field_to_foreign_key(
    method is_valid_object (line 528) | def is_valid_object(cls, data):
    method _attach_objects_hook (line 538) | def _attach_objects_hook(
    method _attach_objects_post_save_hook (line 554) | def _attach_objects_post_save_hook(
    method _create_from_stripe_object (line 599) | def _create_from_stripe_object(
    method _get_or_create_from_stripe_object (line 659) | def _get_or_create_from_stripe_object(
    method _stripe_object_to_customer (line 773) | def _stripe_object_to_customer(
    method _stripe_object_to_default_tax_rates (line 797) | def _stripe_object_to_default_tax_rates(
    method _stripe_object_to_tax_rates (line 819) | def _stripe_object_to_tax_rates(
    method _stripe_object_set_total_tax_amounts (line 839) | def _stripe_object_set_total_tax_amounts(
    method _stripe_object_to_line_items (line 879) | def _stripe_object_to_line_items(
    method _stripe_object_to_subscription_items (line 922) | def _stripe_object_to_subscription_items(
    method _stripe_object_to_refunds (line 960) | def _stripe_object_to_refunds(
    method sync_from_stripe_data (line 991) | def sync_from_stripe_data(
    method _get_or_retrieve (line 1042) | def _get_or_retrieve(cls, id, stripe_account=None, **kwargs):
    method __str__ (line 1067) | def __str__(self):
  class IdempotencyKey (line 1071) | class IdempotencyKey(models.Model):
    class Meta (line 1081) | class Meta:
    method __str__ (line 1084) | def __str__(self):
    method is_expired (line 1088) | def is_expired(self) -> bool:

FILE: djstripe/models/billing.py
  class DjstripeInvoiceTotalTaxAmount (line 37) | class DjstripeInvoiceTotalTaxAmount(models.Model):
    class Meta (line 61) | class Meta:
  class DjstripeUpcomingInvoiceTotalTaxAmount (line 66) | class DjstripeUpcomingInvoiceTotalTaxAmount(models.Model):
    class Meta (line 90) | class Meta:
  class Coupon (line 94) | class Coupon(StripeModel):
    class Meta (line 172) | class Meta(StripeModel.Meta):
    method __str__ (line 175) | def __str__(self):
    method human_readable_amount (line 181) | def human_readable_amount(self):
    method human_readable (line 191) | def human_readable(self):
  class Discount (line 202) | class Discount(StripeModel):
    method is_valid_object (line 275) | def is_valid_object(cls, data):
  class BaseInvoice (line 282) | class BaseInvoice(StripeModel):
    class Meta (line 638) | class Meta(StripeModel.Meta):
    method __str__ (line 642) | def __str__(self):
    method upcoming (line 648) | def upcoming(
    method retry (line 717) | def retry(self):
    method _attach_objects_post_save_hook (line 731) | def _attach_objects_post_save_hook(
    method plan (line 752) | def plan(self) -> Optional["Plan"]:
  class Invoice (line 780) | class Invoice(BaseInvoice):
    method _attach_objects_post_save_hook (line 828) | def _attach_objects_post_save_hook(
  class UpcomingInvoice (line 853) | class UpcomingInvoice(BaseInvoice):
    method __init__ (line 873) | def __init__(self, *args, **kwargs):
    method get_stripe_dashboard_url (line 880) | def get_stripe_dashboard_url(self):
    method _attach_objects_hook (line 883) | def _attach_objects_hook(
    method _attach_objects_post_save_hook (line 894) | def _attach_objects_post_save_hook(
    method invoiceitems (line 930) | def invoiceitems(self):
    method lineitems (line 951) | def lineitems(self):
    method default_tax_rates (line 966) | def default_tax_rates(self):
    method total_tax_amounts (line 974) | def total_tax_amounts(self):
    method id (line 984) | def id(self):
    method id (line 988) | def id(self, value):
    method save (line 991) | def save(self, *args, **kwargs):
  class InvoiceItem (line 995) | class InvoiceItem(StripeModel):
    method _manipulate_stripe_object_hook (line 1104) | def _manipulate_stripe_object_hook(cls, data):
    method _attach_objects_post_save_hook (line 1110) | def _attach_objects_post_save_hook(
    method __str__ (line 1133) | def __str__(self):
    method get_stripe_dashboard_url (line 1136) | def get_stripe_dashboard_url(self):
    method api_retrieve (line 1139) | def api_retrieve(self, *args, **kwargs):
  class LineItem (line 1150) | class LineItem(StripeModel):
    method _manipulate_stripe_object_hook (line 1242) | def _manipulate_stripe_object_hook(cls, data):
    method _attach_objects_post_save_hook (line 1248) | def _attach_objects_post_save_hook(
    method api_list (line 1264) | def api_list(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kwargs):
  class InvoiceOrLineItem (line 1295) | class InvoiceOrLineItem(models.Model):
    method _model_type (line 1311) | def _model_type(cls, id_):
    method _get_or_create_from_stripe_object (line 1319) | def _get_or_create_from_stripe_object(
  class Plan (line 1356) | class Plan(StripeModel):
    class Meta (line 1490) | class Meta(object):
    method get_or_create (line 1494) | def get_or_create(cls, **kwargs):
    method create (line 1503) | def create(cls, **kwargs):
    method __str__ (line 1517) | def __str__(self):
    method amount_in_cents (line 1523) | def amount_in_cents(self):
    method human_readable_price (line 1527) | def human_readable_price(self) -> str:
  class Subscription (line 1573) | class Subscription(StripeModel):
    method api_list (line 1819) | def api_list(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kwargs):
    method update (line 1834) | def update(self, plan: Union[StripeModel, str] = None, **kwargs):
    method extend (line 1855) | def extend(self, delta):
    method cancel (line 1875) | def cancel(self, at_period_end: bool = False, **kwargs):
    method reactivate (line 1935) | def reactivate(self):
    method is_period_current (line 1953) | def is_period_current(self):
    method is_status_current (line 1962) | def is_status_current(self):
    method is_status_temporarily_current (line 1970) | def is_status_temporarily_current(self):
    method is_valid (line 1989) | def is_valid(self):
    method _attach_objects_post_save_hook (line 2003) | def _attach_objects_post_save_hook(
  class SubscriptionItem (line 2025) | class SubscriptionItem(StripeModel):
    method _attach_objects_post_save_hook (line 2091) | def _attach_objects_post_save_hook(
  class SubscriptionSchedule (line 2109) | class SubscriptionSchedule(StripeModel):
    method release (line 2186) | def release(self, api_key=None, stripe_account=None, **kwargs):
    method cancel (line 2218) | def cancel(self, api_key=None, stripe_account=None, **kwargs):
    method update (line 2246) | def update(self, api_key=None, stripe_account=None, **kwargs):
  class ShippingRate (line 2263) | class ShippingRate(StripeModel):
    class Meta (line 2315) | class Meta(StripeModel.Meta):
    method __str__ (line 2318) | def __str__(self):
  class TaxCode (line 2328) | class TaxCode(StripeModel):
    class Meta (line 2343) | class Meta(StripeModel.Meta):
    method __str__ (line 2346) | def __str__(self):
    method _find_owner_account (line 2350) | def _find_owner_account(cls, data, api_key=djstripe_settings.STRIPE_SE...
  class TaxId (line 2355) | class TaxId(StripeModel):
    method __str__ (line 2381) | def __str__(self):
    class Meta (line 2384) | class Meta(StripeModel.Meta):
    method _api_create (line 2388) | def _api_create(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kw...
    method api_retrieve (line 2407) | def api_retrieve(self, api_key=None, stripe_account=None):
    method api_list (line 2434) | def api_list(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kwargs):
  class TaxRate (line 2450) | class TaxRate(StripeModel):
    method __str__ (line 2506) | def __str__(self):
    class Meta (line 2509) | class Meta(StripeModel.Meta):
  class UsageRecord (line 2513) | class UsageRecord(StripeModel):
    method __str__ (line 2550) | def __str__(self):
    method _api_create (line 2554) | def _api_create(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kw...
    method create (line 2582) | def create(cls, **kwargs):
  class UsageRecordSummary (line 2589) | class UsageRecordSummary(StripeModel):
    method __str__ (line 2639) | def __str__(self):
    method _manipulate_stripe_object_hook (line 2643) | def _manipulate_stripe_object_hook(cls, data):
    method api_list (line 2650) | def api_list(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kwargs):

FILE: djstripe/models/checkout.py
  class Session (line 11) | class Session(StripeModel):
    method _attach_objects_post_save_hook (line 109) | def _attach_objects_post_save_hook(

FILE: djstripe/models/connect.py
  class ApplicationFee (line 22) | class ApplicationFee(StripeModel):
  class ApplicationFeeRefund (line 70) | class ApplicationFeeRefund(StripeModel):
  class CountrySpec (line 99) | class CountrySpec(StripeBaseModel):
    method sync_from_stripe_data (line 133) | def sync_from_stripe_data(
    method api_retrieve (line 163) | def api_retrieve(self, api_key: str = None, stripe_account=None):
  class Transfer (line 175) | class Transfer(StripeModel):
    method fee (line 242) | def fee(self):
    method __str__ (line 246) | def __str__(self):
    method _attach_objects_post_save_hook (line 257) | def _attach_objects_post_save_hook(
    method get_stripe_dashboard_url (line 277) | def get_stripe_dashboard_url(self) -> str:
  class TransferReversal (line 285) | class TransferReversal(StripeModel):
    method __str__ (line 315) | def __str__(self):
    method _api_create (line 319) | def _api_create(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kw...
    method api_retrieve (line 341) | def api_retrieve(self, api_key=None, stripe_account=None):
    method api_list (line 368) | def api_list(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kwargs):
    method is_valid_object (line 384) | def is_valid_object(cls, data):

FILE: djstripe/models/core.py
  function _sanitise_price (line 33) | def _sanitise_price(price=None, plan=None, **kwargs):
  class BalanceTransaction (line 53) | class BalanceTransaction(StripeModel):
    method __str__ (line 90) | def __str__(self):
    method get_source_class (line 95) | def get_source_class(self):
    method get_source_instance (line 101) | def get_source_instance(self):
    method get_stripe_dashboard_url (line 104) | def get_stripe_dashboard_url(self):
  class Charge (line 108) | class Charge(StripeModel):
    method __str__ (line 364) | def __str__(self):
    method fee (line 369) | def fee(self):
    method human_readable_status (line 374) | def human_readable_status(self) -> str:
    method fraudulent (line 384) | def fraudulent(self) -> bool:
    method _calculate_refund_amount (line 389) | def _calculate_refund_amount(self, amount: Optional[Decimal]) -> int:
    method refund (line 400) | def refund(self, amount: Decimal = None, reason: str = None) -> "Charge":
    method capture (line 420) | def capture(self, **kwargs) -> "Charge":
    method _attach_objects_post_save_hook (line 434) | def _attach_objects_post_save_hook(
  class Mandate (line 451) | class Mandate(StripeModel):
  class Product (line 487) | class Product(StripeModel):
    method __str__ (line 607) | def __str__(self):
  class Customer (line 620) | class Customer(StripeModel):
    class Meta (line 764) | class Meta(StripeModel.Meta):
    method __str__ (line 767) | def __str__(self):
    method _manipulate_stripe_object_hook (line 774) | def _manipulate_stripe_object_hook(cls, data):
    method get_or_create (line 798) | def get_or_create(
    method create (line 832) | def create(cls, subscriber, idempotency_key=None, stripe_account=None):
    method credits (line 857) | def credits(self):
    method customer_payment_methods (line 864) | def customer_payment_methods(self):
    method pending_charges (line 876) | def pending_charges(self):
    method subscribe (line 882) | def subscribe(self, *, items=None, price=None, plan=None, **kwargs):
    method charge (line 922) | def charge(
    method add_invoice_item (line 962) | def add_invoice_item(
    method add_card (line 1039) | def add_card(self, source, set_default=True):
    method add_payment_method (line 1072) | def add_payment_method(self, payment_method, set_default=True):
    method purge (line 1102) | def purge(self):
    method _get_valid_subscriptions (line 1140) | def _get_valid_subscriptions(self):
    method is_subscribed_to (line 1149) | def is_subscribed_to(self, product: Union[Product, str]) -> bool:
    method has_any_active_subscription (line 1168) | def has_any_active_subscription(self):
    method active_subscriptions (line 1178) | def active_subscriptions(self):
    method valid_subscriptions (line 1189) | def valid_subscriptions(self):
    method subscription (line 1202) | def subscription(self):
    method send_invoice (line 1223) | def send_invoice(self):
    method retry_unpaid_invoices (line 1240) | def retry_unpaid_invoices(self):
    method add_coupon (line 1251) | def add_coupon(self, coupon, idempotency_key=None):
    method upcoming_invoice (line 1267) | def upcoming_invoice(self, **kwargs):
    method _attach_objects_post_save_hook (line 1280) | def _attach_objects_post_save_hook(
    method _attach_objects_hook (line 1323) | def _attach_objects_hook(
    method _sync_invoices (line 1350) | def _sync_invoices(self, **kwargs):
    method _sync_charges (line 1357) | def _sync_charges(self, **kwargs):
    method _sync_cards (line 1362) | def _sync_cards(self, **kwargs):
    method _sync_subscriptions (line 1369) | def _sync_subscriptions(self, **kwargs):
  class Dispute (line 1379) | class Dispute(StripeModel):
    method __str__ (line 1439) | def __str__(self):
    method get_stripe_dashboard_url (line 1444) | def get_stripe_dashboard_url(self) -> str:
    method _attach_objects_post_save_hook (line 1451) | def _attach_objects_post_save_hook(
  class Event (line 1498) | class Event(StripeModel):
    method __str__ (line 1533) | def __str__(self):
    method _attach_objects_hook (line 1536) | def _attach_objects_hook(
    method process (line 1556) | def process(cls, data, api_key=djstripe_settings.STRIPE_SECRET_KEY):
    method invoke_webhook_handlers (line 1570) | def invoke_webhook_handlers(self):
    method parts (line 1586) | def parts(self):
    method category (line 1591) | def category(self):
    method verb (line 1596) | def verb(self):
    method customer (line 1601) | def customer(self):
  class File (line 1616) | class File(StripeModel):
    method is_valid_object (line 1645) | def is_valid_object(cls, data):
    method __str__ (line 1648) | def __str__(self):
  class FileLink (line 1658) | class FileLink(StripeModel):
    method __str__ (line 1675) | def __str__(self):
  class PaymentIntent (line 1679) | class PaymentIntent(StripeModel):
    method __str__ (line 1864) | def __str__(self):
    method update (line 1879) | def update(self, api_key=None, **kwargs):
    method _api_cancel (line 1891) | def _api_cancel(self, api_key=None, **kwargs):
    method _api_confirm (line 1903) | def _api_confirm(self, api_key=None, **kwargs):
  class SetupIntent (line 1920) | class SetupIntent(StripeModel):
    method __str__ (line 2013) | def __str__(self):
  class Payout (line 2034) | class Payout(StripeModel):
    method __str__ (line 2144) | def __str__(self):
  class Price (line 2148) | class Price(StripeModel):
    class Meta (line 2269) | class Meta(object):
    method get_or_create (line 2273) | def get_or_create(cls, **kwargs):
    method create (line 2282) | def create(cls, **kwargs):
    method __str__ (line 2298) | def __str__(self):
    method human_readable_price (line 2302) | def human_readable_price(self):
  class Refund (line 2352) | class Refund(StripeModel):
    method get_stripe_dashboard_url (line 2412) | def get_stripe_dashboard_url(self):
    method __str__ (line 2415) | def __str__(self):

FILE: djstripe/models/orders.py
  class Order (line 19) | class Order(StripeModel):
    method __str__ (line 114) | def __str__(self):
    method _manipulate_stripe_object_hook (line 127) | def _manipulate_stripe_object_hook(cls, data):
    method _attach_objects_post_save_hook (line 131) | def _attach_objects_post_save_hook(
    method cancel (line 146) | def cancel(self, api_key=None, stripe_account=None, **kwargs):
    method reopen (line 170) | def reopen(self, api_key=None, stripe_account=None, **kwargs):
    method submit (line 194) | def submit(self, api_key=None, stripe_account=None, **kwargs):

FILE: djstripe/models/payment_methods.py
  class DjstripePaymentMethod (line 23) | class DjstripePaymentMethod(models.Model):
    method from_stripe_object (line 37) | def from_stripe_object(cls, data):
    method _get_or_create_source (line 50) | def _get_or_create_source(
    method _model_for_type (line 68) | def _model_for_type(cls, type):
    method object_model (line 81) | def object_model(self):
    method resolve (line 84) | def resolve(self):
    method _get_or_create_from_stripe_object (line 88) | def _get_or_create_from_stripe_object(
  class LegacySourceMixin (line 139) | class LegacySourceMixin:
    method _get_customer_or_account_from_kwargs (line 150) | def _get_customer_or_account_from_kwargs(cls, **kwargs):
    method _api_create (line 181) | def _api_create(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kw...
    method api_list (line 217) | def api_list(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kwargs):
    method get_stripe_dashboard_url (line 268) | def get_stripe_dashboard_url(self) -> str:
    method remove (line 276) | def remove(self):
    method api_retrieve (line 297) | def api_retrieve(self, api_key=None, stripe_account=None):
    method _api_delete (line 330) | def _api_delete(self, api_key=None, stripe_account=None, **kwargs):
  class BankAccount (line 364) | class BankAccount(LegacySourceMixin, StripeModel):
    method __str__ (line 426) | def __str__(self):
    method human_readable_status (line 447) | def human_readable_status(self):
    method api_retrieve (line 452) | def api_retrieve(self, **kwargs):
  class Card (line 463) | class Card(LegacySourceMixin, StripeModel):
    method __str__ (line 581) | def __str__(self):
    method create_token (line 605) | def create_token(
  class Source (line 639) | class Source(StripeModel):
    method __str__ (line 729) | def __str__(self):
    method _manipulate_stripe_object_hook (line 733) | def _manipulate_stripe_object_hook(cls, data):
    method _attach_objects_hook (line 738) | def _attach_objects_hook(
    method detach (line 755) | def detach(self) -> bool:
    method api_list (line 780) | def api_list(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kwargs):
  class PaymentMethod (line 797) | class PaymentMethod(StripeModel):
    method __str__ (line 984) | def __str__(self):
    method get_stripe_dashboard_url (line 989) | def get_stripe_dashboard_url(self) -> str:
    method _attach_objects_hook (line 994) | def _attach_objects_hook(
    method attach (line 1012) | def attach(
    method detach (line 1040) | def detach(self):

FILE: djstripe/models/sigma.py
  class ScheduledQueryRun (line 10) | class ScheduledQueryRun(StripeModel):
    method __str__ (line 45) | def __str__(self):

FILE: djstripe/models/webhooks.py
  class WebhookEndpoint (line 24) | class WebhookEndpoint(StripeModel):
    method __str__ (line 63) | def __str__(self):
    method _attach_objects_hook (line 66) | def _attach_objects_hook(
  function _get_version (line 80) | def _get_version():
  function get_remote_ip (line 86) | def get_remote_ip(request):
  class WebhookEventTrigger (line 112) | class WebhookEventTrigger(models.Model):
    method __str__ (line 170) | def __str__(self):
    method from_request (line 174) | def from_request(cls, request, *, webhook_endpoint: WebhookEndpoint = ...
    method json_body (line 257) | def json_body(self):
    method is_test_event (line 264) | def is_test_event(self):
    method verify_signature (line 268) | def verify_signature(
    method validate (line 294) | def validate(
    method process (line 339) | def process(self, save=True, api_key: str = None):

FILE: djstripe/settings.py
  class DjstripeSettings (line 11) | class DjstripeSettings:
    method __init__ (line 39) | def __init__(self):
    method __setattr__ (line 46) | def __setattr__(self, name, value):
    method __delattr__ (line 49) | def __delattr__(self, name):
    method subscriber_request_callback (line 53) | def subscriber_request_callback(self):
    method get_idempotency_key (line 60) | def get_idempotency_key(self):
    method DJSTRIPE_WEBHOOK_URL (line 66) | def DJSTRIPE_WEBHOOK_URL(self):
    method WEBHOOK_TOLERANCE (line 70) | def WEBHOOK_TOLERANCE(self):
    method WEBHOOK_VALIDATION (line 76) | def WEBHOOK_VALIDATION(self):
    method WEBHOOK_SECRET (line 80) | def WEBHOOK_SECRET(self):
    method WEBHOOK_EVENT_CALLBACK (line 87) | def WEBHOOK_EVENT_CALLBACK(self):
    method SUBSCRIBER_CUSTOMER_KEY (line 91) | def SUBSCRIBER_CUSTOMER_KEY(self):
    method TEST_API_KEY (line 97) | def TEST_API_KEY(self):
    method LIVE_API_KEY (line 101) | def LIVE_API_KEY(self):
    method STRIPE_LIVE_MODE (line 106) | def STRIPE_LIVE_MODE(self):
    method STRIPE_SECRET_KEY (line 110) | def STRIPE_SECRET_KEY(self):
    method STRIPE_PUBLIC_KEY (line 121) | def STRIPE_PUBLIC_KEY(self):
    method STRIPE_API_VERSION (line 132) | def STRIPE_API_VERSION(self) -> str:
    method get_callback_function (line 139) | def get_callback_function(self, setting_name, default=None):
    method _get_idempotency_key (line 170) | def _get_idempotency_key(self, object_type, action, livemode) -> str:
    method get_default_api_key (line 179) | def get_default_api_key(self, livemode) -> str:
    method get_subscriber_model_string (line 193) | def get_subscriber_model_string(self) -> str:
    method get_subscriber_model (line 197) | def get_subscriber_model(self):

FILE: djstripe/sync.py
  function sync_subscriber (line 9) | def sync_subscriber(subscriber):

FILE: djstripe/utils.py
  function get_supported_currency_choices (line 15) | def get_supported_currency_choices(api_key):
  function clear_expired_idempotency_keys (line 31) | def clear_expired_idempotency_keys():
  function convert_tstamp (line 38) | def convert_tstamp(response) -> Optional[datetime.datetime]:
  function get_friendly_currency_amount (line 56) | def get_friendly_currency_amount(amount, currency: str) -> str:
  class QuerySetMock (line 63) | class QuerySetMock(QuerySet):
    method from_iterable (line 70) | def from_iterable(cls, model, iterable):
    method _clone (line 76) | def _clone(self):
    method update (line 79) | def update(self):
    method delete (line 82) | def delete(self):
  function get_id_from_stripe_data (line 86) | def get_id_from_stripe_data(data):
  function get_model (line 101) | def get_model(model_name):
  function get_queryset (line 108) | def get_queryset(pks, model_name):
  function get_timezone_utc (line 113) | def get_timezone_utc():

FILE: djstripe/views.py
  class ProcessWebhookView (line 18) | class ProcessWebhookView(View):
    method post (line 30) | def post(self, request, uuid=None):

FILE: djstripe/webhooks.py
  function handler (line 33) | def handler(*event_types):
  function handler_all (line 57) | def handler_all(func=None):
  function call_handlers (line 71) | def call_handlers(event):

FILE: manage.py
  function main (line 14) | def main():

FILE: tests/__init__.py
  class AssertStripeFksMixin (line 32) | class AssertStripeFksMixin:
    method _get_field_str (line 33) | def _get_field_str(self, field) -> str:
    method assert_fks (line 50) | def assert_fks(self, obj, expected_blank_fks, processed_stripe_ids=None):
  function load_fixture (line 88) | def load_fixture(filename):
  function datetime_to_unix (line 93) | def datetime_to_unix(datetime_):
  class StripeItem (line 97) | class StripeItem(dict):
    method __getattr__ (line 106) | def __getattr__(self, name):
    method __setattr__ (line 113) | def __setattr__(self, name, value):
    method __delattr__ (line 116) | def __delattr__(self, name):
    method delete (line 122) | def delete(self) -> bool:
    method class_url (line 129) | def class_url(cls):
    method instance_url (line 132) | def instance_url(self):
    method request (line 138) | def request(self, method, url, params) -> Dict:
  class StripeList (line 146) | class StripeList(dict):
    method __getattr__ (line 166) | def __getattr__(self, name):
    method __setattr__ (line 173) | def __setattr__(self, name, value):
    method __delattr__ (line 176) | def __delattr__(self, name):
    method __iter__ (line 182) | def __iter__(self) -> Any:
    method __next__ (line 187) | def __next__(self) -> StripeItem:
    method list (line 194) | def list(self, **kwargs: Any) -> "StripeList":
    method auto_paging_iter (line 202) | def auto_paging_iter(self) -> "StripeList":
    method total_count (line 210) | def total_count(self):
  class ExternalAccounts (line 214) | class ExternalAccounts(object):
    method __init__ (line 215) | def __init__(self, external_account_fakes):
    method create (line 218) | def create(self, source, api_key=None):
    method retrieve (line 223) | def retrieve(self, id, expand=None):
    method list (line 228) | def list(self, **kwargs):
  class AccountDict (line 232) | class AccountDict(dict):
    method save (line 233) | def save(self, idempotency_key=None):
    method external_accounts (line 237) | def external_accounts(self):
    method create (line 242) | def create(self):
  class LegacySourceDict (line 363) | class LegacySourceDict(dict):
    method delete (line 364) | def delete(self):
  class BankAccountDict (line 368) | class BankAccountDict(LegacySourceDict):
  class CardDict (line 409) | class CardDict(LegacySourceDict):
  class SourceDict (line 423) | class SourceDict(dict):
    method detach (line 424) | def detach(self):
  class PaymentMethodDict (line 496) | class PaymentMethodDict(dict):
    method detach (line 497) | def detach(self):
  class ChargeDict (line 672) | class ChargeDict(StripeItem):
    method __init__ (line 673) | def __init__(self, *args, **kwargs):
    method refund (line 678) | def refund(self, amount=None, reason=None):
    method capture (line 682) | def capture(self):
  class SubscriptionDict (line 1074) | class SubscriptionDict(StripeItem):
    method __init__ (line 1075) | def __init__(self, *args, **kwargs):
    method __setattr__ (line 1080) | def __setattr__(self, name, value):
    method delete (line 1101) | def delete(self, **kwargs):
    method save (line 1107) | def save(self, idempotency_key=None):
  class Sources (line 1299) | class Sources(object):
    method __init__ (line 1300) | def __init__(self, card_fakes):
    method create (line 1303) | def create(self, source, api_key=None):
    method retrieve (line 1308) | def retrieve(self, id, expand=None):
    method list (line 1313) | def list(self, **kwargs):
  function convert_source_dict (line 1317) | def convert_source_dict(data):
  class CustomerDict (line 1332) | class CustomerDict(dict):
    method __init__ (line 1333) | def __init__(self, *args, **kwargs):
    method save (line 1341) | def save(self, idempotency_key=None):
    method delete (line 1344) | def delete(self):
    method sources (line 1348) | def sources(self):
    method create_for_user (line 1351) | def create_for_user(self, user):
  class InvoiceDict (line 1413) | class InvoiceDict(StripeItem):
    method __init__ (line 1414) | def __init__(self, *args, **kwargs):
    method pay (line 1419) | def pay(self):
  class UsageRecordSummaryDict (line 1863) | class UsageRecordSummaryDict(StripeItem):
  class WebhookEndpointDict (line 1872) | class WebhookEndpointDict(StripeItem):
  class PayoutDict (line 1881) | class PayoutDict(StripeItem):

FILE: tests/apps/example/forms.py
  class PurchaseSubscriptionForm (line 6) | class PurchaseSubscriptionForm(forms.Form):
  class PaymentIntentForm (line 14) | class PaymentIntentForm(forms.Form):

FILE: tests/apps/example/management/commands/regenerate_test_fixtures.py
  class Command (line 20) | class Command(BaseCommand):
    method add_arguments (line 44) | def add_arguments(self, parser):
    method handle (line 56) | def handle(self, *args, **options):
    method init_fake_id_map (line 285) | def init_fake_id_map(self):
    method update_fake_id_map (line 325) | def update_fake_id_map(self, obj):
    method get_fake_id (line 342) | def get_fake_id(self, obj):
    method fake_json_ids (line 369) | def fake_json_ids(self, json_str):
    method unfake_json_ids (line 382) | def unfake_json_ids(self, json_str):
    method update_fixture_obj (line 401) | def update_fixture_obj(
    method get_or_create_stripe_account (line 500) | def get_or_create_stripe_account(self, old_obj, readonly_fields):
    method get_or_create_stripe_bank_account (line 505) | def get_or_create_stripe_bank_account(self, old_obj, readonly_fields):
    method get_or_create_stripe_card (line 536) | def get_or_create_stripe_card(self, old_obj, readonly_fields):
    method get_or_create_stripe_source (line 563) | def get_or_create_stripe_source(self, old_obj, readonly_fields):
    method get_or_create_stripe_invoice (line 594) | def get_or_create_stripe_invoice(self, old_obj, writable_fields):
    method get_or_create_stripe_charge (line 619) | def get_or_create_stripe_charge(self, old_obj, writable_fields):
    method get_or_create_stripe_payment_intent (line 642) | def get_or_create_stripe_payment_intent(self, old_obj, writable_fields):
    method get_or_create_stripe_payment_method (line 665) | def get_or_create_stripe_payment_method(self, old_obj, writable_fields):
    method get_or_create_stripe_balance_transaction (line 701) | def get_or_create_stripe_balance_transaction(self, old_obj):
    method save_fixture (line 718) | def save_fixture(self, obj):
    method pre_process_subscription (line 731) | def pre_process_subscription(self, create_obj):
    method preserve_old_sideeffect_values (line 783) | def preserve_old_sideeffect_values(

FILE: tests/apps/example/views.py
  class CreateCheckoutSessionView (line 25) | class CreateCheckoutSessionView(LoginRequiredMixin, TemplateView):
    method get_context_data (line 39) | def get_context_data(self, **kwargs):
  class CheckoutSessionSuccessView (line 142) | class CheckoutSessionSuccessView(TemplateView):
  class PurchaseSubscriptionView (line 150) | class PurchaseSubscriptionView(FormView):
    method get_context_data (line 165) | def get_context_data(self, **kwargs):
    method form_valid (line 182) | def form_valid(self, form):
    method get_success_url (line 218) | def get_success_url(self):
  class PurchaseSubscriptionSuccessView (line 225) | class PurchaseSubscriptionSuccessView(DetailView):
  function create_payment_intent (line 234) | def create_payment_intent(request):

FILE: tests/apps/testapp/models.py
  class Organization (line 5) | class Organization(Model):
  class StaticEmailOrganization (line 11) | class StaticEmailOrganization(Model):
    method email (line 17) | def email(self):
  class NoEmailOrganization (line 21) | class NoEmailOrganization(Model):

FILE: tests/apps/testapp/urls.py
  function empty_view (line 5) | def empty_view(request):

FILE: tests/apps/testapp_content/urls.py
  function testview (line 9) | def testview(request):

FILE: tests/apps/testapp_namespaced/urls.py
  function testview (line 5) | def testview(request):

FILE: tests/conftest.py
  function create_account (line 14) | def create_account(monkeypatch):
  function fake_user (line 29) | def fake_user():
  function fake_customer (line 37) | def fake_customer(fake_user):

FILE: tests/fields/admin.py
  class CustomActionModelAdmin (line 11) | class CustomActionModelAdmin(StripeModelAdmin):
    method get_actions (line 12) | def get_actions(self, request):
    method _cancel (line 30) | def _cancel(self, request, queryset):
    method _release_subscription_schedule (line 36) | def _release_subscription_schedule(self, request, queryset):
    method _cancel_subscription_schedule (line 43) | def _cancel_subscription_schedule(self, request, queryset):

FILE: tests/fields/models.py
  class ExampleDecimalModel (line 9) | class ExampleDecimalModel(models.Model):
  class MockStripeClass (line 13) | class MockStripeClass:
    method retrieve (line 14) | def retrieve(self):
  class CustomActionModel (line 18) | class CustomActionModel(StripeModel):
    method cancel (line 25) | def cancel(self, at_period_end: bool = False, **kwargs):

FILE: tests/test_account.py
  class TestAccount (line 27) | class TestAccount(AssertStripeFksMixin, TestCase):
    method test_get_default_account (line 34) | def test_get_default_account(self, file_retrieve_mock, account_retriev...
    method test_sync_from_stripe_data (line 71) | def test_sync_from_stripe_data(
    method test__find_owner_account (line 102) | def test__find_owner_account(self, fileupload_retrieve_mock, account_r...
    method test_business_url (line 117) | def test_business_url(self, fileupload_retrieve_mock, account_retrieve...
    method test_branding_logo (line 132) | def test_branding_logo(self, fileupload_retrieve_mock, account_retriev...
    method test_branding_icon (line 149) | def test_branding_icon(self, fileupload_retrieve_mock, account_retriev...
    method test__attach_objects_post_save_hook (line 162) | def test__attach_objects_post_save_hook(
    method test_get_default_account_null_logo (line 186) | def test_get_default_account_null_logo(
    method test_get_stripe_dashboard_url (line 219) | def test_get_stripe_dashboard_url(
  class TestAccountMethods (line 232) | class TestAccountMethods:
    method test_account_str (line 256) | def test_account_str(
    method test__str__null_settings_null_business_profile (line 278) | def test__str__null_settings_null_business_profile(
    method test_livemode_populates_correctly_for_livemode (line 311) | def test_livemode_populates_correctly_for_livemode(
    method test_livemode_populates_correctly_for_testmode (line 360) | def test_livemode_populates_correctly_for_testmode(
  class TestAccountRestrictedKeys (line 387) | class TestAccountRestrictedKeys(TestCase):
    method test_account_str_restricted_key (line 394) | def test_account_str_restricted_key(self, account_retrieve_mock):
  function test_account__create_from_stripe_object (line 421) | def test_account__create_from_stripe_object(
  function test_api_reject (line 465) | def test_api_reject(

FILE: tests/test_admin.py
  function test_get_forward_relation_fields_for_model (line 75) | def test_get_forward_relation_fields_for_model(output, input):
  class TestAdminRegisteredModelsChildrenOfStripeModel (line 79) | class TestAdminRegisteredModelsChildrenOfStripeModel(TestCase):
    method setUp (line 80) | def setUp(self):
    method test_get_list_display_links (line 94) | def test_get_list_display_links(self):
    method test_get_list_display (line 129) | def test_get_list_display(self):
    method test_get_list_filter (line 180) | def test_get_list_filter(self):
    method test_get_readonly_fields (line 218) | def test_get_readonly_fields(self):
    method test_get_list_select_related (line 266) | def test_get_list_select_related(self):
    method test_get_fieldsets_add (line 307) | def test_get_fieldsets_add(self):
    method test_get_fields_add (line 359) | def test_get_fields_add(self):
    method test_get_search_fields (line 403) | def test_get_search_fields(self):
    method test_get_actions (line 450) | def test_get_actions(self):
  class TestAdminRegisteredModelsNotChildrenOfStripeModel (line 500) | class TestAdminRegisteredModelsNotChildrenOfStripeModel(TestCase):
    method setUp (line 501) | def setUp(self):
    method test_get_list_display_links (line 507) | def test_get_list_display_links(self):
    method test_get_list_display (line 542) | def test_get_list_display(self):
    method test_get_list_filter (line 591) | def test_get_list_filter(self):
    method test_get_readonly_fields (line 627) | def test_get_readonly_fields(self):
    method test_get_list_select_related (line 673) | def test_get_list_select_related(self):
    method test_get_fieldsets_add (line 714) | def test_get_fieldsets_add(self):
    method test_get_fields_add (line 764) | def test_get_fields_add(self):
    method test_get_search_fields (line 808) | def test_get_search_fields(self):
  class TestAdminInlineModels (line 852) | class TestAdminInlineModels(TestCase):
    method test_readonly_fields_exist (line 853) | def test_readonly_fields_exist(self):
  class TestAdminSite (line 869) | class TestAdminSite(TestCase):
    method setUp (line 870) | def setUp(self):
    method test_search_fields (line 873) | def test_search_fields(self):
    method test_search_fields_exist (line 888) | def test_search_fields_exist(self):
    method test_list_select_related_fields_exist (line 902) | def test_list_select_related_fields_exist(self):
  class TestCustomActionMixin (line 917) | class TestCustomActionMixin:
    method test_get_admin_action_context (line 931) | def test_get_admin_action_context(
    method test_get_actions (line 990) | def test_get_actions(self, admin_user):
    method test_changelist_view (line 1020) | def test_changelist_view(self, admin_client, fake_selected_pks):
    method test__resync_instances (line 1047) | def test__resync_instances(
    method test__sync_all_instances (line 1093) | def test__sync_all_instances(self, admin_client, fake_selected_pks):
  class TestSubscriptionAdminCustomAction (line 1123) | class TestSubscriptionAdminCustomAction:
    method test__cancel_subscription_instances (line 1124) | def test__cancel_subscription_instances(  # noqa: C901
  class TestSubscriptionScheduleAdminCustomAction (line 1200) | class TestSubscriptionScheduleAdminCustomAction:
    method test__release_subscription_schedule (line 1201) | def test__release_subscription_schedule(  # noqa: C901
    method test__cancel_subscription_schedule (line 1282) | def test__cancel_subscription_schedule(  # noqa: C901

FILE: tests/test_api_keys.py
  class TestCheckApiKeySettings (line 15) | class TestCheckApiKeySettings(TestCase):
    method test_global_api_keys_live_mode (line 27) | def test_global_api_keys_live_mode(
    method test_global_api_keys_test_mode (line 61) | def test_global_api_keys_test_mode(
    method test_api_key_live_mode (line 97) | def test_api_key_live_mode(
    method test_secret_key_test_mode (line 135) | def test_secret_key_test_mode(

FILE: tests/test_apikey.py
  function test_get_api_key_details_by_prefix (line 29) | def test_get_api_key_details_by_prefix():
  function test_get_api_key_details_by_prefix_bad_values (line 38) | def test_get_api_key_details_by_prefix_bad_values():
  function test_clean_public_apikey (line 47) | def test_clean_public_apikey():
  function test_apikey_detect_livemode_and_type (line 56) | def test_apikey_detect_livemode_and_type(
  class APIKeyTest (line 80) | class APIKeyTest(TestCase):
    method setUp (line 81) | def setUp(self):
    method test_get_stripe_dashboard_url (line 100) | def test_get_stripe_dashboard_url(self):
    method test___str__ (line 110) | def test___str__(self):
    method test_secret_redacted (line 120) | def test_secret_redacted(self):
    method test_secret_not_in_str (line 124) | def test_secret_not_in_str(self):
    method test_get_account_by_api_key (line 128) | def test_get_account_by_api_key(self):
    method test_refresh_account (line 142) | def test_refresh_account(self, fileupload_retrieve_mock, account_retri...

FILE: tests/test_balance_transaction.py
  class TestBalanceTransactionStr (line 30) | class TestBalanceTransactionStr:
    method test___str__ (line 32) | def test___str__(self, transaction_status):
  class TestBalanceTransactionSourceClass (line 45) | class TestBalanceTransactionSourceClass:
    method test_get_source_class_success (line 47) | def test_get_source_class_success(self, transaction_type):
    method test_get_source_class_failure (line 59) | def test_get_source_class_failure(self, transaction_type):
  class TestBalanceTransaction (line 70) | class TestBalanceTransaction(TestCase):
    method test_sync_from_stripe_data (line 110) | def test_sync_from_stripe_data(
    method test_get_source_instance (line 181) | def test_get_source_instance(
    method test_get_stripe_dashboard_url (line 250) | def test_get_stripe_dashboard_url(

FILE: tests/test_bank_account.py
  class TestStrBankAccount (line 28) | class TestStrBankAccount:
    method test__str__ (line 37) | def test__str__(self, fake_stripe_data, has_account, has_customer, mon...
    method test_human_readable_status (line 98) | def test_human_readable_status(self, fake_stripe_data, monkeypatch):
  class BankAccountTest (line 124) | class BankAccountTest(AssertStripeFksMixin, TestCase):
    method setUp (line 125) | def setUp(self):
    method test_attach_objects_hook_without_customer (line 141) | def test_attach_objects_hook_without_customer(self):
    method test_attach_objects_hook_without_account (line 148) | def test_attach_objects_hook_without_account(self):
    method test_api_retrieve_by_customer_equals_retrieval_by_account (line 162) | def test_api_retrieve_by_customer_equals_retrieval_by_account(
    method test_create_bank_account_finds_customer_with_account_absent (line 181) | def test_create_bank_account_finds_customer_with_account_absent(self):
    method test_create_bank_account_finds_customer_with_account_present (line 200) | def test_create_bank_account_finds_customer_with_account_present(self):
    method test_create_bank_account_finds_account_with_customer_absent (line 222) | def test_create_bank_account_finds_account_with_customer_absent(self):
    method test_api_call_no_customer_and_no_account (line 245) | def test_api_call_no_customer_and_no_account(self):
    method test_api_call_bad_customer (line 261) | def test_api_call_bad_customer(self):
    method test_api_call_bad_account (line 277) | def test_api_call_bad_account(self):
    method test__api_create_with_account_absent (line 298) | def test__api_create_with_account_absent(self, customer_retrieve_mock):
    method test__api_create_with_customer_and_account (line 315) | def test__api_create_with_customer_and_account(
    method test__api_create_with_customer_absent (line 339) | def test__api_create_with_customer_absent(
    method test_remove_bankaccount_by_customer (line 367) | def test_remove_bankaccount_by_customer(
    method test_remove_bankaccount_by_account (line 409) | def test_remove_bankaccount_by_account(
    method test_remove_already_deleted_bankaccount_by_account (line 451) | def test_remove_already_deleted_bankaccount_by_account(
    method test_remove_already_deleted_bank_account (line 500) | def test_remove_already_deleted_bank_account(
    method test_api_list (line 523) | def test_api_list(self, customer_retrieve_mock):

FILE: tests/test_card.py
  class TestStrCard (line 30) | class TestStrCard:
    method test__str__ (line 38) | def test__str__(self, fake_stripe_data, has_account, has_customer, mon...
  class CardTest (line 83) | class CardTest(AssertStripeFksMixin, TestCase):
    method setUp (line 84) | def setUp(self):
    method test_attach_objects_hook_without_customer (line 100) | def test_attach_objects_hook_without_customer(self):
    method test_attach_objects_hook_without_account (line 107) | def test_attach_objects_hook_without_account(self):
    method test_api_retrieve_by_customer_equals_retrieval_by_account (line 124) | def test_api_retrieve_by_customer_equals_retrieval_by_account(
    method test_create_card_finds_customer_with_account_absent (line 146) | def test_create_card_finds_customer_with_account_absent(self):
    method test_create_card_finds_customer_with_account_present (line 165) | def test_create_card_finds_customer_with_account_present(self):
    method test_create_card_finds_account_with_customer_absent (line 190) | def test_create_card_finds_account_with_customer_absent(self):
    method test_card_create_token (line 217) | def test_card_create_token(self, token_create_mock):
    method test_api_call_no_customer_and_no_account (line 223) | def test_api_call_no_customer_and_no_account(self):
    method test_api_call_bad_customer (line 239) | def test_api_call_bad_customer(self):
    method test_api_call_bad_account (line 255) | def test_api_call_bad_account(self):
    method test__api_create_with_account_absent (line 274) | def test__api_create_with_account_absent(self, customer_retrieve_mock):
    method test__api_create_with_customer_absent (line 284) | def test__api_create_with_customer_absent(self, account_retrieve_mock):
    method test__api_create_with_customer_and_account (line 299) | def test__api_create_with_customer_and_account(
    method test_remove_card_by_customer (line 326) | def test_remove_card_by_customer(
    method test_remove_card_by_account (line 359) | def test_remove_card_by_account(self, account_retrieve_mock, card_dele...
    method test_remove_already_deleted_card_by_account (line 390) | def test_remove_already_deleted_card_by_account(
    method test_remove_already_deleted_card (line 429) | def test_remove_already_deleted_card(
    method test_remove_no_such_source (line 449) | def test_remove_no_such_source(self, customer_retrieve_mock, card_dele...
    method test_remove_no_such_customer (line 467) | def test_remove_no_such_customer(self, customer_retrieve_mock, card_de...
    method test_remove_unexpected_exception (line 485) | def test_remove_unexpected_exception(
    method test_api_list (line 505) | def test_api_list(self, customer_retrieve_mock):

FILE: tests/test_charge.py
  class ChargeTest (line 39) | class ChargeTest(AssertStripeFksMixin, TestCase):
    method setUp (line 41) | def setUp(self):
    method test___str__ (line 71) | def test___str__(self):
    method test_capture_charge (line 117) | def test_capture_charge(
    method test_sync_from_stripe_data (line 206) | def test_sync_from_stripe_data(
    method test_sync_from_stripe_data_refunded_on_update (line 300) | def test_sync_from_stripe_data_refunded_on_update(
    method test_sync_from_stripe_data_refunded (line 436) | def test_sync_from_stripe_data_refunded(
    method test_sync_from_stripe_data_max_amount (line 555) | def test_sync_from_stripe_data_max_amount(
    method test_sync_from_stripe_data_unsupported_source (line 641) | def test_sync_from_stripe_data_unsupported_source(
    method test_sync_from_stripe_data_no_customer (line 700) | def test_sync_from_stripe_data_no_customer(
    method test_sync_from_stripe_data_with_transfer (line 798) | def test_sync_from_stripe_data_with_transfer(
    method test_sync_from_stripe_data_with_destination (line 901) | def test_sync_from_stripe_data_with_destination(
    method test__attach_objects_hook_missing_source_data (line 942) | def test__attach_objects_hook_missing_source_data(
    method test_max_size_large_charge_on_decimal_amount (line 1017) | def test_max_size_large_charge_on_decimal_amount(

FILE: tests/test_coupon.py
  class TransferTest (line 14) | class TransferTest(TestCase):
    method test_retrieve_coupon (line 15) | def test_retrieve_coupon(self):
  class CouponTest (line 21) | class CouponTest(TestCase):
    method test_blank_coupon_str (line 22) | def test_blank_coupon_str(self):
    method test___str__ (line 26) | def test___str__(self):
    method test_human_readable_usd_off_forever (line 36) | def test_human_readable_usd_off_forever(self):
    method test_human_readable_eur_off_forever (line 46) | def test_human_readable_eur_off_forever(self):
    method test_human_readable_percent_off_forever (line 56) | def test_human_readable_percent_off_forever(self):
    method test_human_readable_percent_off_once (line 66) | def test_human_readable_percent_off_once(self):
    method test_human_readable_percent_off_one_month (line 76) | def test_human_readable_percent_off_one_month(self):
    method test_human_readable_percent_off_three_months (line 87) | def test_human_readable_percent_off_three_months(self):
    method test_human_readable_integer_percent_off_forever (line 98) | def test_human_readable_integer_percent_off_forever(self):
  class TestCouponDecimal (line 109) | class TestCouponDecimal:
    method test_decimal_percent_off_coupon (line 127) | def test_decimal_percent_off_coupon(self, inputted, expected):

FILE: tests/test_customer.py
  class TestCustomer (line 64) | class TestCustomer(AssertStripeFksMixin, TestCase):
    method setUp (line 65) | def setUp(self):
    method test___str__ (line 82) | def test___str__(self):
    method test_balance (line 87) | def test_balance(self):
    method test_customer_dashboard_url (line 101) | def test_customer_dashboard_url(self):
    method test_customer_sync_unsupported_source (line 112) | def test_customer_sync_unsupported_source(self):
    method test_customer_sync_has_subscriber_metadata (line 128) | def test_customer_sync_has_subscriber_metadata(self):
    method test_customer_sync_has_subscriber_metadata_disabled (line 140) | def test_customer_sync_has_subscriber_metadata_disabled(self):
    method test_customer_sync_has_bad_subscriber_metadata (line 163) | def test_customer_sync_has_bad_subscriber_metadata(self):
    method test_customer_create_metadata_disabled (line 183) | def test_customer_create_metadata_disabled(self, customer_mock):
    method test_customer_sync_non_local_card (line 220) | def test_customer_sync_non_local_card(
    method test_customer_sync_bank_account_source (line 263) | def test_customer_sync_bank_account_source(self, bank_account_retrieve...
    method test_customer_sync_no_sources (line 287) | def test_customer_sync_no_sources(self, customer_mock):
    method test_customer_sync_default_source_string (line 316) | def test_customer_sync_default_source_string(self):
    method test_customer_sync_default_payment_method_string (line 342) | def test_customer_sync_default_payment_method_string(
    method test_customer_sync_null_default_payment_method (line 372) | def test_customer_sync_null_default_payment_method(
    method test_customer_purge_leaves_customer_record (line 439) | def test_customer_purge_leaves_customer_record(
    method test_customer_purge_detaches_sources (line 457) | def test_customer_purge_detaches_sources(
    method test_customer_purge_deletes_idempotency_key (line 485) | def test_customer_purge_deletes_idempotency_key(self, customer_api_cre...
    method test_customer_purge_raises_customer_exception (line 518) | def test_customer_purge_raises_customer_exception(
    method test_customer_delete_raises_unexpected_exception (line 548) | def test_customer_delete_raises_unexpected_exception(
    method test_add_card_set_default_true (line 572) | def test_add_card_set_default_true(self, customer_retrieve_mock):
    method test_add_card_set_default_false (line 582) | def test_add_card_set_default_false(self, customer_retrieve_mock):
    method test_add_card_set_default_false_with_single_card_still_becomes_default (line 592) | def test_add_card_set_default_false_with_single_card_still_becomes_def...
    method test_add_payment_method_obj (line 614) | def test_add_payment_method_obj(self, attach_mock, customer_retrieve_m...
    method test_add_payment_method_set_default_true (line 650) | def test_add_payment_method_set_default_true(
    method test_add_payment_method_set_default_false (line 700) | def test_add_payment_method_set_default_false(
    method test_charge_accepts_only_decimals (line 739) | def test_charge_accepts_only_decimals(self):
    method test_add_coupon_by_id (line 747) | def test_add_coupon_by_id(self, customer_retrieve_mock, coupon_retriev...
    method test_add_coupon_by_object (line 762) | def test_add_coupon_by_object(self, customer_retrieve_mock, coupon_ret...
    method test_refund_charge (line 811) | def test_refund_charge(
    method test_refund_charge_object_returned (line 906) | def test_refund_charge_object_returned(
    method test_calculate_refund_amount_partial_refund (line 979) | def test_calculate_refund_amount_partial_refund(self):
    method test_calculate_refund_above_max_refund (line 987) | def test_calculate_refund_above_max_refund(self):
    method test_charge_converts_dollars_into_cents (line 1012) | def test_charge_converts_dollars_into_cents(
    method test_charge_doesnt_require_invoice (line 1084) | def test_charge_doesnt_require_invoice(
    method test_charge_passes_extra_arguments (line 1133) | def test_charge_passes_extra_arguments(
    method test_charge_string_source (line 1182) | def test_charge_string_source(
    method test_charge_card_source (line 1223) | def test_charge_card_source(
    method test_retry_unpaid_invoices (line 1301) | def test_retry_unpaid_invoices(
    method test_retry_unpaid_invoices_none_unpaid (line 1374) | def test_retry_unpaid_invoices_none_unpaid(
    method test_retry_unpaid_invoices_expected_exception (line 1431) | def test_retry_unpaid_invoices_expected_exception(
    method test_retry_unpaid_invoices_unexpected_exception (line 1495) | def test_retry_unpaid_invoices_unexpected_exception(
    method test_send_invoice_success (line 1523) | def test_send_invoice_success(self, invoice_create_mock):
    method test_send_invoice_failure (line 1534) | def test_send_invoice_failure(self, invoice_create_mock):
    method test_sync_customer_with_discount (line 1549) | def test_sync_customer_with_discount(self, coupon_retrieve_mock):
    method test_sync_customer_discount_already_present (line 1559) | def test_sync_customer_discount_already_present(self, coupon_retrieve_...
    method test_sync_customer_delete_discount (line 1571) | def test_sync_customer_delete_discount(self):
    method test_sync_invoices (line 1593) | def test_sync_invoices(
    method test_sync_invoices_none (line 1607) | def test_sync_invoices_none(
    method test_sync_charges (line 1625) | def test_sync_charges(
    method test_sync_charges_none (line 1639) | def test_sync_charges_none(
    method test_sync_subscriptions (line 1658) | def test_sync_subscriptions(
    method test_sync_subscriptions_none (line 1672) | def test_sync_subscriptions_none(
    method test_subscribe_price_string_new_style (line 1685) | def test_subscribe_price_string_new_style(
    method test_subscribe_price_string_old_style (line 1722) | def test_subscribe_price_string_old_style(
    method test_subscription_shortcut_with_multiple_subscriptions_old_style (line 1758) | def test_subscription_shortcut_with_multiple_subscriptions_old_style(
    method test_subscription_shortcut_with_multiple_subscriptions_new_style_by_price (line 1803) | def test_subscription_shortcut_with_multiple_subscriptions_new_style_b...
    method test_subscription_shortcut_with_multiple_subscriptions_new_style_by_price_and_plan (line 1856) | def test_subscription_shortcut_with_multiple_subscriptions_new_style_b...
    method test_subscription_shortcut_with_invalid_subscriptions (line 1914) | def test_subscription_shortcut_with_invalid_subscriptions(
    method test_add_invoice_item (line 1970) | def test_add_invoice_item(self, invoiceitem_create_mock, invoiceitem_s...
    method test_add_invoice_item_djstripe_objects (line 2003) | def test_add_invoice_item_djstripe_objects(
    method test_add_invoice_item_bad_decimal (line 2028) | def test_add_invoice_item_bad_decimal(self):
    method test_upcoming_invoice_plan (line 2081) | def test_upcoming_invoice_plan(
    method test_is_subscribed_to_with_product_old_style (line 2154) | def test_is_subscribed_to_with_product_old_style(
    method test_is_subscribed_to_with_product_new_style (line 2184) | def test_is_subscribed_to_with_product_new_style(
    method test_is_subscribed_to_with_product_string_new_style (line 2211) | def test_is_subscribed_to_with_product_string_new_style(
    method test_is_subscribed_to_with_product_string_by_price (line 2238) | def test_is_subscribed_to_with_product_string_by_price(
  class TestCustomerLegacy (line 2260) | class TestCustomerLegacy(AssertStripeFksMixin, TestCase):
    method setUp (line 2261) | def setUp(self):
    method test_subscribe_plan_string_new_style (line 2288) | def test_subscribe_plan_string_new_style(
    method test_subscribe_plan_string_old_style (line 2327) | def test_subscribe_plan_string_old_style(
    method test_subscription_shortcut_with_multiple_subscriptions_new_style_by_plan (line 2364) | def test_subscription_shortcut_with_multiple_subscriptions_new_style_b...
    method test_subscription_shortcut_with_invalid_subscriptions (line 2415) | def test_subscription_shortcut_with_invalid_subscriptions(
    method test_upcoming_invoice (line 2508) | def test_upcoming_invoice(

FILE: tests/test_discount.py
  class TestDiscount (line 30) | class TestDiscount(AssertStripeFksMixin, TestCase):
    method test_sync_from_stripe_data (line 73) | def test_sync_from_stripe_data(

FILE: tests/test_dispute.py
  class TestDispute (line 28) | class TestDispute(TestCase):
    method setUp (line 29) | def setUp(self):
    method test___str__ (line 63) | def test___str__(
    method test_sync_from_stripe_data (line 103) | def test_sync_from_stripe_data(
    method test__attach_objects_post_save_hook (line 145) | def test__attach_objects_post_save_hook(
    method test_get_stripe_dashboard_url (line 203) | def test_get_stripe_dashboard_url(

FILE: tests/test_django.py
  class TestRunManagePyCheck (line 6) | class TestRunManagePyCheck(TestCase):
    method test_manage_py_check (line 14) | def test_manage_py_check(self):

FILE: tests/test_enums.py
  class TestEnumMetaClass (line 9) | class TestEnumMetaClass(TestCase):
    method test_python2_prepare (line 10) | def test_python2_prepare(self):
  class TestEnumHumanize (line 15) | class TestEnumHumanize(TestCase):
    method test_humanize (line 16) | def test_humanize(self):

FILE: tests/test_event.py
  class EventTest (line 23) | class EventTest(TestCase):
    method setUp (line 24) | def setUp(self):
    method test___str__ (line 34) | def test___str__(self):
    method test_invoke_webhook_handlers_event_with_log_stripe_error (line 42) | def test_invoke_webhook_handlers_event_with_log_stripe_error(self):
    method test_invoke_webhook_handlers_event_with_raise_stripe_error (line 48) | def test_invoke_webhook_handlers_event_with_raise_stripe_error(self):
    method test_invoke_webhook_handlers_event_when_invalid (line 54) | def test_invoke_webhook_handlers_event_when_invalid(self):
    method test_process_event (line 62) | def test_process_event(
    method test_process_event_exists (line 90) | def test_process_event_exists(
    method test_process_event_failure_rolls_back (line 117) | def test_process_event_failure_rolls_back(self, invoke_webhook_handler...
    method _create_event (line 154) | def _create_event(self, event_data, event_retrieve_mock):
  class EventRaceConditionTest (line 161) | class EventRaceConditionTest(TestCase):
    method test_process_event_race_condition (line 171) | def test_process_event_race_condition(

FILE: tests/test_event_handlers.py
  class EventTestCase (line 157) | class EventTestCase(TestCase):
    method _create_event (line 163) | def _create_event(self, event_data, event_retrieve_mock, patch_data=No...
  class TestAccountEvents (line 175) | class TestAccountEvents(EventTestCase):
    method setUp (line 176) | def setUp(self):
    method test_account_deauthorized_event (line 187) | def test_account_deauthorized_event(self, event_retrieve_mock):
    method test_account_authorized_event (line 194) | def test_account_authorized_event(self, event_retrieve_mock):
    method test_custom_account_external_account_created_bank_account_event (line 207) | def test_custom_account_external_account_created_bank_account_event(
    method test_custom_account_external_account_deleted_bank_account_event (line 236) | def test_custom_account_external_account_deleted_bank_account_event(
    method test_custom_account_external_account_updated_bank_account_event (line 265) | def test_custom_account_external_account_updated_bank_account_event(
    method test_custom_account_external_account_created_card_event (line 307) | def test_custom_account_external_account_created_card_event(
    method test_custom_account_external_account_deleted_card_event (line 334) | def test_custom_account_external_account_deleted_card_event(
    method test_custom_account_external_account_updated_card_event (line 363) | def test_custom_account_external_account_updated_card_event(
    method test_express_account_external_account_created_bank_account_event (line 402) | def test_express_account_external_account_created_bank_account_event(
    method test_express_account_external_account_deleted_bank_account_event (line 431) | def test_express_account_external_account_deleted_bank_account_event(
    method test_express_account_external_account_updated_bank_account_event (line 460) | def test_express_account_external_account_updated_bank_account_event(
    method test_express_account_external_account_created_card_event (line 502) | def test_express_account_external_account_created_card_event(
    method test_express_account_external_account_deleted_card_event (line 529) | def test_express_account_external_account_deleted_card_event(
    method test_express_account_external_account_updated_card_event (line 558) | def test_express_account_external_account_updated_card_event(
    method test_standard_account_updated_event (line 599) | def test_standard_account_updated_event(
    method test_express_account_updated_event (line 634) | def test_express_account_updated_event(
    method test_custom_account_updated_event (line 669) | def test_custom_account_updated_event(
  class TestChargeEvents (line 699) | class TestChargeEvents(EventTestCase):
    method setUp (line 700) | def setUp(self):
    method test_charge_created (line 754) | def test_charge_created(
  class TestCheckoutEvents (line 786) | class TestCheckoutEvents(EventTestCase):
    method setUp (line 787) | def setUp(self):
    method test_checkout_session_completed (line 837) | def test_checkout_session_completed(
    method test_checkout_session_async_payment_succeeded (line 905) | def test_checkout_session_async_payment_succeeded(
    method test_checkout_session_async_payment_failed (line 975) | def test_checkout_session_async_payment_failed(
    method test_checkout_session_completed_customer_subscriber_added (line 1045) | def test_checkout_session_completed_customer_subscriber_added(
  class TestCustomerEvents (line 1088) | class TestCustomerEvents(EventTestCase):
    method setUp (line 1089) | def setUp(self):
    method test_customer_created (line 1097) | def test_customer_created(self, event_retrieve_mock, customer_retrieve...
    method test_customer_metadata_created (line 1114) | def test_customer_metadata_created(
    method test_customer_metadata_updated (line 1142) | def test_customer_metadata_updated(
    method test_customer_deleted (line 1179) | def test_customer_deleted(
    method test_customer_discount_created (line 1201) | def test_customer_discount_created(self, event_retrieve_mock, coupon_r...
    method test_customer_discount_deleted (line 1216) | def test_customer_discount_deleted(self, event_retrieve_mock, coupon_r...
    method test_customer_card_created (line 1235) | def test_customer_card_created(
    method test_customer_unknown_source_created (line 1251) | def test_customer_unknown_source_created(
    method test_customer_default_source_deleted (line 1271) | def test_customer_default_source_deleted(self, customer_retrieve_mock):
    method test_customer_source_double_delete (line 1287) | def test_customer_source_double_delete(self, customer_retrieve_mock):
    method test_customer_subscription_created (line 1306) | def test_customer_subscription_created(
    method test_customer_subscription_deleted (line 1377) | def test_customer_subscription_deleted(
    method test_customer_bogus_event_type (line 1420) | def test_customer_bogus_event_type(
  class TestDisputeEvents (line 1436) | class TestDisputeEvents(EventTestCase):
    method setUp (line 1437) | def setUp(self):
    method test_dispute_created (line 1475) | def test_dispute_created(
    method test_dispute_funds_withdrawn (line 1526) | def test_dispute_funds_withdrawn(
    method test_dispute_updated (line 1576) | def test_dispute_updated(
    method test_dispute_closed (line 1626) | def test_dispute_closed(
    method test_dispute_funds_reinstated_full (line 1681) | def test_dispute_funds_reinstated_full(
    method test_dispute_funds_reinstated_partial (line 1736) | def test_dispute_funds_reinstated_partial(
  class TestFileEvents (line 1754) | class TestFileEvents(EventTestCase):
    method setUp (line 1755) | def setUp(self):
    method test_file_created (line 1771) | def test_file_created(self, event_retrieve_mock, file_retrieve_mock):
  class TestInvoiceEvents (line 1779) | class TestInvoiceEvents(EventTestCase):
    method setUp (line 1780) | def setUp(self):
    method test_invoice_created_no_existing_customer (line 1831) | def test_invoice_created_no_existing_customer(
    method test_invoice_created (line 1902) | def test_invoice_created(
    method test_invoice_deleted (line 1976) | def test_invoice_deleted(
    method test_invoice_upcoming (line 2002) | def test_invoice_upcoming(self):
  class TestInvoiceItemEvents (line 2009) | class TestInvoiceItemEvents(EventTestCase):
    method setUp (line 2010) | def setUp(self):
    method test_invoiceitem_created (line 2059) | def test_invoiceitem_created(
    method test_invoiceitem_deleted (line 2155) | def test_invoiceitem_deleted(
  class TestPlanEvents (line 2199) | class TestPlanEvents(EventTestCase):
    method test_plan_created (line 2205) | def test_plan_created(
    method test_plan_updated_request_object (line 2227) | def test_plan_updated_request_object(
    method test_plan_deleted (line 2249) | def test_plan_deleted(self, product_retrieve_mock, plan_retrieve_mock):
  class TestPriceEvents (line 2262) | class TestPriceEvents(EventTestCase):
    method test_price_created (line 2268) | def test_price_created(
    method test_price_updated (line 2290) | def test_price_updated(
    method test_price_deleted (line 2312) | def test_price_deleted(self, product_retrieve_mock, price_retrieve_mock):
  class TestPaymentMethodEvents (line 2325) | class TestPaymentMethodEvents(AssertStripeFksMixin, EventTestCase):
    method setUp (line 2326) | def setUp(self):
    method test_payment_method_attached (line 2334) | def test_payment_method_attached(
    method test_card_payment_method_attached (line 2358) | def test_card_payment_method_attached(
    method test_payment_method_detached (line 2384) | def test_payment_method_detached(
    method test_card_payment_method_detached (line 2417) | def test_card_payment_method_detached(
  class TestPaymentIntentEvents (line 2439) | class TestPaymentIntentEvents(EventTestCase):
    method test_payment_intent_succeeded_with_destination_charge (line 2465) | def test_payment_intent_succeeded_with_destination_charge(
  class TestSubscriptionScheduleEvents (line 2504) | class TestSubscriptionScheduleEvents(EventTestCase):
    method test_subscription_schedule_created (line 2514) | def test_subscription_schedule_created(
    method test_subscription_schedule_and_subscription_created (line 2583) | def test_subscription_schedule_and_subscription_created(
    method test_subscription_schedule_canceled (line 2619) | def test_subscription_schedule_canceled(
    method test_subscription_schedule_completed (line 2664) | def test_subscription_schedule_completed(
    method test_subscription_schedule_expiring (line 2705) | def test_subscription_schedule_expiring(
    method test_subscription_schedule_released (line 2745) | def test_subscription_schedule_released(
    method test_subscription_schedule_updated (line 2827) | def test_subscription_schedule_updated(
    method test_subscription_schedule_aborted (line 2922) | def test_subscription_schedule_aborted(
  class TestTaxIdEvents (line 2974) | class TestTaxIdEvents(EventTestCase):
    method test_tax_id_created (line 2990) | def test_tax_id_created(
    method test_tax_id_updated (line 3011) | def test_tax_id_updated(
    method test_tax_id_deleted (line 3043) | def test_tax_id_deleted(
  class TestTransferEvents (line 3060) | class TestTransferEvents(EventTestCase):
    method test_transfer_created (line 3069) | def test_transfer_created(
    method test_transfer_deleted (line 3096) | def test_transfer_deleted(
  class TestOrderEvents (line 3117) | class TestOrderEvents(EventTestCase):
    method test_order_created (line 3160) | def test_order_created(
    method test_order_updated (line 3230) | def test_order_updated(
    method test_order_submitted (line 3301) | def test_order_submitted(
    method test_order_processing (line 3372) | def test_order_processing(
    method test_order_cancelled (line 3443) | def test_order_cancelled(
    method test_order_complet (line 3514) | def test_order_complet(

FILE: tests/test_fields.py
  class TestStripeDecimalCurrencyAmountField (line 18) | class TestStripeDecimalCurrencyAmountField:
    method test_stripe_to_db_none_val (line 21) | def test_stripe_to_db_none_val(self):
    method test_stripe_to_db_decimal_val (line 32) | def test_stripe_to_db_decimal_val(self, expected, inputted):
  class TestStripeDateTimeField (line 37) | class TestStripeDateTimeField(TestCase):
    method test_stripe_to_db_none_val (line 40) | def test_stripe_to_db_none_val(self):
    method test_stripe_to_db_datetime_val (line 43) | def test_stripe_to_db_datetime_val(self):
  class TestStripePercentField (line 50) | class TestStripePercentField:
    method test_stripe_percent_field (line 68) | def test_stripe_percent_field(self, inputted, expected):

FILE: tests/test_file_link.py
  class TestFileLink (line 18) | class TestFileLink(TestCase):
    method test___str__ (line 29) | def test___str__(self, mock_file_link_retrieve, mock_file_upload_retri...
    method test_sync_from_stripe_data (line 46) | def test_sync_from_stripe_data(

FILE: tests/test_file_upload.py
  class TestFileLink (line 19) | class TestFileLink(TestCase):
    method test_file_upload_api_retrieve (line 25) | def test_file_upload_api_retrieve(self, mock_file_upload_retrieve):
    method test_sync_from_stripe_data (line 64) | def test_sync_from_stripe_data(self, mock_file_upload_retrieve):
  class TestFileUploadStr (line 74) | class TestFileUploadStr:
    method test___str__ (line 76) | def test___str__(self, file_purpose):

FILE: tests/test_forms.py
  class TestCustomActionForm (line 19) | class TestCustomActionForm:
    method test___init__ (line 23) | def test___init__(self, action_name, monkeypatch):
  class TestAPIKeyAdminCreateForm (line 57) | class TestAPIKeyAdminCreateForm:
    method test__post_clean (line 59) | def test__post_clean(self, secret, monkeypatch):

FILE: tests/test_idempotency_keys.py
  class IdempotencyKeyTest (line 11) | class IdempotencyKeyTest(TestCase):
    method test_generate_idempotency_key (line 12) | def test_generate_idempotency_key(self):
    method test_clear_expired_idempotency_keys (line 30) | def test_clear_expired_idempotency_keys(self):

FILE: tests/test_invoice.py
  class InvoiceTest (line 42) | class InvoiceTest(AssertStripeFksMixin, TestCase):
    method setUp (line 43) | def setUp(self):
    method test_sync_from_stripe_data (line 121) | def test_sync_from_stripe_data(
    method test_sync_from_stripe_data_update_total_tax_amounts (line 210) | def test_sync_from_stripe_data_update_total_tax_amounts(
    method test_sync_from_stripe_data_default_payment_method (line 335) | def test_sync_from_stripe_data_default_payment_method(
    method test_billing_reason_enum (line 404) | def test_billing_reason_enum(
    method test_invoice_status_enum (line 474) | def test_invoice_status_enum(
    method test_retry_true (line 543) | def test_retry_true(
    method test_retry_false (line 616) | def test_retry_false(
    method test_status_draft (line 680) | def test_status_draft(
    method test_status_open (line 740) | def test_status_open(
    method test_status_paid (line 800) | def test_status_paid(
    method test_status_uncollectible (line 858) | def test_status_uncollectible(
    method test_status_void (line 918) | def test_status_void(
    method test_sync_no_subscription (line 992) | def test_sync_no_subscription(
    method test_invoice_with_subscription_invoice_items (line 1065) | def test_invoice_with_subscription_invoice_items(
    method test_invoice_with_no_invoice_items (line 1118) | def test_invoice_with_no_invoice_items(
    method test_invoice_with_non_subscription_invoice_items (line 1177) | def test_invoice_with_non_subscription_invoice_items(
    method test_invoice_plan_from_invoice_items (line 1240) | def test_invoice_plan_from_invoice_items(
    method test_invoice_plan_from_subscription (line 1300) | def test_invoice_plan_from_subscription(
    method test_invoice_without_plan (line 1356) | def test_invoice_without_plan(
    method test_upcoming_invoice (line 1435) | def test_upcoming_invoice(
    method test_upcoming_invoice_with_subscription (line 1565) | def test_upcoming_invoice_with_subscription(
    method test_upcoming_invoice_with_subscription_plan (line 1665) | def test_upcoming_invoice_with_subscription_plan(
    method test_no_upcoming_invoices (line 1727) | def test_no_upcoming_invoices(self, invoice_upcoming_mock):
    method test_upcoming_invoice_error (line 1735) | def test_upcoming_invoice_error(self, invoice_upcoming_mock):
  class TestInvoiceDecimal (line 1740) | class TestInvoiceDecimal:
    method test_decimal_tax_percent (line 1758) | def test_decimal_tax_percent(self, inputted, expected, monkeypatch):  ...

FILE: tests/test_invoiceitem.py
  class InvoiceItemTest (line 41) | class InvoiceItemTest(AssertStripeFksMixin, TestCase):
    method setUp (line 42) | def setUp(self):
    method test___str__ (line 121) | def test___str__(
    method test_sync_with_subscription (line 201) | def test_sync_with_subscription(
    method test_sync_expanded_invoice_with_subscription (line 312) | def test_sync_expanded_invoice_with_subscription(
    method test_sync_proration (line 420) | def test_sync_proration(
    method test_sync_null_invoice (line 505) | def test_sync_null_invoice(
    method test_sync_with_taxes (line 588) | def test_sync_with_taxes(

FILE: tests/test_line_item.py
  class LineItemTest (line 30) | class LineItemTest(AssertStripeFksMixin, TestCase):
    method setUp (line 31) | def setUp(self):
    method test_sync_from_stripe_data (line 108) | def test_sync_from_stripe_data(
    method test_api_list (line 138) | def test_api_list(

FILE: tests/test_managers.py
  class SubscriptionManagerTest (line 24) | class SubscriptionManagerTest(TestCase):
    method setUp (line 25) | def setUp(self):
    method test_started_during_no_records (line 108) | def test_started_during_no_records(self):
    method test_started_during_has_records (line 111) | def test_started_during_has_records(self):
    method test_canceled_during (line 114) | def test_canceled_during(self):
    method test_canceled_all (line 117) | def test_canceled_all(self):
    method test_active_all (line 120) | def test_active_all(self):
    method test_started_plan_summary (line 123) | def test_started_plan_summary(self):
    method test_active_plan_summary (line 130) | def test_active_plan_summary(self):
    method test_canceled_plan_summary (line 137) | def test_canceled_plan_summary(self):
    method test_churn (line 144) | def test_churn(self):
  class TransferManagerTest (line 150) | class TransferManagerTest(TestCase):
    method test_transfer_summary (line 157) | def test_transfer_summary(
  class ChargeManagerTest (line 184) | class ChargeManagerTest(TestCase):
    method setUp (line 185) | def setUp(self):
    method test_is_during_april_2015 (line 273) | def test_is_during_april_2015(self):
    method test_get_paid_totals_for_april_2015 (line 297) | def test_get_paid_totals_for_april_2015(self):

FILE: tests/test_migrations.py
  class TestCustomerSubscriberFK (line 13) | class TestCustomerSubscriberFK(TestCase):
    method setUp (line 18) | def setUp(self):
    method test_customer_subscriber_fk_to_subscriber_model (line 21) | def test_customer_subscriber_fk_to_subscriber_model(self):
    method test_customer_subscriber_fk_fallback_to_auth_user_model (line 31) | def test_customer_subscriber_fk_fallback_to_auth_user_model(self):

FILE: tests/test_mixins.py
  class TestPaymentsContextMixin (line 18) | class TestPaymentsContextMixin(TestCase):
    method test_get_context_data (line 19) | def test_get_context_data(self):
  class TestSubscriptionMixin (line 43) | class TestSubscriptionMixin(TestCase):
    method setUp (line 44) | def setUp(self):
    method test_get_context_data (line 56) | def test_get_context_data(self, stripe_create_customer_mock):

FILE: tests/test_order.py
  class TestOrder (line 38) | class TestOrder(AssertStripeFksMixin, TestCase):
    method test_sync_from_stripe_data (line 79) | def test_sync_from_stripe_data(
    method test__manipulate_stripe_object_hook (line 172) | def test__manipulate_stripe_object_hook(self):
  class TestOrderStr (line 192) | class TestOrderStr:
    method test___str__ (line 203) | def test___str__(self, order_status, monkeypatch):
  class TestOrderMethods (line 285) | class TestOrderMethods:
    method test_cancel (line 337) | def test_cancel(
    method test_reopen (line 431) | def test_reopen(
    method test_submit (line 525) | def test_submit(

FILE: tests/test_payment_intent.py
  function _get_fake_payment_intent_destination_charge_no_customer (line 32) | def _get_fake_payment_intent_destination_charge_no_customer():
  function _get_fake_payment_intent_i_no_customer (line 40) | def _get_fake_payment_intent_i_no_customer():
  class TestStrPaymentIntent (line 46) | class TestStrPaymentIntent:
    method test___str__ (line 60) | def test___str__(self, fake_intent_data, has_account, has_customer, mo...
  class PaymentIntentTest (line 147) | class PaymentIntentTest(AssertStripeFksMixin, TestCase):
    method test_sync_from_stripe_data (line 188) | def test_sync_from_stripe_data(
    method test_status_enum (line 273) | def test_status_enum(
    method test_canceled_intent (line 343) | def test_canceled_intent(

FILE: tests/test_payment_method.py
  class TestPaymentMethod (line 26) | class TestPaymentMethod:
    method mock_customer_get (line 31) | def mock_customer_get(*args, **kwargs):
    method test___str__ (line 35) | def test___str__(self, monkeypatch, customer_exists):
    method test_get_stripe_dashboard_url (line 59) | def test_get_stripe_dashboard_url(self, monkeypatch, customer_exists):
    method test_sync_from_stripe_data (line 80) | def test_sync_from_stripe_data(self, monkeypatch, customer_exists):
  class PaymentMethodTest (line 94) | class PaymentMethodTest(AssertStripeFksMixin, TestCase):
    method setUp (line 95) | def setUp(self):
    method test_attach (line 111) | def test_attach(self, attach_mock):
    method test_attach_obj (line 129) | def test_attach_obj(self, attach_mock):
    method test_attach_synced (line 148) | def test_attach_synced(self, attach_mock):
    method test_detach (line 171) | def test_detach(self):
    method test_detach_card (line 231) | def test_detach_card(self):
    method test_sync_null_customer (line 308) | def test_sync_null_customer(self):

FILE: tests/test_payout.py
  class TestPayout (line 30) | class TestPayout(AssertStripeFksMixin, TestCase):
    method setUp (line 31) | def setUp(self):
    method test_sync_from_stripe_data (line 58) | def test_sync_from_stripe_data(self, balance_transaction_retrieve_mock):
    method test___str__ (line 84) | def test___str__(self, balance_transaction_retrieve_mock):

FILE: tests/test_plan.py
  class PlanCreateTest (line 27) | class PlanCreateTest(AssertStripeFksMixin, TestCase):
    method setUp (line 28) | def setUp(self):
    method test_create_from_product_id (line 40) | def test_create_from_product_id(self, plan_create_mock, product_retrie...
    method test_create_from_stripe_product (line 65) | def test_create_from_stripe_product(self, plan_create_mock, product_re...
    method test_create_from_djstripe_product (line 94) | def test_create_from_djstripe_product(
    method test_create_with_metadata (line 122) | def test_create_with_metadata(self, plan_create_mock, product_retrieve...
  class PlanTest (line 149) | class PlanTest(AssertStripeFksMixin, TestCase):
    method setUp (line 152) | def setUp(self):
    method test___str__ (line 161) | def test___str__(self):
    method test___str__null_product (line 167) | def test___str__null_product(self):
    method test_stripe_plan (line 177) | def test_stripe_plan(self, plan_retrieve_mock):
    method test_stripe_plan_null_product (line 198) | def test_stripe_plan_null_product(self):
    method test_stripe_tier_plan (line 212) | def test_stripe_tier_plan(self):
    method test_stripe_metered_plan (line 228) | def test_stripe_metered_plan(self):
  class TestHumanReadablePlan (line 244) | class TestHumanReadablePlan:
    method get_fake_price_NONE_flat_amount (line 248) | def get_fake_price_NONE_flat_amount():
    method get_fake_price_0_flat_amount (line 254) | def get_fake_price_0_flat_amount():
    method get_fake_price_0_amount (line 260) | def get_fake_price_0_amount():
    method test_human_readable (line 286) | def test_human_readable(self, fake_plan_data, expected_str, monkeypatch):

FILE: tests/test_price.py
  class PriceCreateTest (line 27) | class PriceCreateTest(AssertStripeFksMixin, TestCase):
    method setUp (line 28) | def setUp(self):
    method test_create_from_product_id (line 40) | def test_create_from_product_id(self, price_create_mock, product_retri...
    method test_create_from_stripe_product (line 67) | def test_create_from_stripe_product(self, price_create_mock, product_r...
    method test_create_from_djstripe_product (line 96) | def test_create_from_djstripe_product(
    method test_create_with_metadata (line 124) | def test_create_with_metadata(self, price_create_mock, product_retriev...
  class PriceTest (line 151) | class PriceTest(AssertStripeFksMixin, TestCase):
    method setUp (line 152) | def setUp(self):
    method test_stripe_price (line 162) | def test_stripe_price(self, price_retrieve_mock):
    method test_stripe_tier_price (line 184) | def test_stripe_tier_price(self, price_retrieve_mock):
    method test_stripe_metered_price (line 200) | def test_stripe_metered_price(self, price_retrieve_mock):
    method test_stripe_onetime_price (line 216) | def test_stripe_onetime_price(self, price_retrieve_mock):
  class TestStrPrice (line 233) | class TestStrPrice:
    method test___str__ (line 243) | def test___str__(self, fake_price_data, monkeypatch):
  class TestHumanReadablePrice (line 268) | class TestHumanReadablePrice:
    method get_fake_price_NONE_flat_amount (line 272) | def get_fake_price_NONE_flat_amount():
    method get_fake_price_0_flat_amount (line 278) | def get_fake_price_0_flat_amount():
    method get_fake_price_0_amount (line 284) | def get_fake_price_0_amount():
    method test_human_readable (line 311) | def test_human_readable(self, fake_price_data, expected_str, monkeypat...

FILE: tests/test_product.py
  class TestProduct (line 26) | class TestProduct:
    method mock_file_retrieve (line 30) | def mock_file_retrieve(*args, **kwargs):
    method mock_account_retrieve (line 33) | def mock_account_retrieve(*args, **kwargs):
    method mock_product_get (line 36) | def mock_product_get(self, *args, **kwargs):
    method test___str__ (line 40) | def test___str__(self, count, monkeypatch):
    method test_sync_from_stripe_data (line 68) | def test_sync_from_stripe_data(self, monkeypatch):

FILE: tests/test_refund.py
  class RefundTest (line 30) | class RefundTest(AssertStripeFksMixin, TestCase):
    method setUp (line 31) | def setUp(self):
    method test_sync_from_stripe_data (line 108) | def test_sync_from_stripe_data(
    method test___str__ (line 177) | def test___str__(
    method test_reason_enum (line 249) | def test_reason_enum(
    method test_status_enum (line 331) | def test_status_enum(

FILE: tests/test_session.py
  class SessionTest (line 31) | class SessionTest(AssertStripeFksMixin, TestCase):
    method test_sync_from_stripe_data (line 72) | def test_sync_from_stripe_data(
    method test___str__ (line 153) | def test___str__(
  class TestSession (line 171) | class TestSession:
    method test__attach_objects_post_save_hook (line 181) | def test__attach_objects_post_save_hook(

FILE: tests/test_settings.py
  class TestSubscriberModelRetrievalMethod (line 15) | class TestSubscriberModelRetrievalMethod(TestCase):
    method test_with_user (line 16) | def test_with_user(self):
    method test_with_org (line 24) | def test_with_org(self):
    method test_with_org_static (line 32) | def test_with_org_static(self):
    method test_bad_model_name (line 40) | def test_bad_model_name(self):
    method test_unknown_model (line 51) | def test_unknown_model(self):
    method test_no_email_model (line 63) | def test_no_email_model(self):
    method test_no_callback (line 71) | def test_no_callback(self):
    method test_bad_callback (line 83) | def test_bad_callback(self):
    method test_get_callback_function_with_valid_func_callable (line 91) | def test_get_callback_function_with_valid_func_callable(self):
    method test_get_callback_function_with_valid_string_callable (line 99) | def test_get_callback_function_with_valid_string_callable(self, import...
    method test_get_callback_function_import_error (line 107) | def test_get_callback_function_import_error(self):
    method test_get_callback_function_with_non_callable_string (line 113) | def test_get_callback_function_with_non_callable_string(self, import_s...
    method test_get_callback_function_ (line 119) | def test_get_callback_function_(self):
  class TestStripeApiVersion (line 125) | class TestStripeApiVersion(TestCase):
    method test_global_stripe_api_version (line 126) | def test_global_stripe_api_version(self):
  class TestGetStripeApiVersion (line 135) | class TestGetStripeApiVersion(TestCase):
    method test_with_default (line 136) | def test_with_default(self):
    method test_with_override (line 143) | def test_with_override(self):
  class TestObjectPatching (line 150) | class TestObjectPatching(TestCase):
    method test_object_patching (line 156) | def test_object_patching(self, mock):

FILE: tests/test_setup_intent.py
  class TestStrSetupIntent (line 26) | class TestStrSetupIntent:
    method get_fake_setup_intent_destination_charge_no_customer (line 30) | def get_fake_setup_intent_destination_charge_no_customer():
    method test___str__ (line 46) | def test___str__(self, fake_intent_data, has_account, has_customer, mo...
  class SetupIntentTest (line 90) | class SetupIntentTest(AssertStripeFksMixin, TestCase):
    method test_sync_from_stripe_data (line 94) | def test_sync_from_stripe_data(self, customer_retrieve_mock):
    method test_status_enum (line 113) | def test_status_enum(self, customer_retrieve_mock):
    method test_canceled_intent (line 134) | def test_canceled_intent(self, customer_retrieve_mock):

FILE: tests/test_shipping_rate.py
  class ShippingRateTest (line 21) | class ShippingRateTest(AssertStripeFksMixin, TestCase):
    method test_sync_from_stripe_data (line 22) | def test_sync_from_stripe_data(self):
    method test_sync_from_stripe_data_with_tax_code (line 42) | def test_sync_from_stripe_data_with_tax_code(self, tax_code_retrieve_m...
    method test___str__ (line 59) | def test___str__(self):

FILE: tests/test_source.py
  class SourceTest (line 22) | class SourceTest(AssertStripeFksMixin, TestCase):
    method setUp (line 23) | def setUp(self):
    method test_attach_objects_hook_without_customer (line 38) | def test_attach_objects_hook_without_customer(self):
    method test_sync_from_stripe_data (line 50) | def test_sync_from_stripe_data(self):
    method test___str__ (line 63) | def test___str__(self):
    method test_detach (line 81) | def test_detach(self, source_retrieve_mock):

FILE: tests/test_stripe_model.py
  class ExampleStripeModel (line 15) | class ExampleStripeModel(StripeModel):
  class TestStripeModelExceptions (line 20) | class TestStripeModelExceptions(TestCase):
    method test_no_object_value (line 21) | def test_no_object_value(self):
    method test_bad_object_value (line 32) | def test_bad_object_value(self):
  function test__api_delete (line 50) | def test__api_delete(
  function test_api_retrieve (line 82) | def test_api_retrieve(
  function test_api_retrieve_reverse_foreign_key_lookup (line 102) | def test_api_retrieve_reverse_foreign_key_lookup(mock_stripe_class):
  function test__find_owner_account_for_empty_data (line 156) | def test__find_owner_account_for_empty_data(
  function test__find_owner_account (line 189) | def test__find_owner_account(
  function test__find_owner_account_for_webhook_event_trigger (line 246) | def test__find_owner_account_for_webhook_event_trigger(

FILE: tests/test_subscription.py
  class SubscriptionStrTest (line 57) | class SubscriptionStrTest(TestCase):
    method setUp (line 58) | def setUp(self):
    method test___str__ (line 77) | def test___str__(
  class SubscriptionTest (line 95) | class SubscriptionTest(AssertStripeFksMixin, TestCase):
    method setUp (line 138) | def setUp(
    method test_sync_from_stripe_data (line 187) | def test_sync_from_stripe_data(
    method test_sync_from_stripe_data_default_source_string (line 224) | def test_sync_from_stripe_data_default_source_string(
    method test_sync_items_with_tax_rates (line 250) | def test_sync_items_with_tax_rates(
    method test_is_status_temporarily_current (line 283) | def test_is_status_temporarily_current(
    method test_is_status_temporarily_current_false (line 313) | def test_is_status_temporarily_current_false(
    method test_is_status_temporarily_current_false_and_canceled (line 339) | def test_is_status_temporarily_current_false_and_canceled(
    method test_extend (line 372) | def test_extend(
    method test_extend_negative_delta (line 420) | def test_extend_negative_delta(
    method test_extend_with_trial (line 456) | def test_extend_with_trial(
    method test_update (line 505) | def test_update(
    method test_update_deprecation_warnings_raised (line 547) | def test_update_deprecation_warnings_raised(
    method test_update_with_plan_model (line 577) | def test_update_with_plan_model(
    method test_cancel_now (line 619) | def test_cancel_now(
    method test_cancel_at_period_end (line 670) | def test_cancel_at_period_end(
    method test_cancel_during_trial_sets_at_period_end (line 729) | def test_cancel_during_trial_sets_at_period_end(
    method test_cancel_and_reactivate (line 776) | def test_cancel_and_reactivate(
    method test_cancel_already_canceled (line 829) | def test_cancel_already_canceled(
    method test_cancel_error_in_cancel (line 854) | def test_cancel_error_in_cancel(
    method test_sync_multi_plan (line 884) | def test_sync_multi_plan(
    method test_update_multi_plan (line 945) | def test_update_multi_plan(
    method test_remove_all_multi_plan (line 1045) | def test_remove_all_multi_plan(
    method test_sync_metered_plan (line 1116) | def test_sync_metered_plan(
    method test_api_list (line 1153) | def test_api_list(self, subscription_list_mock):
    method test_api_list_with_no_status (line 1167) | def test_api_list_with_no_status(self, subscription_list_mock):
  class TestSubscriptionDecimal (line 1181) | class TestSubscriptionDecimal:
    method test_decimal_application_fee_percent (line 1199) | def test_decimal_application_fee_percent(  # noqa: C901

FILE: tests/test_subscription_item.py
  class SubscriptionItemTest (line 42) | class SubscriptionItemTest(AssertStripeFksMixin, TestCase):
    method setUp (line 85) | def setUp(
    method test_sync_from_stripe_data_metered_subscription (line 134) | def test_sync_from_stripe_data_metered_subscription(
    method test_sync_items_with_tax_rates (line 183) | def test_sync_items_with_tax_rates(
    method test_sync_multi_plan_subscription (line 259) | def test_sync_multi_plan_subscription(

FILE: tests/test_subscription_schedule.py
  class SubscriptionScheduleTest (line 33) | class SubscriptionScheduleTest(AssertStripeFksMixin, TestCase):
    method setUp (line 76) | def setUp(
    method test_sync_from_stripe_data (line 126) | def test_sync_from_stripe_data(
    method test___str__ (line 149) | def test___str__(
    method test_release (line 169) | def test_release(
    method test_cancel (line 199) | def test_cancel(
    method test_update (line 229) | def test_update(

FILE: tests/test_sync.py
  function capture_stdout (line 19) | def capture_stdout():
  class TestSyncSubscriber (line 32) | class TestSyncSubscriber(TestCase):
    method setUp (line 33) | def setUp(self):
    method test_sync_success (line 47) | def test_sync_success(
    method test_sync_fail (line 74) | def test_sync_fail(self, stripe_customer_create_mock, api_retrieve_mock):

FILE: tests/test_tax_code.py
  class TaxCodeTest (line 15) | class TaxCodeTest(TestCase):
    method test_sync_from_stripe_data (line 16) | def test_sync_from_stripe_data(self):
    method test___str__ (line 21) | def test___str__(self):

FILE: tests/test_tax_id.py
  class TestTaxIdStr (line 19) | class TestTaxIdStr(TestCase):
    method test___str__ (line 30) | def test___str__(
  class TestTransfer (line 42) | class TestTransfer(AssertStripeFksMixin, TestCase):
    method test_sync_from_stripe_data (line 53) | def test_sync_from_stripe_data(
    method test__api_create (line 82) | def test__api_create(
    method test__api_create_no_id_kwarg (line 110) | def test__api_create_no_id_kwarg(
    method test__api_create_no_customer (line 128) | def test__api_create_no_customer(
    method test_api_retrieve (line 149) | def test_api_retrieve(
    method test_api_list (line 172) | def test_api_list(

FILE: tests/test_tax_rates.py
  class TaxRateTest (line 16) | class TaxRateTest(TestCase):
    method test_sync_from_stripe_data (line 17) | def test_sync_from_stripe_data(self):
    method test___str__ (line 25) | def test___str__(self):
  class TestTaxRateDecimal (line 34) | class TestTaxRateDecimal:
    method test_decimal_tax_percent (line 52) | def test_decimal_tax_percent(self, inputted, expected):

FILE: tests/test_transfer.py
  function FAKE_TRANSFER_COMPLETE_REVERSAL (line 22) | def FAKE_TRANSFER_COMPLETE_REVERSAL():
  function FAKE_TRANSFER_PARTIAL_REVERSAL (line 29) | def FAKE_TRANSFER_PARTIAL_REVERSAL():
  class TestTransferStr (line 36) | class TestTransferStr:
    method test___str__ (line 57) | def test___str__(
  class TestTransfer (line 78) | class TestTransfer(AssertStripeFksMixin, TestCase):
    method test_sync_from_stripe_data (line 93) | def test_sync_from_stripe_data(
    method test_fee (line 128) | def test_fee(
    method test_get_stripe_dashboard_url (line 153) | def test_get_stripe_dashboard_url(

FILE: tests/test_transfer_reversal.py
  class TestTransferReversalStr (line 24) | class TestTransferReversalStr(TestCase):
    method test___str__ (line 41) | def test___str__(
  class TestTransfer (line 54) | class TestTransfer(AssertStripeFksMixin, TestCase):
    method test_sync_from_stripe_data (line 71) | def test_sync_from_stripe_data(
    method test_api_retrieve (line 112) | def test_api_retrieve(
    method test__api_create (line 144) | def test__api_create(
    method test_api_list (line 161) | def test_api_list(self, transfer_reversal_list_mock):
    method test_is_valid_object (line 175) | def test_is_valid_object(self):

FILE: tests/test_usage_record.py
  class TestUsageRecord (line 26) | class TestUsageRecord(AssertStripeFksMixin, TestCase):
    method test_sync_from_stripe_data (line 48) | def test_sync_from_stripe_data(
    method test___str__ (line 102) | def test___str__(
    method test__api_create (line 154) | def test__api_create(

FILE: tests/test_usage_record_summary.py
  class TestUsageRecordSummary (line 29) | class TestUsageRecordSummary(AssertStripeFksMixin, TestCase):
    method test_sync_from_stripe_data_with_null_invoice (line 51) | def test_sync_from_stripe_data_with_null_invoice(
    method test_sync_from_stripe_data (line 118) | def test_sync_from_stripe_data(
    method test___str__ (line 210) | def test___str__(
    method test_api_list (line 265) | def test_api_list(

FILE: tests/test_utils.py
  class TestTimestampConversion (line 23) | class TestTimestampConversion(TestCase):
    method test_conversion (line 24) | def test_conversion(self):
    method test_conversion_no_tz (line 35) | def test_conversion_no_tz(self):
  class TestGetSupportedCurrencyChoices (line 40) | class TestGetSupportedCurrencyChoices(TestCase):
    method test_get_choices (line 50) | def test_get_choices(
  class TestUtils (line 67) | class TestUtils(TestCase):
    method test_get_friendly_currency_amount (line 68) | def test_get_friendly_currency_amount(self):

FILE: tests/test_views.py
  class TestConfirmCustomActionView (line 39) | class TestConfirmCustomActionView:
    method dummy_get_response (line 51) | def dummy_get_response(self, request):
    method test_get_form_kwargs (line 64) | def test_get_form_kwargs(self, action_name, admin_user, monkeypatch):
    method test_form_valid (line 108) | def test_form_valid(self, djstripe_owner_account_exists, action_name, ...
    method test_form_invalid (line 180) | def test_form_invalid(
    method test__sync_all_instances (line 237) | def test__sync_all_instances(self, fake_selected_pks, monkeypatch):
    method test__resync_instances (line 293) | def test__resync_instances(self, djstripe_owner_account_exists, monkey...
    method test__resync_instances_stripe_permission_error (line 370) | def test__resync_instances_stripe_permission_error(self, monkeypatch):
    method test__resync_instances_stripe_invalid_request_error (line 419) | def test__resync_instances_stripe_invalid_request_error(self, monkeypa...
    method test__cancel_subscription_instances (line 463) | def test__cancel_subscription_instances(
    method test__cancel_subscription_instances_stripe_invalid_request_error (line 567) | def test__cancel_subscription_instances_stripe_invalid_request_error(
    method test__release_subscription_schedule (line 660) | def test__release_subscription_schedule(
    method test__cancel_subscription_schedule (line 768) | def test__cancel_subscription_schedule(
    method test__release_subscription_schedule_stripe_invalid_request_error (line 876) | def test__release_subscription_schedule_stripe_invalid_request_error(
    method test__cancel_subscription_schedule_stripe_invalid_request_error (line 974) | def test__cancel_subscription_schedule_stripe_invalid_request_error(

FILE: tests/test_webhooks.py
  function mock_webhook_handler (line 35) | def mock_webhook_handler(webhook_event_trigger):
  class TestWebhookEventTrigger (line 39) | class TestWebhookEventTrigger(TestCase):
    method _send_event (line 42) | def _send_event(self, event_data):
    method test_webhook_test_event (line 50) | def test_webhook_test_event(self):
    method test___str__ (line 59) | def test___str__(self):
    method test_webhook_retrieve_event_fail (line 81) | def test_webhook_retrieve_event_fail(
    method test_webhook_retrieve_event_pass (line 115) | def test_webhook_retrieve_event_pass(
    method test_webhook_invalid_verify_signature_fail (line 144) | def test_webhook_invalid_verify_signature_fail(
    method test_webhook_verify_signature_pass (line 182) | def test_webhook_verify_signature_pass(
    method test_webhook_no_validation_pass (line 220) | def test_webhook_no_validation_pass(
    method test_webhook_no_signature (line 241) | def test_webhook_no_signature(self):
    method test_webhook_remote_addr_is_none (line 249) | def test_webhook_remote_addr_is_none(self):
    method test_webhook_remote_addr_is_empty_string (line 265) | def test_webhook_remote_addr_is_empty_string(self):
    method test_webhook_reraise_exception (line 286) | def test_webhook_reraise_exception(
    method test_webhook_with_custom_callback (line 326) | def test_webhook_with_custom_callback(
    method test_webhook_with_transfer_event_duplicate (line 355) | def test_webhook_with_transfer_event_duplicate(
    method test_webhook_good_platform_account (line 390) | def test_webhook_good_platform_account(
    method test_webhook_good_connect_account (line 425) | def test_webhook_good_connect_account(
    method test_webhook_error (line 456) | def test_webhook_error(
  class TestWebhookHandlers (line 481) | class TestWebhookHandlers(TestCase):
    method setUp (line 482) | def setUp(self):
    method test_global_handler_registration (line 494) | def test_global_handler_registration(self):
    method test_event_handler_registration (line 501) | def test_event_handler_registration(self):
    method test_event_subtype_handler_registration (line 512) | def test_event_subtype_handler_registration(self):
    method test_global_handler_registration_with_function (line 524) | def test_global_handler_registration_with_function(self):
    method test_event_handle_registation_with_string (line 531) | def test_event_handle_registation_with_string(self):
    method test_event_handle_registation_with_list_of_strings (line 538) | def test_event_handle_registation_with_list_of_strings(self):
    method test_webhook_event_trigger_invalid_body (line 546) | def test_webhook_event_trigger_invalid_body(self):
    method _call_handlers (line 555) | def _call_handlers(event_spec, data):
  class TestGetRemoteIp (line 567) | class TestGetRemoteIp:
    class RequestClass (line 568) | class RequestClass:
      method __init__ (line 569) | def __init__(self, data):
      method headers (line 573) | def headers(self):
      method META (line 577) | def META(self):
    method test_get_remote_ip (line 593) | def test_get_remote_ip(self, data):
    method test_get_remote_ip_remote_addr_is_none (line 608) | def test_get_remote_ip_remote_addr_is_none(self, data):
  class TestWebhookEndpoint (line 618) | class TestWebhookEndpoint:
    method test_sync_from_stripe_data_non_existent_webhook_endpoint (line 621) | def test_sync_from_stripe_data_non_existent_webhook_endpoint(self):
    method test_sync_from_stripe_data_existent_webhook_endpoint (line 631) | def test_sync_from_stripe_data_existent_webhook_endpoint(self):
    method test___str__ (line 659) | def test___str__(self):

FILE: tests/urls.py
  function empty_view (line 8) | def empty_view(request):
Condensed preview — 290 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,178K chars).
[
  {
    "path": ".editorconfig",
    "chars": 267,
    "preview": "# EditorConfig: http://editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 4\nindent_style ="
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 92,
    "preview": "# These are supported funding model platforms\n\ngithub: dj-stripe\nopen_collective: dj-stripe\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/api-change-notice.md",
    "chars": 586,
    "preview": "---\nname: API Change Notice\nabout: Has something changed in the Stripe API that we haven't gotten to? Let us know\ntitle:"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 451,
    "preview": "---\nname: Bug report\nabout: Any other type of bug or crash\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the bug*"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/documentation-issue-request.md",
    "chars": 329,
    "preview": "---\nname: Documentation Issue/Request\nabout: Is something missing from the docs? Is a section of the docs outdated or in"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-or-enhancement-proposal.md",
    "chars": 481,
    "preview": "---\nname: Feature or Enhancement Proposal\nabout: Suggest an idea for this project\ntitle: ''\nlabels: discussion\nassignees"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/general-bug.md",
    "chars": 983,
    "preview": "---\nname: General Bug\nabout: Any type of bug or crash not related to webhooks or syncing\ntitle: ''\nlabels: bug\nassignees"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/how-to-usage-question.md",
    "chars": 343,
    "preview": "---\nname: How To/Usage Question\nabout: Have a question on how to use a dj-stripe feature?\ntitle: How do I [short descrip"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/issue-with-webhooks-or-sync.md",
    "chars": 1133,
    "preview": "---\nname: Issue with webhooks or sync\nabout: For issues happening specifically when data is being synced from Stripe to\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/migration-upgrade-issue.md",
    "chars": 692,
    "preview": "---\nname: Migration/Upgrade Issue\nabout: Having trouble upgrading versions of dj-stripe? Let us know\ntitle: Failure when"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/other-issue.md",
    "chars": 89,
    "preview": "---\nname: Other Issue\nabout: For anything else\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 369,
    "preview": "<!--\n\nThank you for your pull request!\n\nPlease adhere to the following guidelines:\n\n- Clear, single-purpose, atomic comm"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 156,
    "preview": "version: 2\nupdates:\n  # Update Github actions in workflows\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n  "
  },
  {
    "path": ".github/install_poetry_action/action.yaml",
    "chars": 943,
    "preview": "name: Setup and install poetry\ndescription: Install and Setup Poetry\n\ninputs:\n  POETRY_VERSION:\n    required: true\n    t"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 1584,
    "preview": "name: CI tests\n\non:\n  push:\n    paths-ignore:\n      - \"docs/**\"\n      - \"pyproject.toml\"\n      - \"mkdocs.yml\"\n      - \"."
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "chars": 1998,
    "preview": "name: \"CodeQL\"\n\non:\n  push:\n    branches: [master]\n  pull_request:\n    # The branches below must be a subset of the bran"
  },
  {
    "path": ".github/workflows/docs.yml",
    "chars": 1180,
    "preview": "name: Build and deploy docs\n\non:\n  push:\n    branches:\n      - \"master\"\n      # Push events to branches matching \"stable"
  },
  {
    "path": ".github/workflows/linting.yml",
    "chars": 618,
    "preview": "name: Linting\n\non:\n  push:\n\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches"
  },
  {
    "path": ".gitignore",
    "chars": 228,
    "preview": "*.py[cod]\n__pycache__\n.tox\ndj_stripe.egg-info\n*.mo\n\n# Environments\n.venv\n\n# mkdocs\nsite/\n\n# SQLite\n*.sqlite3\n\n# Coverage"
  },
  {
    "path": ".pre-commit-config.yaml",
    "chars": 682,
    "preview": "exclude: \".git|.tox|.pytest_cache\"\ndefault_stages: [commit]\nfail_fast: true\n\nrepos:\n  - repo: https://github.com/pre-com"
  },
  {
    "path": ".readthedocs.yml",
    "chars": 270,
    "preview": "# Read the Docs configuration file\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details\n\nversion:"
  },
  {
    "path": "LICENSE",
    "chars": 1084,
    "preview": "MIT License\n\nCopyright (c) 2020 The @dj-stripe Organization\n\nPermission is hereby granted, free of charge, to any person"
  },
  {
    "path": "djstripe/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "djstripe/admin/__init__.py",
    "chars": 130,
    "preview": "from .admin import StripeModelAdmin\n\n# Do not remove: This ensures loading of djstripe.admin.admin\n__all__ = [\"StripeMod"
  },
  {
    "path": "djstripe/admin/actions.py",
    "chars": 4219,
    "preview": "\"\"\"\nDjango Administration Custom Actions Module\n\"\"\"\nfrom django.contrib import admin\nfrom django.contrib.admin import he"
  },
  {
    "path": "djstripe/admin/admin.py",
    "chars": 25925,
    "preview": "\"\"\"\nDjango Administration interface definitions\n\"\"\"\nfrom typing import Any, Dict\n\nfrom django.contrib import admin\nfrom "
  },
  {
    "path": "djstripe/admin/admin_inline.py",
    "chars": 2390,
    "preview": "\"\"\"\nDjango Administration Inline interface definitions\n\"\"\"\nfrom django.contrib import admin\n\nfrom djstripe import models"
  },
  {
    "path": "djstripe/admin/filters.py",
    "chars": 2861,
    "preview": "\"\"\"\nDjango Administration Custom Filters Module\n\"\"\"\nfrom django.contrib import admin\n\nfrom djstripe import models\n\n\nclas"
  },
  {
    "path": "djstripe/admin/forms.py",
    "chars": 9224,
    "preview": "\"\"\"\nModule for all dj-stripe Admin app forms\n\"\"\"\nfrom typing import Optional\nfrom urllib.parse import urljoin\n\nfrom djan"
  },
  {
    "path": "djstripe/admin/utils.py",
    "chars": 880,
    "preview": "\"\"\"\nDjango Administration Utils Module\n\"\"\"\n\n\nclass ReadOnlyMixin:\n    def has_add_permission(self, request):\n        ret"
  },
  {
    "path": "djstripe/admin/views.py",
    "chars": 4645,
    "preview": "\"\"\"\ndj-stripe - Views related to the djstripe app.\n\"\"\"\nimport logging\n\nimport stripe\nfrom django.contrib import messages"
  },
  {
    "path": "djstripe/apps.py",
    "chars": 766,
    "preview": "\"\"\"\ndj-stripe - Django + Stripe Made Easy\n\"\"\"\nimport pkg_resources\nfrom django.apps import AppConfig\n\n__version__ = pkg_"
  },
  {
    "path": "djstripe/checks.py",
    "chars": 13634,
    "preview": "\"\"\"\ndj-stripe System Checks\n\"\"\"\nimport re\n\nfrom django.core import checks\nfrom django.db.utils import DatabaseError\n\nSTR"
  },
  {
    "path": "djstripe/enums.py",
    "chars": 26155,
    "preview": "import operator\nfrom collections import OrderedDict\n\nfrom django.utils.translation import gettext_lazy as _\n\n\nclass Enum"
  },
  {
    "path": "djstripe/event_handlers.py",
    "chars": 14589,
    "preview": "\"\"\"\nWebhook event handlers for the various models\n\nStripe docs for Events: https://stripe.com/docs/api/events\nStripe doc"
  },
  {
    "path": "djstripe/exceptions.py",
    "chars": 633,
    "preview": "\"\"\"\ndj-stripe Exceptions.\n\"\"\"\n\n\nclass MultipleSubscriptionException(Exception):\n    \"\"\"Raised when a Customer has multip"
  },
  {
    "path": "djstripe/fields.py",
    "chars": 6138,
    "preview": "\"\"\"\ndj-stripe Custom Field Definitions\n\"\"\"\nimport decimal\n\nfrom django.conf import SettingsReference, settings\nfrom djan"
  },
  {
    "path": "djstripe/locale/fr/LC_MESSAGES/django.po",
    "chars": 17508,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: 1.3.0\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2019-01-28 12:02+1300\\n\""
  },
  {
    "path": "djstripe/locale/ru/LC_MESSAGES/django.po",
    "chars": 17574,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: 1.3.0\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2019-01-28 12:02+1300\\n\""
  },
  {
    "path": "djstripe/management/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "djstripe/management/commands/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "djstripe/management/commands/djstripe_clear_expired_idempotency_keys.py",
    "chars": 271,
    "preview": "from django.core.management.base import BaseCommand\n\nfrom ...utils import clear_expired_idempotency_keys\n\n\nclass Command"
  },
  {
    "path": "djstripe/management/commands/djstripe_init_customers.py",
    "chars": 1016,
    "preview": "\"\"\"\ninit_customers command.\n\"\"\"\nfrom django.core.management.base import BaseCommand\n\nfrom ...models import Customer\nfrom"
  },
  {
    "path": "djstripe/management/commands/djstripe_process_events.py",
    "chars": 4089,
    "preview": "from django.core.management.base import BaseCommand\n\nfrom ... import models\nfrom ...mixins import VerbosityAwareOutputMi"
  },
  {
    "path": "djstripe/management/commands/djstripe_sync_customers.py",
    "chars": 861,
    "preview": "\"\"\"\nsync_customer command.\n\"\"\"\nfrom django.core.management.base import BaseCommand\n\nfrom ...settings import djstripe_set"
  },
  {
    "path": "djstripe/management/commands/djstripe_sync_models.py",
    "chars": 21565,
    "preview": "\"\"\"Module for the djstripe_sync_model management command to sync\nall Stripe objects to the local db.\n\nInvoke like so:\n  "
  },
  {
    "path": "djstripe/management/commands/djstripe_update_invoiceitem_ids.py",
    "chars": 2896,
    "preview": "from django.core.management.base import BaseCommand\nfrom django.db import transaction\n\nfrom ...models.billing import Inv"
  },
  {
    "path": "djstripe/managers.py",
    "chars": 3267,
    "preview": "\"\"\"\ndj-stripe model managers\n\"\"\"\nimport decimal\n\nfrom django.db import models\n\n\nclass StripeModelManager(models.Manager)"
  },
  {
    "path": "djstripe/migrations/0001_initial.py",
    "chars": 209453,
    "preview": "# Generated by Django 3.2.11 on 2022-01-17 03:13\n\nimport uuid\n\nimport django.core.validators\nimport django.db.models.del"
  },
  {
    "path": "djstripe/migrations/0008_2_5.py",
    "chars": 11473,
    "preview": "# Generated by Django 3.2.3 on 2021-05-30 23:47\n\nimport django.db.models.deletion\nfrom django.conf import settings\nfrom "
  },
  {
    "path": "djstripe/migrations/0009_2_6.py",
    "chars": 14130,
    "preview": "# Generated by Django 3.2.4 on 2021-06-22 01:38\n\nimport uuid\n\nimport django.core.validators\nimport django.db.models.dele"
  },
  {
    "path": "djstripe/migrations/0010_alter_customer_balance.py",
    "chars": 471,
    "preview": "# Generated by Django 4.0.1 on 2022-01-12 13:12\n\nfrom django.db import migrations\n\nimport djstripe.fields\n\n\nclass Migrat"
  },
  {
    "path": "djstripe/migrations/0011_2_7.py",
    "chars": 18331,
    "preview": "# Generated by Django 3.2.11 on 2022-01-19 04:59\n\nimport django.db.models.deletion\nfrom django.conf import settings\nfrom"
  },
  {
    "path": "djstripe/migrations/0012_auto_20221217_0559.py",
    "chars": 2287,
    "preview": "# Generated by Django 3.2.15 on 2022-12-17 05:59\n\nfrom django.db import migrations\n\nimport djstripe.enums\nimport djstrip"
  },
  {
    "path": "djstripe/migrations/0013_product_default_price.py",
    "chars": 831,
    "preview": "# Generated by Django 3.2.15 on 2022-12-21 10:57\n\nimport django.db.models.deletion\nfrom django.conf import settings\nfrom"
  },
  {
    "path": "djstripe/migrations/0014_lineitem.py",
    "chars": 6391,
    "preview": "# Generated by Django 3.2.16 on 2023-01-26 05:14\n\nimport django.db.models.deletion\nfrom django.conf import settings\nfrom"
  },
  {
    "path": "djstripe/migrations/0015_alter_payout_destination.py",
    "chars": 1816,
    "preview": "# Generated by Django 3.2.12 on 2022-03-29 06:49\n\nfrom pathlib import Path\n\nfrom django.db import migrations\n\n\ndef get_s"
  },
  {
    "path": "djstripe/migrations/0016_alter_payout_destination.py",
    "chars": 611,
    "preview": "# Generated by Django 3.2.16 on 2023-01-26 14:47\n\nimport django.db.models.deletion\nfrom django.db import migrations\n\nimp"
  },
  {
    "path": "djstripe/migrations/0017_invoiceorlineitem.py",
    "chars": 843,
    "preview": "# Generated by Django 3.2.13 on 2022-07-09 08:04\n\nimport django.db.models.deletion\nfrom django.conf import settings\nfrom"
  },
  {
    "path": "djstripe/migrations/0018_discount.py",
    "chars": 5897,
    "preview": "# Generated by Django 3.2.16 on 2023-01-28 06:04\n\nimport django.db.models.deletion\nfrom django.conf import settings\nfrom"
  },
  {
    "path": "djstripe/migrations/0019_add_customer_discount.py",
    "chars": 1006,
    "preview": "# Generated by Django 3.2.13 on 2022-07-09 08:09\n\nimport django.db.models.deletion\nfrom django.conf import settings\nfrom"
  },
  {
    "path": "djstripe/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "djstripe/migrations/sql/migrate_mysql_backward.sql",
    "chars": 1059,
    "preview": "--\n-- Rename field destination_clone on payout to destination\n--\nALTER TABLE `djstripe_payout` CHANGE `destination_id` `"
  },
  {
    "path": "djstripe/migrations/sql/migrate_mysql_forward.sql",
    "chars": 1085,
    "preview": "--\n-- Add field destination_clone to payout\n--\nALTER TABLE `djstripe_payout` ADD COLUMN `destination_clone_id` varchar(2"
  },
  {
    "path": "djstripe/migrations/sql/migrate_postgresql_backward.sql",
    "chars": 1446,
    "preview": "--\n-- Rename field destination_clone on payout to destination\n--\nSET CONSTRAINTS \"djstripe_payout_destination_clone_id_f"
  },
  {
    "path": "djstripe/migrations/sql/migrate_postgresql_forward.sql",
    "chars": 1216,
    "preview": "--\n-- Add field destination_clone to payout\n--\nALTER TABLE \"djstripe_payout\" ADD COLUMN \"destination_clone_id\" varchar(2"
  },
  {
    "path": "djstripe/migrations/sql/migrate_sqlite_backward.sql",
    "chars": 5867,
    "preview": "--\n-- Rename field destination_clone on payout to destination\n--\nCREATE TABLE \"new__djstripe_payout\" (\"destination_clone"
  },
  {
    "path": "djstripe/migrations/sql/migrate_sqlite_forward.sql",
    "chars": 3269,
    "preview": "--\n-- Add field destination_clone to payout\n--\nALTER TABLE \"djstripe_payout\" ADD COLUMN \"destination_clone_id\" varchar(2"
  },
  {
    "path": "djstripe/mixins.py",
    "chars": 1971,
    "preview": "\"\"\"\ndj-stripe mixins\n\"\"\"\nimport sys\nimport traceback\n\nfrom .models import Customer, Plan\nfrom .settings import djstripe_"
  },
  {
    "path": "djstripe/models/__init__.py",
    "chars": 1990,
    "preview": "from .account import Account\nfrom .api import APIKey\nfrom .base import IdempotencyKey, StripeModel\nfrom .billing import "
  },
  {
    "path": "djstripe/models/account.py",
    "chars": 10234,
    "preview": "import stripe\nfrom django.db import models, transaction\n\nfrom .. import enums\nfrom ..enums import APIKeyType\nfrom ..fiel"
  },
  {
    "path": "djstripe/models/api.py",
    "chars": 4226,
    "preview": "import re\nfrom base64 import b64encode\nfrom uuid import uuid4\n\nfrom django.core.validators import RegexValidator\nfrom dj"
  },
  {
    "path": "djstripe/models/base.py",
    "chars": 40485,
    "preview": "import logging\nimport uuid\nfrom datetime import timedelta\nfrom typing import Dict, List, Optional, Type\n\nfrom django.db "
  },
  {
    "path": "djstripe/models/billing.py",
    "chars": 100132,
    "preview": "import logging\nimport warnings\nfrom typing import Optional, Union\n\nimport stripe\nfrom django.db import models\nfrom djang"
  },
  {
    "path": "djstripe/models/checkout.py",
    "chars": 4554,
    "preview": "import stripe\nfrom django.db import models\n\nfrom djstripe.settings import djstripe_settings\n\nfrom .. import enums\nfrom ."
  },
  {
    "path": "djstripe/models/connect.py",
    "chars": 13194,
    "preview": "import stripe\nfrom django.db import models\n\nfrom djstripe.utils import get_friendly_currency_amount\n\nfrom .. import enum"
  },
  {
    "path": "djstripe/models/core.py",
    "chars": 85968,
    "preview": "from decimal import Decimal\nfrom typing import Optional, Union\n\nimport stripe\nfrom django.apps import apps\nfrom django.d"
  },
  {
    "path": "djstripe/models/fraud.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "djstripe/models/orders.py",
    "chars": 8366,
    "preview": "import stripe\nfrom django.db import models\n\nfrom djstripe.models.billing import Discount\nfrom djstripe.settings import d"
  },
  {
    "path": "djstripe/models/payment_methods.py",
    "chars": 37989,
    "preview": "from typing import Optional, Union\n\nimport stripe\nfrom django.db import models, transaction\nfrom stripe.error import Inv"
  },
  {
    "path": "djstripe/models/sigma.py",
    "chars": 1489,
    "preview": "import stripe\nfrom django.db import models\n\nfrom .. import enums\nfrom ..fields import JSONField, StripeDateTimeField, St"
  },
  {
    "path": "djstripe/models/webhooks.py",
    "chars": 11769,
    "preview": "\"\"\"\nModule for dj-stripe Webhook models\n\"\"\"\n\nimport json\nimport warnings\nfrom traceback import format_exc\nfrom uuid impo"
  },
  {
    "path": "djstripe/settings.py",
    "chars": 8205,
    "preview": "\"\"\"\ndj-stripe settings\n\"\"\"\nimport stripe\nfrom django.apps import apps as django_apps\nfrom django.conf import settings\nfr"
  },
  {
    "path": "djstripe/signals.py",
    "chars": 8617,
    "preview": "\"\"\"\nsignals are sent for each event Stripe sends to the app\n\nStripe docs for Webhooks: https://stripe.com/docs/webhooks\n"
  },
  {
    "path": "djstripe/sync.py",
    "chars": 579,
    "preview": "\"\"\"\nUtility functions used for syncing data.\n\"\"\"\nfrom stripe.error import InvalidRequestError\n\nfrom .models import Custo"
  },
  {
    "path": "djstripe/templates/djstripe/admin/add_form.html",
    "chars": 251,
    "preview": "{% extends \"./change_form.html\" %}\n\n\n\n{% block djstripewarning %}\n    <p class=\"stripe-confirmation-warning\">{{opts.verb"
  },
  {
    "path": "djstripe/templates/djstripe/admin/change_form.html",
    "chars": 984,
    "preview": "{% extends \"admin/change_form.html\" %}\n{% load i18n %}\n\n{% block object-tools-items %}\n    {{ block.super }}\n    {% with"
  },
  {
    "path": "djstripe/templates/djstripe/admin/confirm_action.html",
    "chars": 2788,
    "preview": "{% extends \"admin/base_site.html\" %}\n{% load i18n static l10n admin_urls %}\n\n\n{% block extrahead %}\n    {{ block.super }"
  },
  {
    "path": "djstripe/templates/djstripe/admin/webhook_endpoint/add_form.html",
    "chars": 250,
    "preview": "{% extends \"./change_form.html\" %}\n\n\n{% block djstripewarning %}\n    <p class=\"stripe-danger-warning\">{{opts.verbose_nam"
  },
  {
    "path": "djstripe/templates/djstripe/admin/webhook_endpoint/change_form.html",
    "chars": 227,
    "preview": "{% extends \"../change_form.html\" %}\n\n\n{% block djstripewarning %}\n    <p class=\"stripe-danger-warning\">Any Changes made "
  },
  {
    "path": "djstripe/templates/djstripe/admin/webhook_endpoint/delete_confirmation.html",
    "chars": 1251,
    "preview": "{% extends \"admin/delete_confirmation.html\" %}\n{% block extrahead %}\n    {{ block.super }}\n    <script>\n\n    // Handler "
  },
  {
    "path": "djstripe/urls.py",
    "chars": 679,
    "preview": "\"\"\"\nUrls related to the djstripe app.\n\nWire this into the root URLConf this way::\n\n    path(\"stripe/\", include(\"djstripe"
  },
  {
    "path": "djstripe/utils.py",
    "chars": 3359,
    "preview": "\"\"\"\nUtility functions related to the djstripe app.\n\"\"\"\nimport datetime\nfrom typing import Optional\n\nimport stripe\nfrom d"
  },
  {
    "path": "djstripe/views.py",
    "chars": 2158,
    "preview": "\"\"\"\ndj-stripe - Views related to the djstripe app.\n\"\"\"\nimport logging\n\nfrom django.http import HttpResponse, HttpRespons"
  },
  {
    "path": "djstripe/webhooks.py",
    "chars": 3045,
    "preview": "\"\"\"\nUtils related to processing or registering for webhooks\n\nA model registers itself here if it wants to be in the list"
  },
  {
    "path": "docs/CONTRIBUTING.md",
    "chars": 7618,
    "preview": "# Contributing\n\nContributions are welcome, and they are greatly appreciated! Every little bit helps, and\ncredit will alw"
  },
  {
    "path": "docs/README.md",
    "chars": 3600,
    "preview": "# dj-stripe - Django + Stripe Made Easy\n\n[![Stripe Verified Partner](https://img.shields.io/static/v1?label=Stripe&messa"
  },
  {
    "path": "docs/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "docs/api_keys.md",
    "chars": 2831,
    "preview": "# Managing Stripe API keys\n\nStripe API keys are stored in the database, and editable from the Django admin.\n\n!!! attenti"
  },
  {
    "path": "docs/api_versions.md",
    "chars": 1933,
    "preview": "# A note on Stripe API versions\n\nA point that can cause confusion to new users of dj-stripe is that there\nare several di"
  },
  {
    "path": "docs/history/0_x.md",
    "chars": 10247,
    "preview": "# dj-stripe 0.x release notes\n\n## 0.8.0 (2015-12-30)\n\n-   better plan ordering documentation (Thanks @cjrh)\n-   added a "
  },
  {
    "path": "docs/history/1_x.md",
    "chars": 19436,
    "preview": "# dj-stripe 1.x release notes\n\n## 1.2.4 (2019-02-27)\n\nThis is a bugfix-only version:\n\n-   Allow billing_cycle_anchor arg"
  },
  {
    "path": "docs/history/2_4_0.md",
    "chars": 8389,
    "preview": "# dj-stripe 2.4.0 release notes (2020-11-19)\n\n!!! attention\n\n    To upgrade to 2.4.0 from older versions of dj-stripe, s"
  },
  {
    "path": "docs/history/2_4_x.md",
    "chars": 1603,
    "preview": "# dj-stripe 2.4.4 release notes (2021-05-22)\n\n-   Fix syncing of tax IDs in management commands\n-   Set `default_auto_fi"
  },
  {
    "path": "docs/history/2_5_0.md",
    "chars": 2371,
    "preview": "# dj-stripe 2.5.0 (2021-06-06)\n\n!!! attention\n\n    It is not possible to upgrade to dj-stripe 2.5.0 from versions older "
  },
  {
    "path": "docs/history/2_5_x.md",
    "chars": 238,
    "preview": "# dj-stripe 2.5.1 (2021-07-02)\n\n## Release notes\n\n-   Fixed migration issue for new setups using custom `DJSTRIPE_CUSTOM"
  },
  {
    "path": "docs/history/2_6_0.md",
    "chars": 3440,
    "preview": "# dj-stripe 2.6.0 (2022-01-15)\n\n!!! attention\n\n    It is not possible to upgrade to dj-stripe 2.6.0 from versions older "
  },
  {
    "path": "docs/history/2_6_x.md",
    "chars": 469,
    "preview": "# dj-stripe 2.6.2 (2022-07-02)\n\nThis is a maintenance release to remove the generation of an unnecessary migration when\n"
  },
  {
    "path": "docs/history/2_7_0.md",
    "chars": 1401,
    "preview": "# dj-stripe 2.7.0 (2022-10-17)\n\n!!! attention\n\n    It is not possible to upgrade to dj-stripe 2.7.0 from versions older "
  },
  {
    "path": "docs/history/2_7_x.md",
    "chars": 313,
    "preview": "# dj-stripe 2.7.2 (2022-10-21)\n\n## Release notes\n\n-   Fix installing with Poetry on Django 4.0 and higher\n\n# dj-stripe 2"
  },
  {
    "path": "docs/history/2_8_0.md",
    "chars": 3184,
    "preview": "# dj-stripe 2.8.0 (202X-XX-XX)\n\n!!! attention\n\n    It is not possible to upgrade to dj-stripe 2.8.0 from versions older "
  },
  {
    "path": "docs/history/2_x.md",
    "chars": 16057,
    "preview": "# dj-stripe 2.0 ~ 2.3 release notes\n\n## 2.3.0 (2020-04-19)\n\n-   The minimum version of Django is now 2.1, and Python 3.6"
  },
  {
    "path": "docs/installation.md",
    "chars": 1981,
    "preview": "## Installation\n\n### Get the distribution\n\nInstall dj-stripe with pip:\n```bash\n\n    pip install dj-stripe\n```\n\nOr with ["
  },
  {
    "path": "docs/project/authors.md",
    "chars": 648,
    "preview": "# Credits\n\n## Core contributors\n\n-   [Alexander Kavanaugh](https://github.com/kavdev) (Co-maintainer)\n-   [Jerome Leclan"
  },
  {
    "path": "docs/project/release_process.md",
    "chars": 3749,
    "preview": "# Release Process\n\n!!! note\n\n    Before `MAJOR` or `MINOR` releases:\n\n    -   Review deprecation notes (eg search for \"d"
  },
  {
    "path": "docs/project/sponsors.md",
    "chars": 492,
    "preview": "# Sponsors\n\n## Gold Sponsors\n\n[![Stripe Logo](../logos/stripe_blurple.svg)](https://stripe.com)\n\nThis project is sponsor"
  },
  {
    "path": "docs/project/support.md",
    "chars": 631,
    "preview": "# Support\n\n## Support plans\n\ndj-stripe offers paid support plans via Github Sponsors:\n\n<https://github.com/sponsors/dj-s"
  },
  {
    "path": "docs/project/test_fixtures.md",
    "chars": 2350,
    "preview": "# Test Fixtures\n\ndj-stripe's unit tests rely on fixtures to represent Stripe API and\nwebhook data.\n\n## Rationale\n\nThese "
  },
  {
    "path": "docs/reference/enums.md",
    "chars": 36,
    "preview": "# Enumerations\n\n\n::: djstripe.enums\n"
  },
  {
    "path": "docs/reference/managers.md",
    "chars": 34,
    "preview": "# Managers\n\n::: djstripe.managers\n"
  },
  {
    "path": "docs/reference/models.md",
    "chars": 1079,
    "preview": "# Models\n\nModels hold the bulk of the functionality included in the dj-stripe\npackage. Each model is tied closely to its"
  },
  {
    "path": "docs/reference/project.md",
    "chars": 233,
    "preview": "\n<!-- We load the djstripe and tests packages in order for mkdocstrings to create links to them and their sub-packages a"
  },
  {
    "path": "docs/reference/settings.md",
    "chars": 7749,
    "preview": "# Settings\n\n## STRIPE_API_VERSION (='2020-08-27')\n\nThe API version used to communicate with the Stripe API is configurab"
  },
  {
    "path": "docs/reference/utils.md",
    "chars": 33,
    "preview": "# Utilities\n\n\n::: djstripe.utils\n"
  },
  {
    "path": "docs/stripe_elements_js.md",
    "chars": 1684,
    "preview": "# Integrating Stripe Elements (JS SDK)\n\n!!! tip\n\n    TLDR: If you haven't yet migrated to PaymentIntents, prefer\n    `st"
  },
  {
    "path": "docs/usage/creating_individual_charges.md",
    "chars": 555,
    "preview": "# Creating individual charges\n\nOn the subscriber's customer object, use the [`charge`][djstripe.models.core.Customer.cha"
  },
  {
    "path": "docs/usage/creating_usage_record.md",
    "chars": 738,
    "preview": "# Create a Stripe Usage Record\n\nUsage records allow you to report customer usage and metrics to Stripe for metered billi"
  },
  {
    "path": "docs/usage/local_webhook_testing.md",
    "chars": 1700,
    "preview": "# Local Webhook Testing\n\nThe [Stripe CLI][cli] allows receiving webhooks events from Stripe on your local machine via a "
  },
  {
    "path": "docs/usage/managing_subscriptions.md",
    "chars": 714,
    "preview": "# Managing subscriptions and payment sources\n\n## Extending subscriptions\n\nFor your convenience, dj-stripe provides a [`S"
  },
  {
    "path": "docs/usage/manually_syncing_with_stripe.md",
    "chars": 2476,
    "preview": "# Manually syncing data with Stripe\n\nIf you're using dj-stripe's webhook handlers then data will be\nautomatically synced"
  },
  {
    "path": "docs/usage/subscribing_customers.md",
    "chars": 2333,
    "preview": "# Subscribing a customer to one or more prices (or plans)\n\n## Recommended Approach\n\n```python\n# Recommended Approach to "
  },
  {
    "path": "docs/usage/using_stripe_checkout.md",
    "chars": 515,
    "preview": "# Create a Stripe Checkout Session\n\n\nFor your convenience, dj-stripe has provided an example implementation on how to us"
  },
  {
    "path": "docs/usage/using_with_docker.md",
    "chars": 1959,
    "preview": "# Using with Docker\n\nA [Docker image](https://hub.docker.com/r/stripe/stripe-cli) allows you to run the Stripe CLI in a "
  },
  {
    "path": "docs/usage/webhooks.md",
    "chars": 3980,
    "preview": "# Using Stripe Webhooks\n\n## Setting up a new webhook endpoint in dj-stripe\n\nAs of dj-stripe 2.7.0, dj-stripe can create "
  },
  {
    "path": "manage.py",
    "chars": 448,
    "preview": "#!/usr/bin/env python\nimport os\nimport sys\n\ntry:\n    from django.core.management import execute_from_command_line\nexcept"
  },
  {
    "path": "mkdocs.yml",
    "chars": 2872,
    "preview": "site_name: Dj-Stripe\nsite_url: https://dj-stripe.github.io/dj-stripe/\nsite_description: Django + Stripe Made Easy\nsite_a"
  },
  {
    "path": "pyproject.toml",
    "chars": 4662,
    "preview": "[tool.poetry]\nname = \"dj-stripe\"\nversion = \"2.8.0-dev.0\"\ndescription = \"Django + Stripe made easy\"\nlicense = \"MIT\"\nautho"
  },
  {
    "path": "tests/__init__.py",
    "chars": 75361,
    "preview": "\"\"\"\nA Fake or multiple fakes for each stripe object.\n\nOriginally collected using API VERSION 2015-07-28.\nUpdated to API "
  },
  {
    "path": "tests/apps/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/apps/example/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/apps/example/forms.py",
    "chars": 365,
    "preview": "from django import forms\n\nimport djstripe.models\n\n\nclass PurchaseSubscriptionForm(forms.Form):\n    email = forms.EmailFi"
  },
  {
    "path": "tests/apps/example/management/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/apps/example/management/commands/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/apps/example/management/commands/regenerate_test_fixtures.py",
    "chars": 29237,
    "preview": "import json\nfrom copy import deepcopy\n\nimport stripe.api_resources\nimport stripe.stripe_object\nfrom django.core.manageme"
  },
  {
    "path": "tests/apps/example/templates/checkout.html",
    "chars": 856,
    "preview": "<html>\n  <head>\n    <title>Checkout</title>\n    <script src=\"https://js.stripe.com/v3/\"></script>\n  </head>\n  <body>\n   "
  },
  {
    "path": "tests/apps/example/templates/checkout_success.html",
    "chars": 283,
    "preview": "{% extends \"base.html\" %}\n\n{% block title %}Thanks for your order!{% endblock %}\n\n{% block content %}\n    <p>\n      We a"
  },
  {
    "path": "tests/apps/example/templates/example_base.html",
    "chars": 270,
    "preview": "{% extends \"base.html\" %}\n\n\n{% block header_css %}\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/b"
  },
  {
    "path": "tests/apps/example/templates/payment_intent.html",
    "chars": 6183,
    "preview": "{% extends \"example_base.html\" %}\n\n{% block header_js %}\n{{ block.super }}\n\n<script src=\"https://js.stripe.com/v3/\"></sc"
  },
  {
    "path": "tests/apps/example/templates/purchase_subscription.html",
    "chars": 5313,
    "preview": "{% extends \"example_base.html\" %}\n\n{% comment%}\nexample subscription purchase page, very closely based on https://stripe"
  },
  {
    "path": "tests/apps/example/templates/purchase_subscription_success.html",
    "chars": 354,
    "preview": "{% extends \"example_base.html\" %}\n\n{% block content %}\n\n<section class=\"section\">\n    <div class=\"container\">\n        Su"
  },
  {
    "path": "tests/apps/example/urls.py",
    "chars": 680,
    "preview": "from django.urls import path\n\nfrom . import views\n\napp_name = \"djstripe_example\"\n\nurlpatterns = [\n    path(\n        \"che"
  },
  {
    "path": "tests/apps/example/views.py",
    "chars": 10627,
    "preview": "import json\nimport logging\n\nimport stripe\nfrom django.contrib.auth import get_user_model\nfrom django.contrib.auth.mixins"
  },
  {
    "path": "tests/apps/testapp/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/apps/testapp/models.py",
    "chars": 580,
    "preview": "from django.db.models.base import Model\nfrom django.db.models.fields import CharField, EmailField\n\n\nclass Organization(M"
  },
  {
    "path": "tests/apps/testapp/urls.py",
    "chars": 267,
    "preview": "from django.http import HttpResponse\nfrom django.urls import include, path\n\n\ndef empty_view(request):\n    return HttpRes"
  },
  {
    "path": "tests/apps/testapp_content/README.md",
    "chars": 29,
    "preview": "Represents protected content\n"
  },
  {
    "path": "tests/apps/testapp_content/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/apps/testapp_content/models.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/apps/testapp_content/urls.py",
    "chars": 217,
    "preview": "\"\"\"\nRepresents protected content\n\"\"\"\n\nfrom django.http import HttpResponse\nfrom django.urls import path\n\n\ndef testview(r"
  },
  {
    "path": "tests/apps/testapp_namespaced/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/apps/testapp_namespaced/models.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/apps/testapp_namespaced/urls.py",
    "chars": 215,
    "preview": "from django.http import HttpResponse\nfrom django.urls import path\n\n\ndef testview(request):\n    return HttpResponse()\n\n\na"
  },
  {
    "path": "tests/conftest.py",
    "chars": 945,
    "preview": "\"\"\"\nModule for creating re-usable fixtures to be used across the test suite\n\"\"\"\nimport pytest\nimport stripe\nfrom django."
  },
  {
    "path": "tests/fields/admin.py",
    "chars": 1976,
    "preview": "from django.contrib import admin\nfrom django.shortcuts import render\n\nfrom djstripe.admin.admin import StripeModelAdmin\n"
  },
  {
    "path": "tests/fields/models.py",
    "chars": 691,
    "preview": "\"\"\"Models used exclusively for testing\"\"\"\n\nfrom django.db import models\n\nfrom djstripe.fields import StripePercentField\n"
  },
  {
    "path": "tests/fixtures/account_custom_acct_1IuHosQveW0ONQsd.json",
    "chars": 5300,
    "preview": "{\n    \"id\": \"acct_1IuHosQveW0ONQsd\",\n    \"object\": \"account\",\n    \"business_profile\": {\n        \"mcc\": null,\n        \"na"
  },
  {
    "path": "tests/fixtures/account_express_acct_1IuHosQveW0ONQsd.json",
    "chars": 4338,
    "preview": "{\n    \"business_profile\": {\n        \"mcc\": null,\n        \"name\": \"Express Account\",\n        \"support_address\": null,\n   "
  },
  {
    "path": "tests/fixtures/account_standard_acct_1Fg9jUA3kq9o1aTc.json",
    "chars": 1551,
    "preview": "{\n    \"id\": \"acct_1Fg9jUA3kq9o1aTc\",\n    \"object\": \"account\",\n    \"metadata\": {},\n    \"business_profile\": {\n        \"nam"
  },
  {
    "path": "tests/fixtures/balance_transaction_txn_fake_ch_fakefakefakefakefake0001.json",
    "chars": 647,
    "preview": "{\n    \"id\": \"txn_fake_ch_fakefakefakefakefake0001\",\n    \"object\": \"balance_transaction\",\n    \"amount\": 2000,\n    \"availa"
  },
  {
    "path": "tests/fixtures/bank_account_ba_fakefakefakefakefake0003.json",
    "chars": 555,
    "preview": "{\n    \"id\": \"ba_fakefakefakefakefake0003\",\n    \"object\": \"bank_account\",\n    \"account_holder_name\": \"Jane Austen\",\n    \""
  },
  {
    "path": "tests/fixtures/bank_account_ba_fakefakefakefakefake0004.json",
    "chars": 514,
    "preview": "{\n    \"id\": \"ba_1IuVozQveW0ONQsd3dWG85e2\",\n    \"object\": \"bank_account\",\n    \"account\": \"acct_1IuHosQveW0ONQsd\",\n    \"ac"
  },
  {
    "path": "tests/fixtures/card_card_fakefakefakefakefake0001.json",
    "chars": 732,
    "preview": "{\n    \"id\": \"card_fakefakefakefakefake0001\",\n    \"object\": \"card\",\n    \"account\": null,\n    \"address_city\": null,\n    \"a"
  },
  {
    "path": "tests/fixtures/card_card_fakefakefakefakefake0002.json",
    "chars": 712,
    "preview": "{\n    \"id\": \"card_fakefakefakefakefake0002\",\n    \"object\": \"card\",\n    \"account\": null,\n    \"address_city\": null,\n    \"a"
  },
  {
    "path": "tests/fixtures/card_card_fakefakefakefakefake0003.json",
    "chars": 712,
    "preview": "{\n    \"id\": \"card_fakefakefakefakefake0003\",\n    \"object\": \"card\",\n    \"account\": null,\n    \"address_city\": null,\n    \"a"
  },
  {
    "path": "tests/fixtures/card_card_fakefakefakefakefake0004.json",
    "chars": 764,
    "preview": "{\n    \"id\": \"card_1IuVlSQveW0ONQsdkXBUUHyE\",\n    \"object\": \"card\",\n    \"account\": \"acct_1IuHosQveW0ONQsd\",\n    \"address_"
  },
  {
    "path": "tests/fixtures/charge_ch_fakefakefakefakefake0001.json",
    "chars": 3578,
    "preview": "{\n    \"id\": \"ch_fakefakefakefakefake0001\",\n    \"object\": \"charge\",\n    \"amount\": 2000,\n    \"amount_captured\": 0,\n    \"am"
  },
  {
    "path": "tests/fixtures/customer_cus_4QWKsZuuTHcs7X.json",
    "chars": 3909,
    "preview": "{\n    \"id\": \"cus_4QWKsZuuTHcs7X\",\n    \"object\": \"customer\",\n    \"address\": null,\n    \"balance\": 0,\n    \"created\": 155799"
  },
  {
    "path": "tests/fixtures/customer_cus_4UbFSo9tl62jqj.json",
    "chars": 16486,
    "preview": "{\n    \"id\": \"cus_4UbFSo9tl62jqj\",\n    \"object\": \"customer\",\n    \"address\": null,\n    \"balance\": 0,\n    \"created\": 155799"
  },
  {
    "path": "tests/fixtures/customer_cus_6lsBvm5rJ0zyHc.json",
    "chars": 17068,
    "preview": "{\n    \"id\": \"cus_6lsBvm5rJ0zyHc\",\n    \"object\": \"customer\",\n    \"address\": null,\n    \"balance\": 0,\n    \"created\": 155799"
  },
  {
    "path": "tests/fixtures/customer_cus_example_with_bank_account.json",
    "chars": 2293,
    "preview": "{\n    \"id\": \"cus_example_with_bank_account\",\n    \"object\": \"customer\",\n    \"address\": null,\n    \"balance\": 0,\n    \"creat"
  },
  {
    "path": "tests/fixtures/dispute_ch_fakefakefakefake01.json",
    "chars": 2436,
    "preview": "{\n    \"id\": \"ch_1JHRCWJSZQVUcJYgOCavbxio\",\n    \"object\": \"charge\",\n    \"livemode\": false,\n    \"created\": 1557995177,\n   "
  },
  {
    "path": "tests/fixtures/dispute_dp_fakefakefakefake01.json",
    "chars": 2563,
    "preview": "{\n    \"id\": \"dp_1JAyTwJSZQVUcJYgPqasUEn1\",\n    \"object\": \"dispute\",\n    \"amount\": 1000,\n    \"balance_transaction\": \"txn_"
  },
  {
    "path": "tests/fixtures/dispute_dp_fakefakefakefake02.json",
    "chars": 2563,
    "preview": "{\n    \"id\": \"dp_1JAyTwJSZQVUcJYgPqasUEn1\",\n    \"object\": \"dispute\",\n    \"amount\": 1000,\n    \"balance_transaction\": \"txn_"
  },
  {
    "path": "tests/fixtures/dispute_dp_funds_reinstated_full.json",
    "chars": 3460,
    "preview": "{\n    \"id\": \"dp_1JAyTwJSZQVUcJYgPqasUEn1\",\n    \"object\": \"dispute\",\n    \"amount\": 1000,\n    \"balance_transaction\": \"txn_"
  },
  {
    "path": "tests/fixtures/dispute_pi_fakefakefakefake01.json",
    "chars": 888,
    "preview": "{\n    \"id\": \"pi_1JAyTwJSZQVUcJYgBbsz0NuH\",\n    \"object\": \"payment_intent\",\n    \"livemode\": false,\n    \"created\": 1557995"
  },
  {
    "path": "tests/fixtures/dispute_pm_fakefakefakefake01.json",
    "chars": 1006,
    "preview": "{\n    \"id\": \"card_fakefakefakefakefake0001\",\n    \"object\": \"payment_method\",\n    \"billing_details\": {\n        \"address\":"
  },
  {
    "path": "tests/fixtures/dispute_txn_fakefakefakefake01.json",
    "chars": 713,
    "preview": "{\n    \"id\": \"txn_1JHRCWJSZQVUcJYgYwW8XpF4\",\n    \"object\": \"balance_transaction\",\n    \"livemode\": null,\n    \"created\": 15"
  },
  {
    "path": "tests/fixtures/event_account_application_authorized.json",
    "chars": 454,
    "preview": "{\n  \"id\": \"evt_1Iu8ZfA3kq9o1aTcf3b7EknK\",\n  \"object\": \"event\",\n  \"account\": \"acct_1Fg9jUA3kq9o1aTc\",\n  \"api_version\": \"2"
  },
  {
    "path": "tests/fixtures/event_account_application_deauthorized.json",
    "chars": 454,
    "preview": "{\n  \"id\": \"evt_1Iu8ZfA3kq9o1aTcf3b7EknK\",\n  \"object\": \"event\",\n  \"account\": \"acct_1Fg9jUA3kq9o1aTc\",\n  \"api_version\": \"2"
  },
  {
    "path": "tests/fixtures/event_account_updated_custom.json",
    "chars": 5977,
    "preview": "{\n    \"id\": \"evt_1Itt6eB9wPxT0ovY3LLhi5bw\",\n    \"object\": \"event\",\n    \"account\": \"acct_1IuHosQveW0ONQsd\",\n    \"api_vers"
  },
  {
    "path": "tests/fixtures/event_account_updated_express.json",
    "chars": 5977,
    "preview": "{\n    \"id\": \"evt_1Itt6eB9wPxT0ovY3LLhi5bw\",\n    \"object\": \"event\",\n    \"account\": \"acct_1IuHosQveW0ONQsd\",\n    \"api_vers"
  },
  {
    "path": "tests/fixtures/event_account_updated_standard.json",
    "chars": 3274,
    "preview": "{\n  \"id\": \"evt_1Itt6eB9wPxT0ovY3LLhi5bw\",\n  \"object\": \"event\",\n  \"account\": \"acct_1Fg9jUA3kq9o1aTc\",\n  \"api_version\": \"2"
  },
  {
    "path": "tests/fixtures/event_external_account_bank_account_created.json",
    "chars": 1055,
    "preview": "{\n    \"id\": \"evt_1IuKmFQveW0ONQsdEAB1O64Y\",\n    \"object\": \"event\",\n    \"account\": \"acct_1IuHosQveW0ONQsd\",\n    \"api_vers"
  },
  {
    "path": "tests/fixtures/event_external_account_bank_account_deleted.json",
    "chars": 989,
    "preview": "{\n  \"id\": \"evt_1IuKmFQveW0ONQsdEAB1O64Y\",\n  \"object\": \"event\",\n  \"account\": \"acct_1IuHosQveW0ONQsd\",\n  \"api_version\": \"2"
  },
  {
    "path": "tests/fixtures/event_external_account_bank_account_updated.json",
    "chars": 997,
    "preview": "{\n  \"id\": \"evt_1IuKmFQveW0ONQsdEAB1O64Y\",\n  \"object\": \"event\",\n  \"account\": \"acct_1IuHosQveW0ONQsd\",\n  \"api_version\": \"2"
  },
  {
    "path": "tests/fixtures/event_external_account_card_created.json",
    "chars": 1183,
    "preview": "{\n  \"id\": \"evt_1IuIg0QveW0ONQsdDLp7otQC\",\n  \"object\": \"event\",\n  \"account\": \"acct_1IuHosQveW0ONQsd\",\n  \"api_version\": \"2"
  },
  {
    "path": "tests/fixtures/event_external_account_card_deleted.json",
    "chars": 1401,
    "preview": "{\n    \"id\": \"evt_1IuIg0QveW0ONQsdDLp7otQC\",\n    \"object\": \"event\",\n    \"account\": \"acct_1IuHosQveW0ONQsd\",\n    \"api_vers"
  },
  {
    "path": "tests/fixtures/event_external_account_card_updated.json",
    "chars": 1282,
    "preview": "{\n    \"id\": \"evt_1IuIg0QveW0ONQsdDLp7otQC\",\n    \"object\": \"event\",\n    \"account\": \"acct_1IuHosQveW0ONQsd\",\n    \"api_vers"
  },
  {
    "path": "tests/fixtures/invoice_in_fakefakefakefakefake0001.json",
    "chars": 2666,
    "preview": "{\n    \"id\": \"in_fakefakefakefakefake0001\",\n    \"object\": \"invoice\",\n    \"account_country\": \"US\",\n    \"account_name\": \"dj"
  },
  {
    "path": "tests/fixtures/invoice_in_fakefakefakefakefake0004.json",
    "chars": 5578,
    "preview": "{\n    \"id\": \"in_fakefakefakefakefake0004\",\n    \"object\": \"invoice\",\n    \"account_country\": \"US\",\n    \"account_name\": \"dj"
  }
]

// ... and 90 more files (download for full content)

About this extraction

This page contains the full source code of the pydanny/dj-stripe GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 290 files (2.0 MB), approximately 446.5k tokens, and a symbol index with 1597 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!