ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Django Oscar 附加费(Surcharge)配置实战指南:从 SurchargeApplicator 到订单总额的完整链路

Django Oscar 附加费(Surcharge)配置实战指南:从 SurchargeApplicator 到订单总额的完整链路 后端电商【免费下载链接】django-oscarDomain-driven e-commerce for Django项目地址https://gitcode.com/gh_mirrors/dj/django-oscar点击查看免费下载本文是一篇围绕 Django Oscar 结账模块中附加费surcharge又称 checkout fee的实战配置指南。它面向希望在自己的 Oscar 项目里引入信用卡/借记卡手续费、平台服务费等额外收费的开发人员完整覆盖从重写核心 checkout 应用、自定义SurchargeApplicator到实现name/code元数据与calculate计价接口、复用内置PercentageCharge与FlatCharge直至最终写入订单模型的完整链路。读完本文你将掌握 Oscar 附加费的整套扩展模式并能直接在仓库源码中找到每一步的对应实现。什么是附加费Surcharge附加费surcharge也叫结账手续费checkout fee是商户在收到以支票、信用卡、签账卡或借记卡而非现金支付时向顾客额外收取的一笔费用。它至少应当覆盖商户接受该支付方式所产生的成本例如信用卡公司向商户收取的服务费merchant service fee。在 Django Oscar 中附加费是一个独立于商品价格、运费、优惠折扣之外的计费维度它由结账流程单独计算会被累加到订单总额中并且在下单后以Surcharge记录的形式持久化到订单模型里供订单详情页与后台管理界面展示。Oscar 中的附加费架构核心思路重写 checkout 应用并接管SurchargeApplicator配置附加费要求覆盖fork/overrideOscar 核心的checkout应用并在其中提供你自己的SurchargeApplicator类。这是 Oscar 一贯的定制方式具体做法参见仓库内的定制主题文档与如何定制模型。SurchargeApplicator的首要职责是为特定场景提供可用的附加费方案。这一职责通过get_applicable_surcharges方法完成该方法返回顾客可用的附加费列表。从源码看SurchargeApplicator位于 src/oscar/apps/checkout/applicator.py其完整工作流如下get_surcharges(basket, **kwargs)返回附加费对象元组默认返回空元组()等待子类覆盖is_applicable(surcharge, basket, **kwargs)逐一判断每个附加费在当前场景下是否适用默认恒为Trueget_applicable_surcharges(basket, **kwargs)将两者组合——先调用get_surcharges拿到候选集合再过滤出is_applicable为真的项对每一项执行surcharge.calculate(basket..., **kwargs)得到SurchargePrice(surcharge, price)最终组装成SurchargeList返回若没有可用的附加费则返回None。# src/oscar/apps/checkout/applicator.py def get_applicable_surcharges(self, basket, **kwargs): methods [ SurchargePrice(surcharge, surcharge.calculate(basketbasket, **kwargs)) for surcharge in self.get_surcharges(basketbasket, **kwargs) if self.is_applicable(surchargesurcharge, basketbasket, **kwargs) ] if methods: return SurchargeList(methods) else: return None其中SurchargeList是list的子类提供total属性来汇总所有附加费的价格sum(surcharge.price for surcharge in self)而SurchargePrice则把附加费对象与计算出的价格捆绑在一起。get_applicable_surcharges在哪里被调用该方法在仓库中有两处典型的调用场景与文档描述完全对应购物篮摘要页basket detail page在 src/oscar/apps/basket/views.py 中BasketView调用SurchargeApplicator(self.request, context).get_applicable_surcharges(self.request.basket, shipping_chargeshipping_charge)把结果放进模板上下文surcharges这样默认附加费就能作为示例展示在购物篮页面同时用OrderTotalCalculator().calculate(...)算出含附加费的订单总额。结账会话与提交checkout session在 src/oscar/apps/checkout/session.py 中CheckoutSessionMixin.get_submission在确定运费后调用SurchargeApplicator(self.request, submission).get_applicable_surcharges(self.request.basket, shipping_chargeshipping_charge)将结果放入submission[surcharges]随后get_order_totals把它交给订单总额计算器以得到正确的价格明细。关键调用链附加费如何进入订单总额OrderTotalCalculator是附加费汇入订单总额的枢纽实现在 src/oscar/apps/checkout/calculators.pydef calculate(self, basket, shipping_charge, surchargesNone, **kwargs): excl_tax basket.total_excl_tax shipping_charge.excl_tax if basket.is_tax_known and shipping_charge.is_tax_known: incl_tax basket.total_incl_tax shipping_charge.incl_tax else: incl_tax None if surcharges is not None: excl_tax surcharges.total.excl_tax if incl_tax is not None: incl_tax surcharges.total.incl_tax return prices.Price( currencybasket.currency, excl_taxexcl_tax, incl_taxincl_tax )可以看到surcharges.total的含税/不含税金额被直接累加到购物篮总额 运费之上。这也解释了为什么get_applicable_surcharges的调用总是伴随shipping_charge参数——因为百分比附加费的计算需要用到运费见下文PercentageCharge。下单时OrderCreatorsrc/oscar/apps/order/utils.py会把SurchargeList中的每一项持久化为Surcharge模型记录if surcharges is not None: for charge in surcharges: Surcharge.objects.create( orderorder, namecharge.surcharge.name, codecharge.surcharge.code, excl_taxcharge.price.excl_tax, incl_taxcharge.price.incl_tax, tax_codecharge.price.tax_code, )Surcharge模型定义在 src/oscar/apps/order/abstract_models.py包含order外键、name、code、incl_tax、excl_tax、tax_code等字段订单模型还提供了surcharge_incl_tax/surcharge_excl_tax属性来汇总附加费总额同文件第 262-268 行并注册了对应的后台管理类src/oscar/apps/order/admin.py。自定义 SurchargeApplicator场景一所有顾客、所有支付方式都相同——覆盖get_surcharges如果可用的附加费对所有顾客和所有支付方式都一样只需覆盖get_surcharges方法返回附加费元组即可示例中返回一个PercentageCharge2% 的百分比附加费from decimal import Decimal as D from oscar.apps.checkout import applicator from . import surcharges class SurchargeApplicator(applicator.SurchargeApplicator): def get_surcharges(self, basket, **kwargs): return ( surcharges.PercentageCharge(percentageD(2.00)), )注意get_surcharges的签名是(self, basket, **kwargs)其中**kwargs会原样传递——实际调用时通常会携带shipping_charge运费必要时还有结账上下文因此你的返回值可以依赖这些 kwargs 做进一步定制。场景二复杂逻辑——覆盖is_applicable当附加费是否适用取决于支付方式、用户分组、订单金额等条件时应覆盖is_applicable方法。下面的示例让附加费只对 PayPal 支付方式生效from oscar.apps.checkout import applicator class SurchargeApplicator(applicator.SurchargeApplicator): def is_applicable(self, surcharge, basket, **kwargs): payment_method_code kwargs.get(payment_method_code, None) if payment_method_code is not None and payment_method_code paypal: return True else: return False这里的payment_method_code通过**kwargs传入。结账提交时CheckoutSessionMixin会把表单收集到的支付方式等额外数据放进 kwargs参考 src/oscar/apps/checkout/session.py因此你可以在此读取它们做条件判断。文档同时提示get_applicable_surcharges接收购物篮和其他 kwargs这些 kwargs 可以在你搭建自己的附加费时按需确定——例如把支付方式代码、优惠券、用户对象等传进来实现按场景定价。实现你自己的附加费类附加费必须实现的 API任何附加费都需要实现一个确定的最小接口包含两部分name附加费的名称结账期间对顾客可见且可翻译应使用gettext_lazy等翻译机制code附加费的代码可以是 slug 化的名称或其他任意字符串作为不可翻译的收费标识符用于持久化与对账calculate方法接收basket实例作为参数返回一个Price实例来自oscar.core.prices。大多数附加费都继承BaseSurchargesrc/oscar/apps/checkout/surcharges.py该类负责把上述接口stub出来class BaseSurcharge: Surcharge interface class ... The interface is all properties. def calculate(self, basket, **kwargs): raise NotImplementedError也就是说子类只需实现calculate并定义name/code属性即可。文档还特别指出你也可以像实现运费方法shipping methods那样把附加费实现为 Django 模型从而获得数据库持久化、后台管理、可编辑配置等能力。calculate的调用方式与返回类型回顾get_applicable_surcharges的实现每个附加费的calculate是以surcharge.calculate(basketbasket, **kwargs)的方式被调用的kwargs 与get_surcharges/is_applicable收到的完全一致。返回值是oscar.core.prices.Price实例带currency、excl_tax、incl_tax、tax_code等字段它随后被包进SurchargePrice再通过SurchargeList.total参与订单总额汇总最终由 src/oscar/apps/order/utils.py 将name/code/excl_tax/incl_tax/tax_code写入Surcharge记录。Oscar 内置的附加费类Oscar 自带若干可直接使用、也可继承定制的附加费类均位于 src/oscar/apps/checkout/surcharges.pyPercentageCharge—— 按比例计费name _(Percentage surcharge)code percentage-surcharge构造参数percentage百分比数值如D(2.00)表示 2%calculate逻辑若购物篮非空则取kwargs中的shipping_charge若有累加到购物篮总额上作为计费基数excl_tax与incl_tax分别按基数 × percentage / 100计算购物篮为空时返回 0。class PercentageCharge(BaseSurcharge): def __init__(self, percentage): self.percentage percentage def calculate(self, basket, **kwargs): if not basket.is_empty: shipping_charge kwargs.get(shipping_charge) if shipping_charge is not None: total_excl_tax basket.total_excl_tax shipping_charge.excl_tax total_incl_tax basket.total_incl_tax shipping_charge.incl_tax else: total_excl_tax basket.total_excl_tax total_incl_tax basket.total_incl_tax return prices.Price( currencybasket.currency, excl_taxtotal_excl_tax * self.percentage / 100, incl_taxtotal_incl_tax * self.percentage / 100, ) else: return prices.Price( currencybasket.currency, excl_taxD(0.0), incl_taxD(0.0) )要点基数包含运费只要调用时传入shipping_charge这是与结账调用链中始终携带shipping_charge的设计相呼应的。FlatCharge—— 固定金额附加费name _(Flat surcharge)code flat-surcharge构造参数excl_tax、incl_tax两个可选关键字参数calculate直接原样返回这两个金额构成的Price不做任何比例运算class FlatCharge(BaseSurcharge): def __init__(self, excl_taxNone, incl_taxNone): self.excl_tax excl_tax self.incl_tax incl_tax def calculate(self, basket, **kwargs): return prices.Price( currencybasket.currency, excl_taxself.excl_tax, incl_taxself.incl_tax )使用示例from decimal import Decimal as D from oscar.apps.checkout import surcharges percentage_charge surcharges.PercentageCharge(percentageD(2.00)) flat_charge surcharges.FlatCharge(excl_taxD(10.00), incl_taxD(12.10))模板与后台附加费的展示与持久化附加费计算完成后会在两处面向用户/运营人员呈现购物篮摘要页src/oscar/templates/oscar/basket/partials/basket_totals.html 中{% block surcharges %}遍历surchargesSurchargeList显示surcharge.surcharge.name与价格含税/不含税视show_tax_separately而定并可通过basket.currency货币过滤器格式化。订单后台详情src/oscar/templates/oscar/dashboard/orders/order_detail.html 遍历order.surcharges.all展示每一条已持久化的附加费记录对应的管理后台已由 src/oscar/apps/order/admin.py 注册SurchargeAdmin支持按订单号搜索。测试与验证看官方测试如何锁定行为仓库的集成测试为附加费行为提供了精确的可验证依据测试位于 tests/integration/checkout/test_surcharges.pytest_stock_surcharges对空购物篮应用默认 applicator验证surcharges.total.excl_tax D(20.0)、incl_tax D(22.0)内置 applicator 的默认附加费test_percentage_surchargePercentageCharge(percentageD(10))作用于含 12 元商品的购物篮结果price.incl_tax D(1.20)验证商品总额 × 百分比test_percentage_empty_basket空购物篮时百分比附加费为 0test_flat_surchargeFlatCharge(excl_taxD(1), incl_taxD(1.21))原样返回金额test_percentage_with_shipping_charge购物篮 10 元、运费含税 5 元、4% 附加费结果为price.incl_tax D(0.6)即 (105) × 4%实证了百分比附加费的计算基数是购物篮 运费。此外tests/integration/checkout/test_calculator.py 与 tests/integration/checkout/test_mixins.py 也覆盖了applicator 产出附加费 →OrderTotalCalculator.calculate汇总 → 下单时写入Surcharge模型的完整路径可作为你自定义附加费时的对照测试模板。配置完整流程小结Fork checkout 应用在项目中创建自定义的checkout应用方式见 定制主题文档并保证 Oscar 通过get_class(checkout.applicator, SurchargeApplicator)见 src/oscar/apps/checkout/session.py加载到你的类编写附加费类继承BaseSurcharge定义name、code实现calculate(basket, **kwargs)返回Price或直接复用/继承内置的PercentageCharge、FlatCharge编写 applicator覆盖get_surcharges固定集合或is_applicable条件判断必要时把payment_method_code等场景信息经 kwargs 传入验证参照 tests/integration/checkout/test_surcharges.py 编写测试确认购物篮页展示、订单总额汇总与Surcharge持久化三处行为符合预期。这样你的 Oscar 店铺就能在结账环节稳定地收取信用卡手续费等附加费用并在购物篮摘要、订单详情和后台管理三处保持一致、可审计的呈现。赞分享后端电商【免费下载链接】django-oscarDomain-driven e-commerce for Django项目地址https://gitcode.com/gh_mirrors/dj/django-oscar点击查看免费下载相关推荐Django-Oscar订单处理系统配置指南Django Oscar订单处理系统配置指南 概述 在电子商务系统中订单处理是核心业务流程之一。Django Oscar作为一个成熟的电商框架提供了灵活的订后端电商MediaPipe Face Mesh 终极指南如何在移动端实现实时3D面部捕捉MediaPipe Face Mesh 终极指南如何在移动端实现实时3D面部捕捉 想要在普通手机摄像头上实现专业级的面部识别和AR特效吗MediaPipe人工智能机器学习计算机视觉多模态本地部署Django Oscar 运费配置实战指南从自定义 Repository 到重量阶梯计费Django Oscar 运费配置实战指南从自定义 Repository 到重量阶梯计费 本文以 Django Oscar 官方配方文档 how_to_con后端电商上一篇WHC_AutoLayoutKit社区生态如何贡献代码与参与开源项目的完整指南下一篇AI像素画提速10倍Piskel Stable Diffusion插件零基础教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表