本文内容由@淘 老师开发及开源,请移步http://www.heyuantao.cn看全部内容。

以下内容为转载

关于OpenEdx的Ecommerce的配置

OpenEdx项目中的ecommerce和edx-platform是两个独立的组件,两个组建部署后通过Web API接口相互调用和访问数据。ecommerce的目的是为了取代edx-platform中自带的购物车,这样使得课程购买和课程播放管理相互独立,程序更容易维护。

OpenEdx的官网有如何安装ecommerce组件的介绍,单这个仅仅适用于开发版本。在安装OpenEdx的时候ecommerce一般会直接安装上,但仍需要配置。所涉及到的配置文件有edx-platform的lms.env.json、lms.auth.json和ecommerce的ecommerce.yml(/edx/etc/ecommerce.yml)文件的配置。主体过就是配置两个组件的oauth2功能。

最近在网上找到一篇博客,详细记录了设置的过程:相关博文1

(原文附在最后)


#  Ecommerce的汉化

<div>
    shell: “{{ ecommerce_venv_dir }}/bin/python manage.py {{ item }}”
</div>

<div>
    args:
</div>

<div>
      chdir: “{{ ecommerce_code_dir }}”
</div>

<div>
    become_user: “{{ ecommerce_user }}”
</div>

<div>
    environment: “{{ ecommerce_environment }}”
</div>

<div>
    with_items:
</div>

<div>
      – “update_assets –skip-collect”             #可能时执行翻译的关键代码
</div>

<div>
    when: not devstack
</div>

<div>
    tags:
</div>

<div>
      – assets
</div>

<div>
      – assets:gather
</div>

<div>
</div>

<div>
  – name: Run r.js optimizer
</div>

<div>
    shell: “. {{ ecommerce_nodeenv_bin }}/activate && {{ ecommerce_node_bin }}/r.js -o build.js”
</div>

<div>
    args:
</div>

<div>
      chdir: “{{ ecommerce_code_dir }}”
</div>

<div>
    become_user: “{{ ecommerce_user }}”
</div>

<div>
    when: not devstack
</div>

<div>
    tags:
</div>

<div>
      – assets
</div>

<div>
      – assets:gather
</div>

<div>
</div>

<div>
  – name: Run collectstatic
</div>

<div>
    shell: “{{ ecommerce_venv_dir }}/bin/python manage.py {{ item }}”
</div>

<div>
    args:
</div>

<div>
      chdir: “{{ ecommerce_code_dir }}”
</div>

<div>
    become_user: “{{ ecommerce_user }}”
</div>

<div>
    environment: “{{ ecommerce_environment }}”
</div>

<div>
    with_items:
</div>

<div>
      – “collectstatic –noinput”
</div>

<div>
      – “compress”
</div>

<div>
    when: not devstack
</div>

<div>
    tags:
</div>

<div>
      – assets
</div>

<div>
      – assets:gather
</div>
<div>
  ….
</div>

<div>
  LANGUAGE_CODE: zh_CN                                  #这个起到了比较核心的作用,将值从en修改为zh_CN即可
</div>

<div>
  LANGUAGE_COOKIE_NAME: openedx-language-preference     #这个是一个cookie,可以根据这个变量的值来显示相应的语言
</div>

<div>
</div>

<div>
  #将时区一并进行修改
</div>

<div>
  TIME_ZONE:Asia/Shanghai      #原始值为UTC
</div>
<div>
  …
</div>

<div>
  LANGUAGES = (
</div>

<div>
      (‘zh_CN’, _(‘Chinese’)),                              #原本没有这一行,加上这一行,并将其他行屏蔽掉
</div>

<div>
  #    (‘en’, _(‘English’)),
</div>

<div>
  #    (‘es’, _(‘Spanish’)),
</div>

<div>
  #    (‘es-419’, _(‘Spanish (Latin American)’)),
</div>

<div>
  )
</div>
<div>
  /edx/app/ecommerce/ecommerce/ecommerce/settings/production.py
</div>

<div>
  /edx/app/ecommerce/ecommerce/ecommerce/settings/base.py
</div>
<div>
  source ecommerce_env
</div>

<div>
  #下面这条命令将执行语言文件的编译
</div>

<div>
  python manage.py compilemessages –settings=ecommerce.settings.production
</div>
<div>
          context.update({
</div>

<div>
              ‘payment_method’: _(self.get_payment_method(order)),     #进行翻译的部分
</div>

<div>
              ‘display_credit_messaging’: self.order_contains_credit_seat(order),
</div>

<div>
          })
</div>

<div>
  #self.get_payment_method(order)实际返回的的时支付处理模块的字段,实际内容为’alipay’。加上_( )这个函数用来完成实际的翻译
</div>
<div>
                <dt>{% trans “Order Date:” %}</dt>
</div>

<div>
                <dd>{{ order.date_placed|date:”E d, Y” }}</dd>                    #将其改为data:”Y-m-d”,关于Y、E等字符的定义可查看django文档
</div>

<div>
              </dl>
</div>

<div>
</div>

<div>
  #修改为这种方式就会显示为2018-01-02的方式,更容易阅读
</div>
<div>
      1、通过JS和Python脚本生成支付链接,并跳转到PayPal网站。
</div>

<div>
      2、通过Python脚本和PayPal的SDK完成用户支付完成后的转跳和交易的处理。
</div>

<div>
</div>

<div>
      为了便于代码的跟踪和调试,将ecommerce和lms支付过程中的页面转跳和操作逻辑进行记录,以便于后期扩展支付功能。为了使得该记录在后续浏览时具有通用性和易读性,将lms的站点链接统一记录为”<a href="http://lms/">http://lms/</a>“,将ecommerce的站点记录为”<a href="http://ecommerce/">http://ecommerce/</a>“。
</div>

<div>
  二、显示购买按钮的核心代码(第一步)
</div>

<div>
</div>

<div>
         在LMS模块中,通过注册课程系统转跳到Ecommerce模块,此时的URL为“<a href="http://ecommerce/basket/">http://ecommerce/basket/</a>”,这个URL对应的视图函数为:
</div>

<div>
</div>

<div>
  <div>
    #ecommerce/extensions/basket/views.py
  </div>
  
  <div>
    class BasketSummaryView(BasketView):
  </div>
  
  <div>
        def get(self, request, *args, **kwargs):
  </div>
  
  <div>
            basket = request.basket
  </div>
  
  <div>
            ….
  </div>
  
  <div>
        def get_context_data(self, **kwargs):       #这是一个很重要的函数,用于在模板中加入其它变量
  </div>
  
  <div>
           context = super(BasketSummaryView, self).get_context_data(**kwargs)
  </div>
  
  <div>
           formset = context.get(‘formset’, [])
  </div>
  
  <div>
           lines = context.get(‘line_list’, [])
  </div>
  
  <div>
           ….
  </div>
  
  <div>
           payment_processors = site_configuration.get_payment_processors()  #用于获取所支持的支付平台。
  </div>
  
  <div>
           …..
  </div>
</div>

<div>
</div>

<div>
        上述这个视图引入了另外一个模块的函数,同时get_context_data是一个很重要的函数,这个函数在模板中加入了更多的变量。这个视图函数的父类为BasketView,这个类在django-oscar中有定义,参考如下代码:
</div>

<div>
</div>

<div>
  <div>
    #src/oscar/apps/basket/views.py
  </div>
  
  <div>
    class BasketView(ModelFormSetView):
  </div>
  
  <div>
        model = get_model(‘basket’, ‘Line’)
  </div>
  
  <div>
        basket_model = get_model(‘basket’, ‘Basket’)
  </div>
  
  <div>
        …..
  </div>
  
  <div>
        template_name = ‘basket/basket.html’  #此处为该视图的模板,这个模板在django-oscar中有定义,但被ecommerce中的模板给覆盖了
  </div>
</div>

<div>
</div>

<div>
         该视图实际使用的模板为ecommerce/templates/oscar/basket/basket.html  (这一步为猜测),这个模板为框架,引入了同级目录中partials目录中的多模板文件,其中涉及到支付方式的文件为“partials/hosted_checkout_basket.html”。该文件中与支付按钮相关的内容如下:
</div>

<div>
</div>

<div>
  <div>
    #ecommerce/templates/oscar/basket/partials/hosted_checkout_basket.html
  </div>
  
  <div>
                <div class=”pull-right payment-buttons” data-basket-id=”{{ basket.id }}”>
  </div>
  
  <div>
                    {% if free_basket %}       #如果该次支付不需要付费(使用了优惠券并且100%折扣)
  </div>
  
  <div>
                        <a href=”{% url ‘checkout:free-checkout’ %}”
  </div>
  
  <div>
                           data-track-type=”click”
  </div>
  
  <div>
                           data-track-event=”edx.bi.ecommerce.basket.free_checkout”
  </div>
  
  <div>
                           data-track-category=”checkout”
  </div>
  
  <div>
                           class=”btn btn-success checkout-button”>
  </div>
  
  <div>
                            {% trans “Place Order” %}
  </div>
  
  <div>
                        </a>
  </div>
  
  <div>
                    {% else %}                #如果本次支付需要付费,则显示所有的付费按钮,paypal,cybersource等。
  </div>
  
  <div>
                        {% for processor in payment_processors %}            #payment_processors为付费的平台名称
  </div>
  
  <div>
                            <button data-track-type=”click”
  </div>
  
  <div>
                                    data-track-event=”edx.bi.ecommerce.basket.payment_selected”
  </div>
  
  <div>
                                    data-track-category=”checkout”
  </div>
  
  <div>
                                    data-processor-name=”{{ processor.NAME|lower }}”
  </div>
  
  <div>
                                    data-track-checkout-type=”hosted”
  </div>
  
  <div>
                                    class=”btn payment-button”
  </div>
  
  <div>
                                    id=”{{ processor.NAME|lower }}”>
  </div>
  
  <div>
                                {% if processor.NAME == ‘cybersource’ %}
  </div>
  
  <div>
                                    {% trans “Checkout” %}
  </div>
  
  <div>
                                {% elif processor.NAME == ‘paypal’ %}
  </div>
  
  <div>
                                    {# Translators: Do NOT translate the name PayPal. #}
  </div>
  
  <div>
                                    {% trans “Checkout with PayPal” %}
  </div>
  
  <div>
                                                        {% elif processor.NAME == ‘alipay’ %}                #新加的代码,配合后续的代码修改才能在支付页面上显示支付宝
  </div>
  
  <div>
                                                               {% trans “Checkout with Alipay” %}
  </div>
  
  <div>
                                {% endif %}
  </div>
  
  <div>
                            </button>
  </div>
  
  <div>
                        {% endfor %}
  </div>
  
  <div>
                    {% endif %}
  </div>
  
  <div>
                </div>
  </div>
</div>

<div>
</div>

<div>
         从上述模板文件中可以看出,“payment_processors”是一个可枚举类型的数据,其包含了所对接的支付平台,而这个变量的内容来自于BasketSummaryView类中的get_context_data函数,在这个函数内将payment_processor进行了赋值。
</div>

<div>
</div>

<div>
  <div>
    #ecommerce/core/models.py
  </div>
  
  <div>
    class SiteConfiguration(models.Model):
  </div>
  
  <div>
        def get_payment_processors(self):
  </div>
  
  <div>
            all_processors = self._all_payment_processors()
  </div>
  
  <div>
            all_processor_names = {processor.NAME for processor in all_processors}
  </div>
  
  <div>
  </div>
  
  <div>
            missing_processor_configurations = self.payment_processors_set – all_processor_names
  </div>
  
  <div>
            if missing_processor_configurations:
  </div>
  
  <div>
                processor_config_repr = “, “.join(missing_processor_configurations)
  </div>
  
  <div>
                log.warning(
  </div>
  
  <div>
                    ‘Unknown payment processors [%s] are configured for site %s’, processor_config_repr, self.site.id
  </div>
  
  <div>
                )
  </div>
  
  <div>
  </div>
  
  <div>
            return [
  </div>
  
  <div>
                processor for processor in all_processors
  </div>
  
  <div>
                if processor.NAME in self.payment_processors_set and processor.is_enabled()   #确保is_enable的返回值
  </div>
  
  <div>
            ]
  </div>
  
  <div>
  </div>
  
  <div>
        def _all_payment_processors(self):
  </div>
  
  <div>
            “”” Returns all processor classes declared in settings. “””
  </div>
  
  <div>
            all_processors = [get_processor_class(path) for path in settings.PAYMENT_PROCESSORS]
  </div>
  
  <div>
            return all_processors
  </div>
</div>

<div>
</div>

<div>
        对上述代码进行分析payment_processors_set变量来源于类的payment_processors,而payment_processors类型为CharField,该数值存放在数据库中,形式为’cybersource,paypal’(以逗号分开)。另外一个变量”all_processors”来源于ecommerce的配置文件,配置部分为settings.PAYMENT_PROCESSORS。因此要让页面显示出某个支付模板,要同时在这两个地方进行修改。分别为:
</div>

<div>
</div>

<div>
  <div>
    #/edx/etc/ecommerce.yml
  </div>
  
  <div>
    PAYMENT_PROCESSOR_CONFIG:
  </div>
  
  <div>
        edx:
  </div>
  
  <div>
            paypal:
  </div>
  
  <div>
                cancel_url: http://127.0.0.1:8000/commerce/checkout/cancel/
  </div>
  
  <div>
                client_id: AYskdUzpJGCDSJx8xPhFJq4We0FPINEjOTToNH0klY1BdDKj5B-k9CkEfvgUrBknbFxKriYc0DYjsqOJ
  </div>
  
  <div>
                client_secret: EBDM5GgT2RVC8MNacNWFluqj3sx4PdL37qj-A86gypVKQEFDltVkuhTLGfiXHlc5gKn4pnwTcKyWp5sJ
  </div>
  
  <div>
                error_url: http://127.0.0.1:8000/commerce/checkout/error/
  </div>
  
  <div>
                mode: sandbox
  </div>
  
  <div>
                receipt_url: http://127.0.0.1:8000/commerce/checkout/receipt/
  </div>
  
  <div>
       alipay:
  </div>
  
  <div>
                app_id: 2016081900287513
  </div>
  
  <div>
                app_private_key_path: /edx/app/ecommerce/cert/app_private_key.pem
  </div>
  
  <div>
                alipay_public_key_path: /edx/app/ecommerce/cert/alipay_public_key.pem
  </div>
  
  <div>
                mode: sandbox
  </div>
  
  <div>
                app_notify_url: <a href="http://ecommercetest.hudieshanfood.com/checkout/alipay/">http://ecommerce/checkout/alipay/</a>
  </div>
  
  <div>
                cancel_url: <a href="http://127.0.0.1:8000/commerce/checkout/cancel/">http://127.0.0.1:8000/commerce/checkout/cancel/</a>
  </div>
  
  <div>
                error_url: <a href="http://127.0.0.1:8000/commerce/checkout/error/">http://127.0.0.1:8000/commerce/checkout/error/</a>
  </div>
  
  <div>
                receipt_url: <a href="http://127.0.0.1:8000/commerce/checkout/receipt/">http://127.0.0.1:8000/commerce/checkout/receipt/</a>
  </div>
</div>

<div>
</div>

<div>
</div>

<div>
  <div>
    进入admin管理界面,并修改默认的站点配置。修改Payment processors(付款处理器)字段,加入alipay(以逗号分隔)
  </div>
  
  <div>
    <a href="http://ecommerce/admin/core/siteconfiguration/">http://ecommerce/admin/core/siteconfiguration/</a>
  </div>
</div>

<div>
</div>

<div>
  <div>
    #ecommerce/settings/_oscar.py
  </div>
  
  <div>
    PAYMENT_PROCESSORS = (
  </div>
  
  <div>
        ‘ecommerce.extensions.payment.processors.cybersource.Cybersource’,
  </div>
  
  <div>
        ‘ecommerce.extensions.payment.processors.paypal.Paypal’,
  </div>
  
  <div>
        ‘ecommerce.extensions.payment.processors.alipay.Alipay’, #加入这行,同时加入程序文件
  </div>
  
  <div>
    )
  </div>
  
  <div>
    ..
  </div>
  
  <div>
    PAYMENT_PROCESSOR_CONFIG = {
  </div>
  
  <div>
        ‘edx’: {
  </div>
  
  <div>
            ‘paypal’: {
  </div>
  
  <div>
                # ‘mode’ can be either ‘sandbox’ or ‘live’
  </div>
  
  <div>
                ‘mode’: None,
  </div>
  
  <div>
                ‘client_id’: None,
  </div>
  
  <div>
                ‘client_secret’: None,
  </div>
  
  <div>
                ‘receipt_path’: PAYMENT_PROCESSOR_RECEIPT_PATH,
  </div>
  
  <div>
                ‘cancel_checkout_path’: PAYMENT_PROCESSOR_CANCEL_PATH,
  </div>
  
  <div>
                ‘error_path’: PAYMENT_PROCESSOR_ERROR_PATH,
  </div>
  
  <div>
            },
  </div>
  
  <div>
            ‘alipay’: {
  </div>
  
  <div>
                # ‘mode’ can be either ‘sandbox’ or ‘live’
  </div>
  
  <div>
                ‘app_id’: None,
  </div>
  
  <div>
                ‘app_private_key_path’: None,
  </div>
  
  <div>
                ‘alipay_public_key_path’: None,
  </div>
  
  <div>
                ‘mode’: None,
  </div>
  
  <div>
                ‘client_id’: None,
  </div>
  
  <div>
                ‘client_secret’: None,
  </div>
  
  <div>
                ‘receipt_path’: PAYMENT_PROCESSOR_RECEIPT_PATH,
  </div>
  
  <div>
                ‘cancel_checkout_path’: PAYMENT_PROCESSOR_CANCEL_PATH,
  </div>
  
  <div>
                ‘error_path’: PAYMENT_PROCESSOR_ERROR_PATH,
  </div>
  
  <div>
            },
  </div>
  
  <div>
  </div>
  
  <div>
        },
  </div>
  
  <div>
  </div>
</div>

<div>
</div>

<div>
        上述修改完成后,加入支付宝模块的代码,目录在”ecommerce/extensions/payment/processors/”中,该目录同时也有paypal和cybersource的支付平台对接的代码,为了减少代码量,直接复制一份,操作如下:
</div>

<div>
</div>

<div>
  #cp paypal.py alipay.py     #拷贝完成后注意文件的权限
</div>

<div>
  将文件内的类Paypal修改为AliPay,同时将NAME变量修改为’alipay’,修改 后的结果如下:
</div>

<div>
</div>

<div>
  <div>
    class Alipay(BasePaymentProcessor):     #后续功能的修改也是在本文件完成的
  </div>
  
  <div>
        NAME = ‘alipay’
  </div>
  
  <div>
        DEFAULT_PROFILE_NAME = ‘default’
  </div>
  
  <div>
        def __init__(self, site):
  </div>
  
  <div>
             ….
  </div>
</div>

<div>
</div>

<div>
</div>

<div>
        修改后依然不显示,根据错误提示,发现processor.is_enabled()的返回值影响了显示,找到相关代码如下:
</div>

<div>
</div>

<div>
  <div>
    #ecommerce/extensions/payment/processors/__init__.py
  </div>
  
  <div>
    class BasePaymentProcessor(object):
  </div>
  
  <div>
        def is_enabled(cls):
  </div>
  
  <div>
            return waffle.switch_is_active(settings.PAYMENT_PROCESSOR_SWITCH_PREFIX + cls.NAME)
  </div>
</div>

<div>
</div>

<div>
        根据代码,是waffle的开关设置问题,这个开关在admin管理面板可以设置。配置方法如下,配置后重启ecommerce即可显示:
</div>

<div>
</div>

<div>
  <div>
    #<a href="http://ginkgoedx.syslab.org:18130/admin/waffle/switch/">http://ecommerce/admin/waffle/switch/</a>
  </div>
  
  <div>
    #支付开关的页面
  </div>
</div>

<div>
</div>

<div>
        添加一个开关,仿照paypal和cybersource的样式,开关名字为payment_processor_active_alipay,同时勾选active状态。如果要禁用其他支付模块,可在此处把开关取消active状态。由于系统默认开启了paypal,而后续又要添加alipay,可以在此时通过开关禁用掉paypay。
</div>

<div>
</div>

<div>
  三、支付时的核心代码(第二步)
</div>

<div>
        当用户点击支付时(Checkout With Alipay),JS代码会向“<a href="http://ginkgoedx.syslab.org:18130/api/v2/checkout/">http://ecommerce/api/v2/checkout/</a>”发送POST数据,内容如下:
</div>

<div>
</div>

<div>
  <div>
    {“basket_id”:19,”payment_processor”:”alipay”}
  </div>
</div>

<div>
</div>

<div>
        这个请求的处理函数为:
</div>

<div>
</div>

<div>
  <div>
    #ecommerce/extensions/api/v2/views/checkout.py
  </div>
  
  <div>
    class CheckoutView(APIView):
  </div>
  
  <div>
        “””
  </div>
  
  <div>
        Freezes a basket, and returns the information necessary to start the payment process.
  </div>
  
  <div>
        “””
  </div>
  
  <div>
        permission_classes = (IsAuthenticated,)
  </div>
  
  <div>
  </div>
  
  <div>
        def post(self, request):
  </div>
  
  <div>
            basket_id = request.data[‘basket_id’]
  </div>
  
  <div>
            payment_processor_name = request.data[‘payment_processor’]
  </div>
  
  <div>
  </div>
  
  <div>
            logger.info(
  </div>
  
  <div>
                ‘Checkout view called for basket [%s].’,
  </div>
  
  <div>
                basket_id
  </div>
  
  <div>
            )
  </div>
  
  <div>
            ……
  </div>
  
  <div>
            parameters = payment_processor.get_transaction_parameters(basket, request=request)      #该处为核心代码
  </div>
  
  <div>
            payment_page_url = parameters.pop(‘payment_page_url’)
  </div>
  
  <div>
  </div>
  
  <div>
            data = {
  </div>
  
  <div>
                ‘payment_form_data’: parameters,
  </div>
  
  <div>
                ‘payment_page_url’: payment_page_url,
  </div>
  
  <div>
                ‘payment_processor’: payment_processor.NAME,
  </div>
  
  <div>
            }
  </div>
  
  <div>
  </div>
  
  <div>
            serializer = CheckoutSerializer(data)
  </div>
  
  <div>
            return Response(serializer.data)
  </div>
</div>

<div>
</div>

<div>
            上述代码的核心代码为 payment_processor.get_transaction_parameters(basket, request=request),而该代码实际为”ecommerce/extensions/payment/processors/alipay.py”中的代码。由于后续的代码修改要用到支付宝的第三方SDK,因此进入ecommerce的virtualenv环境,安装该软件包,过程如下:
</div>

<div>
</div>

<div>
  <div>
    cd /edx/app/ecommerce                 #进入软件目录
  </div>
  
  <div>
    sudo -H -u ecommerce bash             #更改用户
  </div>
  
  <div>
    source venvs/ecommerce/bin/active     #加载python虚拟环境和环境变量
  </div>
  
  <div>
    source ecommerce_env
  </div>
  
  <div>
    pip install python-alipay-sdk                         #安装第三方支付模块
  </div>
</div>

<div>
</div>

<div>
       当前的代码为,该代码即可完成从ecommerce到支付宝平台的跳转
</div>

<div>
</div>

<div>
  <div>
    #ecommerce/ecommerce/extensions/payment/processors/alipay.py
  </div>
  
  <div>
    from __future__ import unicode_literals
  </div>
  
  <div>
    from __future__ import absolute_import  #work wich conflicts alipay sdk name and class name
  </div>
  
  <div>
    ….
  </div>
  
  <div>
    from alipay import AliPay as AliPaySdk
  </div>
  
  <div>
    import json
  </div>
  
  <div>
  </div>
  
  <div>
    logger = logging.getLogger(__name__)
  </div>
  
  <div>
  </div>
  
  <div>
    class Alipay(BasePaymentProcessor):
  </div>
  
  <div>
        NAME = ‘alipay’
  </div>
  
  <div>
        DEFAULT_PROFILE_NAME = ‘default’
  </div>
  
  <div>
        def __init__(self, site):
  </div>
  
  <div>
            super(Alipay, self).__init__(site)
  </div>
  
  <div>
            mode = self.configuration[‘mode’].decode(‘utf-8’)
  </div>
  
  <div>
            if mode ==’sandbox’:
  </div>
  
  <div>
            self.alipay_gateway = ‘<a href="https://openapi.alipaydev.com/gateway.do">https://openapi.alipaydev.com/gateway.do</a>‘
  </div>
  
  <div>
            else:
  </div>
  
  <div>
            self.alipay_gateway = ‘<a href="https://openapi.alipay.com/gateway.do">https://openapi.alipay.com/gateway.do</a>‘
  </div>
  
  <div>
  </div>
  
  <div>
            self.Debug = False if self.configuration[‘mode’] is ‘sandbox’ else True
  </div>
  
  <div>
            self.app_private_key_string = open(self.configuration[‘app_private_key_path’]).read()
  </div>
  
  <div>
            self.alipay_public_key_string = open(self.configuration[‘alipay_public_key_path’]).read()
  </div>
  
  <div>
            self.notify_url = urljoin(get_ecommerce_url(), reverse(‘alipay:notify’))
  </div>
  
  <div>
            self.return_url = urljoin(get_ecommerce_url(), reverse(‘alipay:return’))
  </div>
  
  <div>
            self.alipay = AliPaySdk(appid=self.configuration[‘app_id’] ,app_notify_url = self.notify_url ,app_private_key_string = self.app_private_key_string ,alipay_public_key_string = self.alipay_public_key_string ,sign_type = “RSA2” ,debug = self.Debug )
  </div>
  
  <div>
            # Number of times payment execution is retried after failure.
  </div>
  
  <div>
            #self.retry_attempts = PaypalProcessorConfiguration.get_solo().retry_attempts
  </div>
  
  <div>
  </div>
  
  <div>
  </div>
  
  <div>
        def get_transaction_parameters(self, basket, request=None, use_client_side_checkout=False, **kwargs):
  </div>
  
  <div>
            “””
  </div>
  
  <div>
            Create a new PayPal payment.
  </div>
  
  <div>
  </div>
  
  <div>
            Arguments:
  </div>
  
  <div>
                basket (Basket): The basket of products being purchased.
  </div>
  
  <div>
                request (Request, optional): A Request object which is used to construct PayPal’s `return_url`.
  </div>
  
  <div>
                use_client_side_checkout (bool, optional): This value is not used.
  </div>
  
  <div>
                **kwargs: Additional parameters; not used by this method.
  </div>
  
  <div>
  </div>
  
  <div>
            Returns:
  </div>
  
  <div>
                dict: PayPal-specific parameters required to complete a transaction. Must contain a URL
  </div>
  
  <div>
                    to which users can be directed in order to approve a newly created payment.
  </div>
  
  <div>
  </div>
  
  <div>
            Raises:
  </div>
  
  <div>
                GatewayError: Indicates a general error or unexpected behavior on the part of PayPal which prevented
  </div>
  
  <div>
                    a payment from being created.
  </div>
  
  <div>
            “””
  </div>
  
  <div>
        total_amount = unicode(basket.total_incl_tax)
  </div>
  
  <div>
        out_trade_no = basket.order_number #or basket.id ?
  </div>
  
  <div>
        subject = ‘Course Buy’
  </div>
  
  <div>
  </div>
  
  <div>
        alipay_buy_link = self.alipay_gateway+”?”+self.alipay.api_alipay_trade_page_pay(out_trade_no = out_trade_no, total_amount = total_amount, subject = subject, return_url = self.return_url ,notify_url = self.notify_url)
  </div>
  
  <div>
            parameters = {
  </div>
  
  <div>
                ‘payment_page_url’: alipay_buy_link,
  </div>
  
  <div>
            }
  </div>
  
  <div>
  </div>
  
  <div>
            return parameters
  </div>
</div>

<div>
</div>

<div>
</div>

<div>
</div>

<div>
  以支付完成后的转跳为例子(paypal),其核心代码如下:
</div>

<div>
</div>

<div>
  <div>
    #ecommerce/extensions/payment/views/paypal.py
  </div>
  
  <div>
    def get(self, request):
  </div>
  
  <div>
            “””Handle an incoming user returned to us by PayPal after approving payment.”””
  </div>
  
  <div>
            payment_id = request.GET.get(‘paymentId’)
  </div>
  
  <div>
            payer_id = request.GET.get(‘PayerID’)
  </div>
  
  <div>
            logger.info(u”Payment [%s] approved by payer [%s]”, payment_id, payer_id)
  </div>
  
  <div>
  </div>
  
  <div>
            paypal_response = request.GET.dict()
  </div>
  
  <div>
            basket = self._get_basket(payment_id)
  </div>
  
  <div>
  </div>
  
  <div>
            if not basket:
  </div>
  
  <div>
                return redirect(self.payment_processor.error_url)
  </div>
  
  <div>
  </div>
  
  <div>
            receipt_url = get_receipt_page_url(
  </div>
  
  <div>
                order_number=basket.order_number,
  </div>
  
  <div>
                site_configuration=basket.site.siteconfiguration
  </div>
  
  <div>
            )
  </div>
  
  <div>
            …..
  </div>
  
  <div>
            #实际的支付代码
  </div>
</div>

<div>
</div>

<div>
        PayPal和AliPay的交易流程有一定的不同,即AliPay有异步通知的步骤,因此当AliPay交易完成并转跳会原先的网址时,交易已经成功了。而PayPal则时在页面同步转跳后由原先网址的代码检查并确定支付的成功。
</div>

<div>
        因此对于上述代码中”receipt_url”这个地址对于支付宝的异步通知没有,这个地址只在同步转跳中发挥作用,即让支付宝在同步状态阶段来到这个页面。而生成这个页面需要的参数为”order_number”即订单编号。如下为支付宝在“异步通知”和“同步转跳”时接收到的数据:
</div>

<div>
</div>

<div>
  <div>
    #异步通知数据
  </div>
  
  <div>
    {u’version’: u’1.0′, u’app_id’: u’2016081900287513′, u’sign’: u’bGVJbMok3RSalj+ayK0GTbqups9T0uv54tvk1x+xu7hGhzoFUqm8nvxuGpyrVMRjyv0U72K58g81b7iVKAHBpIG4Lzpaw7Rg5f4qet0E7rhnEoEj6xUKTTGGt2FkCbq97K2noprvMyxNE7RkkyMx1XieXdFhrBr0tjMAVPPlsdqZRrZ0olN+S8a419/Qrm6TCbSXtbHuNxsGRrTHH2AXtp5PQhC6uHUqlXqyRqRpGNSGphhcYfBNhl/Y65WudFJjhHO1rzGGYQ3MAKOgNGv/8QXAk4XGgDl6dFskvRXpF40K/c2JPZRsfXAu2lMnpLtONptwS5L9XJcU2FyWU9x4Vw==’, u’buyer_pay_amount’: u’0.01′, u’point_amount’: u’0.00′, u’subject’: u’\u6d4b\u8bd5\u8ba2\u5355′, u’charset’: u’utf-8′, u’gmt_create’: u’2018-08-18 00:05:36′, u’out_trade_no’: u’20161155′, u’invoice_amount’: u’0.01′, u’sign_type’: u’RSA2′, u’auth_app_id’: u’2016081900287513′, u’fund_bill_list’: u'[{“amount”:”0.01″,”fundChannel”:”ALIPAYACCOUNT”}]’, u’receipt_amount’: u’0.01′, u’trade_status’: u’TRADE_SUCCESS’, u’gmt_payment’: u’2018-08-18 00:05:46′, u’trade_no’: u’2018081821001004870200545301′, u’seller_id’: u’2088102172081509′, u’total_amount’: u’0.01′, u’notify_time’: u’2018-08-18 19:59:49′, u’notify_id’: u’eb07415964fae02dd2620c7cee2767cmpq’, u’notify_type’: u’trade_status_sync’, u’buyer_id’: u’2088102175004879′}
  </div>
</div>

<div>
</div>

<div>
  <div>
    #同步跳转数据
  </div>
  
  <div>
    {u’trade_no’: u’2018081821001004870200545301′, u’seller_id’: u’2088102172081509′, u’total_amount’: u’0.01′, u’timestamp’: u’2018-08-18 00:06:11′, u’charset’: u’utf-8′, u’app_id’: u’2016081900287513′, u’sign’: u’r7S79IgDAvO4600A8x8BZJ8tKPLG/asELyoTOmhLmHsIBZLgbaTdxt13+NbSvbi+GclrSBpJQZ9ypAN5J5UzmlvklUU4+E3oHHfG+l2A6874NtYeGUzQFgD3GVq7eDuwxixjvJWHwMTL+8/jykvfASuq+aZZZJ5FWsdpqAE5AJOU3YuCRef1Ht/rjQtmw+/dSRB9HFKj+jPJfkpzAOFWdyljfSN7NP7bAuJ4KInRZ32rBqBLSTR1jPYiUWWxELNbjWhr+pMOCDw9HDaYc9oPXvf2efDFbGU6AOh+8wyAHbmypTrEM3TrKezP6JJkP+i0mf5JfaUslzyNV125DM67nQ==’, u’out_trade_no’: u’20161155′, u’version’: u’1.0′, u’sign_type’: u’RSA2′, u’auth_app_id’: u’2016081900287513′, u’method’: u’alipay.trade.page.pay.return’}
  </div>
</div>

<div>
</div>

<div>
         在这两个数据中,字段“out_trade_no”即可以用于保存”order_number”的数据,即在提交订单时,将order_number的数值赋值给out_trade_no”。
</div>

<div>
</div>

<div>
</div>

<div>
           为方便修改,将Ecommerce于支付宝对接的代码一并存放,核心代码涉及到了三个文件,分别是urls.py,processors/alipay.py,views/alipay.py三个文件,三个文件都在ecommerce/extensions/payment目录中。<a href="http://www.heyuantao.cn/wp-content/uploads/2018/10/AlipayForOpenEdxEcommerce.zip">文件下载</a>
</div>
<div>
  Url:<a href="http://ecommerce/">http://ecommerce.site/</a>
</div>

<div>
  Redirect uri:<a href="http://ecommerce/complete/edx-oidc/">http://ecommerce.site/complete/edx-oidc/</a>
</div>

<div>
  Client id:sample_id                (该部分会自动生成,也可以手动修改,注意不要泄露)
</div>

<div>
  Client secret:sample_secert   (该部分会自动生成,也可以手动修改,注意不要泄露)
</div>

<div>
  Client type:Confidential(Web application)
</div>

<div>
  Logout uri:<a href="http://ecommerce/logout/">http://ecommerce.site/logout/</a>
</div>
<div>
  sudo -H -u ecommerce bash
</div>

<div>
  source ./venvs/ecommerce/bin/activate
</div>
<div>
  manage.py create_or_update_site –site-id=1 –site-domain=ecommerce.site –partner-code=edX –partner-name=’Ginkgo’ –lms-url-root=http://lms.site –payment-processors=paypal –client-id=sample_id –client-secret=sample_secret –from-email=<a href="mailto:[email protected]">[email protected]</a>
</div>
<div>
  #增加一个选项并进行如下配置
</div>

<div>
  Enabled:勾选
</div>

<div>
  Checkout on ecommerce service:勾选
</div>

<div>
  Single course checkout page: /basket/single-item/
</div>

<div>
  Cache Time To Live:600    #这个数值暂不清楚功能
</div>

<div>
  Recept page:/checkout/receipt/?order_number=
</div>

<div>
  Enable automatic refund approval:勾选
</div>

<div>
</div>
<div>
      “ECOMMERCE_PUBLIC_URL_ROOT”: “<a href="http://ecommerce.site/">http://ecommerce.site/</a>“,
</div>

<div>
      “JWT_AUTH”: {
</div>

<div>
          “JWT_AUDIENCE”: “SET-ME-PLEASE”,
</div>

<div>
          “JWT_ISSUER”: “<a href="http://lms.site/oauth2">http://lms.site/oauth2</a>“,
</div>

<div>
          “JWT_SECRET_KEY”: “SET-ME-PLEASE”
</div>

<div>
      },
</div>

<div>
      “JWT_ISSUER”: “<a href="http://lms.site/oauth2">http://lms.site/oauth2</a>“,
</div>

<div>
     “LMS_ROOT_URL”: “<a href="http://lms.site/">http://lms.site</a>“,
</div>

<div>
     “OAUTH_ENFORCE_SECURE”: false,
</div>

<div>
     “OAUTH_OIDC_ISSUER”: “<a href="http://lms.site/oauth2">http://lms.site/oauth2</a>“,
</div>

<div>
     “FEATURES”:{
</div>

<div>
          “ENABLE_OAUTH2_PROVIDER”:true,
</div>

<div>
     }
</div>
<div>
  “ECOMMERCE_API_SIGNING_KEY”: “”  #填写1.1中key的内容
</div>
<div>
  …
</div>

<div>
  ECOMMERCE_URL_ROOT: http://ecommerce.site/
</div>

<div>
  EDX_API_KEY: sample_id
</div>

<div>
  …
</div>

<div>
  ENROLLMENT_API_URL: <a href="http://openedxtest.hudieshanfood.com/api/enrollment/v1/enrollment">http://lms.site/api/enrollment/v1/enrollment</a>
</div>

<div>
  JWT_AUTH:
</div>

<div>
      JWT_ALGORITHM: HS256
</div>

<div>
      JWT_DECODE_HANDLER: ecommerce.extensions.api.handlers.jwt_decode_handler
</div>

<div>
      JWT_ISSUERS:
</div>

<div>
      – <a href="http://openedxtest.hudieshanfood.com/oauth2">http://lms.site/oauth2</a>
</div>

<div>
      – ecommerce_worker
</div>

<div>
      JWT_LEEWAY: 1
</div>

<div>
      JWT_SECRET_KEY: SET-ME-PLEASE
</div>

<div>
      JWT_SECRET_KEYS:
</div>

<div>
      – SET-ME-PLEASE
</div>

<div>
      JWT_VERIFY_EXPIRATION: true
</div>

<div>
  …
</div>

<div>
  LMS_DASHBOARD_URL: <a href="http://openedxtest.hudieshanfood.com/dashboard">http://lms.site/dashboard</a>
</div>

<div>
  LMS_HEARTBEAT_URL: <a href="http://openedxtest.hudieshanfood.com/heartbeat">http://lms.site/heartbeat</a>
</div>

<div>
  LMS_URL_ROOT: <a href="http://openedxtest.hudieshanfood.com/">http://lms.site</a>
</div>

<div>
  OAUTH2_PROVIDER_URL: <a href="http://openedxtest.hudieshanfood.com/oauth2">http://lms.site/oauth2</a>
</div>

<div>
  PAYMENT_PROCESSOR_CONFIG:
</div>

<div>
          alipay:
</div>

<div>
              app_id: 2016081900287513
</div>

<div>
              app_private_key_path: /edx/app/ecommerce/cert/app_private_key.pem          #自己定义的密钥
</div>

<div>
              alipay_public_key_path: /edx/app/ecommerce/cert/alipay_public_key.pem      #从阿里云下载的公钥
</div>

<div>
              mode: sandbox
</div>

<div>
              app_notify_url: <a href="http://ecommercetest.hudieshanfood.com/checkout/alipay/">http://ecommerce.site/checkout/alipay/</a>
</div>

<div>
              cancel_url: <a href="http://127.0.0.1:8000/commerce/checkout/cancel/">http://127.0.0.1:8000/commerce/checkout/cancel/</a>
</div>

<div>
              error_url: <a href="http://127.0.0.1:8000/commerce/checkout/error/">http://127.0.0.1:8000/commerce/checkout/error/</a>
</div>

<div>
              receipt_url: <a href="http://127.0.0.1:8000/commerce/checkout/receipt/">http://127.0.0.1:8000/commerce/checkout/receipt/</a>
</div>

<div>
  SECRET_KEY: sample_secert
</div>

<div>
  SESSION_EXPIRE_AT_BROWSER_CLOSE: false
</div>

<div>
  SOCIAL_AUTH_EDX_OIDC_ID_TOKEN_DECRYPTION_KEY: sample_id
</div>

<div>
  #上面的这个可能用不上
</div>

<div>
  SOCIAL_AUTH_EDX_OIDC_ISSUER: <a href="http://openedxtest.hudieshanfood.com/oauth2">http://lms.site/oauth2</a>
</div>

<div>
  SOCIAL_AUTH_EDX_OIDC_KEY: sample_id
</div>

<div>
  SOCIAL_AUTH_EDX_OIDC_LOGOUT_URL: <a href="http://openedxtest.hudieshanfood.com/logout">http://lms.site/logout</a>
</div>

<div>
  SOCIAL_AUTH_EDX_OIDC_SECRET: sample_secert
</div>

<div>
  SOCIAL_AUTH_EDX_OIDC_URL_ROOT: <a href="http://openedxtest.hudieshanfood.com/oauth2">http://lms.site/oauth2</a>
</div>

<div>
  SOCIAL_AUTH_REDIRECT_IS_HTTPS: false
</div>
<div>
  class SiteConfiguration(models.Model):
</div>

<div>
      …
</div>

<div>
      def build_ecommerce_url(self, path=”):
</div>

<div>
      …
</div>

<div>
          scheme = ‘http’ if settings.DEBUG else ‘https’     #将此处修改为只支持http协议
</div>

<div>
          ecommerce_url_root = “{scheme}://{domain}”.format(scheme=scheme, domain=self.site.domain)
</div>

<div>
          return urljoin(ecommerce_url_root, path)
</div>

        <p>
          The Open edX Ecommerce module is actually a 3rd party Django project named <a href="http://oscarcommerce.com/" target="_blank" rel="noopener">Oscar</a> that the Open edX team fully integrated into the platform by fusing the user lists together with Oauth. While recently setting up the Ecommerce module on a Gingko.2 installation I found myself stumbling through some the steps in the official documentation while disagreeing entirely with others. What follows is a modified procedure that I followed to get Ecommerce running on a Ginkgo.2 installation. Hopefully this will save you some time.
        </p>
        
        <h4 data-fontsize="18" data-lineheight="27">
          Setup Procedure
        </h4>
      </div>
      
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
</div>
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
  
  <div id="cta-box" class="fusion-layout-column fusion_builder_column fusion_builder_column_1_2 fusion-one-half fusion-column-last fusion-blend-mode fusion-animated 1_2" data-animationtype="bounce" data-animationduration="0.3" data-animationoffset="50%">
    <div class="fusion-column-wrapper" data-bg-url="">
      <div class="fusion-sep-clear">
      </div>
      
      <div class="fusion-separator fusion-full-width-sep sep-none">
      </div>
      
      <div class="fusion-text">
        <div>
          <strong>Need it now?</strong>
        </div>
      </div>
      
      <div class="fusion-button-wrapper fusion-aligncenter">
        <a id="cta-button" class="fusion-button button-flat fusion-button-round button-large button-orange button-1" href="https://clients.lawrencemcdaniel.com/product/setup-ecommerce/" target="_blank" rel="noopener noreferrer"><span class="fusion-button-text">PROFESSIONAL INSTALLATION SERVICE</span></a>
      </div>
      
      <div class="fusion-sep-clear">
      </div>
      
      <div class="fusion-separator fusion-full-width-sep sep-none">
      </div>
      
      <div class="fusion-text">
        <p>
          Get Ecommerce setup same day.
        </p>
      </div>
      
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
</div>
      <div class="fusion-text">
        <p>
          If you followed the documented instructions from “<a href="https://openedx.atlassian.net/wiki/spaces/OpenOPS/pages/146440579/Native+Open+edX+Ubuntu+16.04+64+bit+Installation" target="_blank" rel="noopener">Native Open edX Ubuntu 16.04 64 bit Installation</a>” for Gingko or later then the Ecommerce module is automatically installed and should be running on your instance. You can verify this by running the following command from a terminal window connected to your Ubuntu instance.
        </p>
        
        <p>
          <code>sudo /edx/bin/supervisorctl status</code>
        </p>
      </div>
      
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
  
  <div class="fusion-layout-column fusion_builder_column fusion_builder_column_1_4 fusion-one-fourth fusion-column-first 1_4">
    <div class="fusion-column-wrapper" data-bg-url="">
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
  
  <div class="fusion-layout-column fusion_builder_column fusion_builder_column_1_2 fusion-one-half 1_2">
    <div class="fusion-column-wrapper" data-bg-url="">
      <p>
        <span class="fusion-imageframe imageframe-none imageframe-2 hover-type-none"><img loading="lazy" class="img-responsive lazyloaded" title="" src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/25054153/open-edx-running-modules2.png" alt="" width="" height="" data-lazy-src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/25054153/open-edx-running-modules2.png" data-was-processed="true" /></span>
      </p>
      
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
  
  <div class="fusion-layout-column fusion_builder_column fusion_builder_column_1_4 fusion-one-fourth fusion-column-last 1_4">
    <div class="fusion-column-wrapper" data-bg-url="">
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
  
  <div class="fusion-layout-column fusion_builder_column fusion_builder_column_1_1 fusion-one-full fusion-column-first fusion-column-last 1_1">
    <div class="fusion-column-wrapper" data-bg-url="">
      <div class="fusion-text">
        <p>
          If you see the “Ecommerce” module in a running state then you can ignore the first two steps of the official documentation, or at least when running these you should notice that both steps are benign. If for any reason you decide to execute the first two steps of the official documentation then be forewarned that step #2 is tantamount to upgrading your entire platform and could thus bring unintended consequences beyond the scope of the Ecommerce module setup.
        </p>
        
        <p>
          Moreover, if the Ecommerce module is not currently running then you should think carefully about your next steps. If your installation is not version Ginkgo or later then you should consider upgrading your entire platform before proceeding simply to ensure that your code base doesn’t venture too far into the unknown. You can read my blog post on <a href="https://blog.lawrencemcdaniel.com/upgrading-open-edx/">Upgrading Open edX</a> for more detail on what’s involved in upgrading and how to prepare.
        </p>
      </div>
      
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
</div>
        <p>
          There are a handful of things to configure in the LMS via the eponymous configuration file <code>/edx/app/edxapp/lms.env.json</code>. Refer to the screen shots below for guidance on the subject matter and approximate locations of each section. You’ll need to restart the LMS for these changes to take effect:
        </p>
        
        <pre class="prettyprint prettyprinted"><span class="pln">sudo </span><span class="pun">/</span><span class="pln">edx</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">supervisorctl restart edxapp</span><span class="pun">:</span></pre>
      </div>
      
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
  
  <div class="fusion-layout-column fusion_builder_column fusion_builder_column_1_2 fusion-one-half fusion-column-first 1_2">
    <div class="fusion-column-wrapper" data-bg-url="">
      <p>
        <span class="fusion-imageframe imageframe-none imageframe-3 hover-type-none"><img loading="lazy" class="img-responsive lazyloaded" title="" src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/25093242/open-edx-ecommerce-config-1.png" alt="" width="" height="" data-lazy-src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/25093242/open-edx-ecommerce-config-1.png" data-was-processed="true" /></span>
      </p>
      
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
  
  <div class="fusion-layout-column fusion_builder_column fusion_builder_column_1_2 fusion-one-half fusion-column-last 1_2">
    <div class="fusion-column-wrapper" data-bg-url="">
      <p>
        <span class="fusion-imageframe imageframe-none imageframe-4 hover-type-none"><img loading="lazy" class="img-responsive lazyloaded" title="" src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/25093333/open-edx-ecommerce-config-3.png" alt="" width="" height="" data-lazy-src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/25093333/open-edx-ecommerce-config-3.png" data-was-processed="true" /></span>
      </p>
      
      <div class="fusion-sep-clear">
      </div>
      
      <div class="fusion-separator fusion-full-width-sep sep-none">
      </div>
      
      <p>
        <span class="fusion-imageframe imageframe-none imageframe-5 hover-type-none"><img loading="lazy" class="img-responsive lazyloaded" title="" src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/25093356/open-edx-ecommerce-config-4.png" alt="" width="" height="" data-lazy-src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/25093356/open-edx-ecommerce-config-4.png" data-was-processed="true" /></span>
      </p>
      
      <div class="fusion-sep-clear">
      </div>
      
      <div class="fusion-separator fusion-full-width-sep sep-none">
      </div>
      
      <p>
        <span class="fusion-imageframe imageframe-none imageframe-6 hover-type-none"><img loading="lazy" class="img-responsive lazyloaded" title="" src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/25093309/open-edx-ecommerce-config-2.png" alt="" width="" height="" data-lazy-src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/25093309/open-edx-ecommerce-config-2.png" data-was-processed="true" /></span>
      </p>
      
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
  
  <div class="fusion-layout-column fusion_builder_column fusion_builder_column_1_1 fusion-one-full fusion-column-first fusion-column-last 1_1">
    <div class="fusion-column-wrapper" data-bg-url="">
      <div class="fusion-text">
        <p>
          Briefly summarizing the purpose of each section:
        </p>
        
        <ul>
          <li>
            <em>ENABLE_OAUTH2_PROVIDER</em> – This enables the LMS as a provider of Oauth2 authentication services. The Ecommerce module will leverage Oauth2 rather than host its own user list and passwords. For example, as an end user if you’ve ever elected to “Login with Facebook” then this flag makes your LMS the “Facebook” of that proposition.
          </li>
          <li>
            <em>JWT_AUTH</em> – This is the URL of the <a href="https://jwt.io/introduction/" target="_blank" rel="noopener">JSON Web Token</a> authorizer. In our case it’s exactly the same as the issuer.
          </li>
          <li>
            <em>JWT_ISSUER</em> – This is the URL of the <a href="https://jwt.io/introduction/" target="_blank" rel="noopener">JSON Web Token</a> issuer
          </li>
          <li>
            <em>OAUTH_OIDC_ISSUER</em> – This is the URL of the <a href="http://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier" target="_blank" rel="noopener">Open ID issuer</a> (eg your LMS platform)
          </li>
          <li>
            <em>PAID_COURSE_REGISTRATION_CURRENCY</em> – The Ecommerce module reads this value to determine which currency symbol to display along side products. This value is also passed to the payment gateway.
          </li>
          <li>
            <em>PDF_RECEIPT_</em> – All of the salient text for customer receipts is stored in these fields.
          </li>
        </ul>
      </div>
      
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
</div>
      <div class="fusion-text">
        <p>
          It wasn’t initially apparent to me but, setting configuration parameters in lms.env.json only indicates to the LMS that you <em>want</em> to use it as part of an Oauth authentication; you still have to setup Oauth itself. We’ll use the Django admin console for this. For the Python/Django uninitiated, Django apps like LMS and CMS come with a “back end” admin console where additional configuration parameters are available beyond what you’ll find in the four JSON files in /edx/app/edxapp/. Refer to this screen shot for the URL path and guidelines for creating an Oauth client.
        </p>
      </div>
      
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
  
  <div class="fusion-layout-column fusion_builder_column fusion_builder_column_1_1 fusion-one-full fusion-column-first fusion-column-last 1_1">
    <div class="fusion-column-wrapper" data-bg-url="">
      <p>
        <span class="fusion-imageframe imageframe-none imageframe-7 hover-type-none"><img loading="lazy" class="img-responsive lazyloaded" title="" src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/25102433/ecommerce-django-oauth-client-setup.png" alt="" width="" height="" data-lazy-src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/25102433/ecommerce-django-oauth-client-setup.png" data-was-processed="true" /></span>
      </p>
      
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
</div>
        <p>
          This is the definitive step in “activating” the Ecommerce module. Refer to the following screen shot for parameter values and the desired outcome.
        </p>
      </div>
      
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
  
  <div class="fusion-layout-column fusion_builder_column fusion_builder_column_1_1 fusion-one-full fusion-column-first fusion-column-last 1_1">
    <div class="fusion-column-wrapper" data-bg-url="">
      <p>
        <span class="fusion-imageframe imageframe-none imageframe-8 hover-type-none"><img loading="lazy" class="img-responsive lazyloaded" title="" src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/25102948/django-ecommerce-configuration.png" alt="" width="" height="" data-lazy-src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/25102948/django-ecommerce-configuration.png" data-was-processed="true" /></span>
      </p>
      
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
</div>
        <p>
          This step essentially binds together the Django configurations you created in the previous two steps 3 & 4 so that the Oscar Ecommerce module works seamlessly with our LMS.
        </p>
        
        <pre class="prettyprint prettyprinted"><span class="pln">sudo su ecommerce </span><span class="pun">-</span><span class="pln">s </span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">bash

cd ~/ecommerce source ../ecommerce_env python manage.py makemigrations python manage.py migrate python manage.py create_or_update_site
site-id=1
site-domain=preescolar.atentamente.mx:8002
partner-code=edX
partner-name=‘Open edX’
lms-url-root=https://preescolar.atentamente.mx </span> payment-processors=paypal
client-id=ecommerce-key
client-secret=ecommerce-secret
from-email=edx.atentamente@gmail.com
discovery_api_url=https://preescolar.atentamente.mx:18381/

        <p>
          Following is how these command line arguments map to the two Django configuration screens from the previous step.
        </p>
      </div>
      
      <p>
        <span class="fusion-imageframe imageframe-none imageframe-9 hover-type-none"><img loading="lazy" class="img-responsive lazyloaded" title="" src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/26130916/ecommerce-bind-django-configs.png" alt="" width="" height="" data-lazy-src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/26130916/ecommerce-bind-django-configs.png" data-was-processed="true" /></span>
      </p>
      
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
</div>
        <p>
          If everything is working as it should then you’ll be able to navigate to the Ecommerce dashboard where you can begin setting up your products. You can refer to the <a href="https://django-oscar.readthedocs.io/" target="_blank" rel="noopener">Oscar Ecommerce Official Documentation</a> for further instructions on setting up products, payment gateways, etcetera.
        </p>
      </div>
      
      <p>
        <span class="fusion-imageframe imageframe-none imageframe-10 hover-type-none"><img loading="lazy" class="img-responsive lazyloaded" title="" src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/25111137/oscar-dashboard-1.png" alt="" width="" height="" data-lazy-src="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/04/25111137/oscar-dashboard-1.png" data-was-processed="true" /></span>
      </p>
      
      <div class="fusion-clearfix">
      </div>
    </div>
  </div>
</div>
        <ul>
          <li>
            <strong>Firewall</strong>. You should pay close attention to the unorthodox port assignments used by the Ecommerce module. By default the Oscar Ecommerce module runs on port 8002 and the LMS “Course Discovery” API runs on port 18381. You might need to open these ports on your firewall.
          </li>
          <li>
            <strong>Port Settings</strong>. Take note that ports have changed over time. The official documentation makes multiple references to ports 18020 and 18130; neither of which seem to be in use on Ginkgo.
          </li>
          <li>
            <strong>Nginx</strong>. If you’re using SSL on your site then you might need to make adjustments to one or more of the Nginx virtual server configurations located in /edx/app/nginx/sites-available/.
          </li>
          <li>
            <strong>Additional Work Notes</strong>. You can reference <a href="https://cdn-blog.lawrencemcdaniel.com/wp-content/uploads/2018/07/04061508/Open-edX-Ecommerce-Configuration-Issue-Resolved.pdf" target="_blank" rel="noopener">these additional work notes</a> from my colleague Eric Mensah and myself as he was trouble-shooting a couple of details related to ports and ssl.
          </li>
        </ul>
        
        <p>
          I hope you found this helpful. Please help me improve this article by leaving a comment below. Thank you!
        </p>
      </div>
    </div>
  </div>
</div>