跳转到主要内容

为django-oscar管理账户

项目描述

“管理账户”是一种可以进行借记和贷记的金钱分配。此包为与电子商务框架Oscar一起使用提供管理账户功能。它也可以独立于Oscar使用。

账户可以用于实现各种有趣的组件,包括

  • 礼品卡

  • 网络账户

  • 忠诚度计划

基本上,任何涉及在一个封闭系统中跟踪资金流动的东西。

此包使用复式记账法,其中每笔交易都记录两次(一次用于来源,一次用于目的地)。这确保了账目总是平衡的,并且对所有交易活动的审计记录完整。

如果你的项目管理金钱,你应该使用这样的库。你的财务人员会感谢你的。

https://travis-ci.org/crgwbr/django-oscar-accounts2.svg?branch=master Coverage Requirements Status https://img.shields.io/pypi/v/django-oscar-accounts2.svg

特性

  • 账户有一个信用额度,默认为零。账户可以设置为没有信用额度,以便在系统中成为“资金来源”。至少必须设置一个没有信用额度的账户,以便资金可以在系统中流动。

  • 账户可以有: - 没有分配用户 - 单一“主要”用户 - 这是最常见的情况 - 分配给一组用户

  • 一个用户可以有多个账户

  • 账户可以有一个开始日期和结束日期,以便在有限的时间内使用

  • 账户可以被限制,使其只能用于支付一系列产品。

  • 账户可以被分类

截图

Dashboard account list Create new account Dashboard transfer list Dashboard account detail

安装

使用pip安装

pip install django-oscar-accounts2

并将oscar_accounts添加到INSTALLED_APPS。运行manage.py migrate oscar_accounts将创建相应的数据库表。要创建一些初始的核心账户和账户类型,使用manage.py oscar_accounts_init。这些账户的名称可以通过设置进行控制(见下文)。

如果与Oscar一起运行,请将一个额外的路径添加到您的TEMPLATE_DIRS

from accounts import TEMPLATE_DIR as ACCOUNTS_TEMPLATE_DIR

TEMPLATE_DIRS = (
    ...
    ACCOUNTS_TEMPLATE_DIR)

这允许通过覆盖块而不是替换整个模板来自定义模板。

为了使账户可通过Oscar仪表板访问,您需要将其追加到您的OSCAR_DASHBOARD_NAVIGATION

from oscar.defaults import *

OSCAR_DASHBOARD_NAVIGATION.append(
    {
        'label': 'Accounts',
        'icon': 'icon-globe',
        'children': [
            {
                'label': 'Accounts',
                'url_name': 'accounts-list',
            },
            {
                'label': 'Transfers',
                'url_name': 'transfers-list',
            },
            {
                'label': 'Deferred income report',
                'url_name': 'report-deferred-income',
            },
            {
                'label': 'Profit/loss report',
                'url_name': 'report-profit-loss',
            },
        ]
    })

此外,您还需要将url模式添加到您的urls.py

from oscar_accounts.dashboard.app import application as accounts_app

# ...

urlpatterns = [
    ...
    url(r'^dashboard/accounts/', include(accounts_app.urls)),
]

您还应该设置一个cronjob,该cronjob调用

./manage.py close_expired_accounts

以关闭任何已过期的账户并将它们的资金转移到“过期”账户。

API

使用管理器创建账户实例

from decimal import Decimal
import datetime

from django.contrib.auth.models import User

from oscar_accounts import models

anonymous_account = models.Account.objects.create()

barry = User.objects.get(username="barry")
user_account = models.Account.objects.create(primary_user=barry)

no_credit_limit_account = models.Account.objects.create(credit_limit=None)
credit_limit_account = models.Account.objects.create(credit_limit=Decimal('1000.00'))

today = datetime.date.today()
next_week = today + datetime.timedelta(days=7)
date_limited_account = models.Account.objects.create(
    start_date=today, end_date=next_week)

使用外观转移资金

from oscar_accounts import facade

staff_member = User.objects.get(username="staff")
trans = facade.transfer(source=no_credit_limit_account,
                        destination=user_account,
                        amount=Decimal('10.00'),
                        user=staff_member)

反向转账

facade.reverse(trans, user=staff_member,
               description="Just an example")

如果提议的转账无效,将引发异常。所有异常都是oscar_accounts.exceptions.AccountException的子类。您的客户端代码应查找此类异常并相应地处理它们。

客户端代码应仅使用oscar_accounts.models.Budget类和来自oscar_accounts.facade的两个函数 - 不需要其他任何内容。

错误处理

请注意,转账操作被封装在其自己的数据库事务中,以确保只有完整的转账被写入。当使用Django的事务中间件时,您需要小心。如果您有一个未处理的异常,则即使没有其他任何操作,账户转账仍将被提交。为了处理这种情况,您需要确保,如果您的支付后代码中出现异常,则回滚任何转账。

这里有一个玩具示例

from oscar_accounts import facade

def submit(self, order_total):
    # Take payment first
    transfer = facade.transfer(self.get_user_account(),
                               self.get_merchant_account(),
                               order_total)
    # Create order models
    try:
        self.place_order()
    except Exception, e:
        # Something went wrong placing the order.  Roll-back the previous
        # transfer
        facade.reverse(transfer)

在这种情况下,您将创建两个转账,但没有订单。虽然这不是理想的情况,但这是处理订单创建期间发生的异常的最佳方式。

多转账支付

项目通常允许用户拥有多个账户,并使用多个账户支付订单。这将涉及多个转账,并在您的应用程序代码中需要一些谨慎的处理。

通常在账户API周围编写自己的包装器来封装您的业务逻辑和错误处理是有意义的。以下是一个示例

from decimal import Decimal as D
from oscar_accounts import models, exceptions, facade


def redeem(order_number, user, amount):
    # Get user's non-empty accounts ordered with the first to expire first
    accounts = models.Account.active.filter(
        user=user, balance__gt=0).order_by('end_date')

    # Build up a list of potential transfers that cover the requested amount
    transfers = []
    amount_to_allocate = amount
    for account in accounts:
        to_transfer = min(account.balance, amount_to_allocate)
        transfers.append((account, to_transfer))
        amount_to_allocate -= to_transfer
        if amount_to_allocate == D('0.00'):
            break
    if amount_to_allocate > D('0.00'):
        raise exceptions.InsufficientFunds()

    # Execute transfers to some 'Sales' account
    destination = models.Account.objects.get(name="Sales")
    completed_transfers = []
    try:
        for account, amount in transfers:
            transfer = facade.transfer(
                account, destination, amount, user=user,
                description="Order %s" % order_number)
            completed_transfers.append(transfer)
    except exceptions.AccountException, transfer_exc:
        # Something went wrong with one of the transfers (possibly a race condition).
        # We try and roll back all completed ones to get us back to a clean state.
        try:
            for transfer in completed_transfers:
                facade.reverse(transfer)
        except Exception, reverse_exc:
            # Uh oh: No man's land.  We could be left with a partial
            # redemption. This will require an admin to intervene.  Make
            # sure your logger mails admins on error.
            logger.error("Order %s, transfers failed (%s) and reverse failed (%s)",
                         order_number, transfer_exc, reverse_exc)
            logger.exception(reverse_exc)

        # Raise an exception so that your client code can inform the user appropriately.
        raise RedemptionFailed()
    else:
        # All transfers completed ok
        return completed_transfers

如您所见,对于无法执行的所有转账的情况有一些谨慎的处理。

如果您使用Oscar,请确保为每个转账创建一个OrderSource实例(而不是将它们全部聚合到一个实例中)。这将提供更好的审计信息。以下是一些示例代码

try:
    transfers = api.redeem(order_number, user, total_incl_tax)
except Exception:
    # Inform user of failed payment
else:
    for transfer in transfers:
        source_type, __ = SourceType.objects.get_or_create(name="Accounts")
        source = Source(
            source_type=source_type,
            amount_allocated=transfer.amount,
            amount_debited=transfer.amount,
            reference=transfer.reference)
        self.add_payment_source(source)

核心账户和账户类型

一个post-syncdb信号将为账户类型和账户创建公共结构。一些名称可以通过设置进行控制,如括号中所示。

  • 资产

    • 销售

      • 赎回(ACCOUNTS_REDEMPTIONS_NAME) - 当账户被用于支付某物时,资金被转移到此处。

      • 过期(ACCOUNTS_LAPSED_NAME) - 当账户过期时,资金被转移到此处。这是通过“close_expired_accounts”管理命令完成的。此账户的名称可以使用ACCOUNTS_LAPSED_NAME设置。

    • 现金

      • “银行”(ACCOUNTS_BANK_NAME) - 顾客支付的创建新账户的源账户(例如礼品卡)。此账户将没有信用额度,并且通常具有负余额,因为资金只被转出。

    • 未付款 - 这包括用作其他账户来源但未由客户支付的账户。例如,您可能允许管理员在仪表板中创建新账户。此类账户将是初始转账的来源账户。

  • 负债

    • 递延收入 - 这包括客户账户/礼品卡。您可能想在此类型中创建额外的账户类型以分类账户。

示例交易

考虑以下账户和账户类型

  • 资产
    • 销售
      • 兑换

      • 过期

    • 现金
      • 银行

    • 未付款
      • 商户资助

  • 负债
    • 递延收入

注意,所有账户的初始余额都是0,所有余额的总和始终为零。

一位客户购买了一张50英镑的礼品卡

  • 创建了一个类型为“递延收入”的新账户,结束日期为-50英镑从银行转账到这个新账户

一位客户使用他们的50英镑礼品卡支付了30英镑的订单

  • 30英镑从礼品卡账户转账到兑换账户

客户的礼品卡过期,仍有20英镑未使用

  • 20英镑从礼品卡账户转账到过期账户

客户打电话投诉,一位员工为20英镑创建了一张新的礼品卡

  • 创建了一个类型为“递延收入”的新账户 - 20英镑从“商户资助”账户转账到这个新账户

设置

有设置可以控制命名以及初始未付款和递延收入账户类型

  • ACCOUNTS_MIN_INITIAL_VALUE 可以用来创建账户(或为充值)的最小值

  • ACCOUNTS_MAX_INITIAL_VALUE 可以转账到账户的最大值。

贡献

分叉存储库,设置虚拟环境并运行

make install

使用以下内容运行测试

./runtests.py

项目详情


下载文件

下载您平台的文件。如果您不确定选择哪个,了解更多关于 安装包 的信息。

源分布

django-oscar-accounts2-0.1.0.tar.gz (810.8 kB 查看散列)

上传时间

构建分布

django_oscar_accounts2-0.1.0-py2.py3-none-any.whl (54.9 kB 查看散列)

上传时间 Python 2 Python 3

支持者

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面