nopCommerce 3.9 wave series refundable Alipay plugin (next)

Keywords: ASP.NET Database SQL Attribute xml

I. Review

Alipay plug-in source download address: Click Download      

    Part One This article introduces the use of Alipay plug-in for payment, full refund, partial refund and multi store configuration of plug-ins. This paper introduces how to implement it.

II. Pre-preparation

Plug-ins have three main functions:

  1. Multi-Store Plug-in Configuration
  2. Payment function
  3. Refund function

Database support:

  1. Add dbl_PaymentInfo table to save payment records.
  2. Add dbl_RefundInfo table to save the refund record.

Other preparations:

  1. Alipay instant arrival PID and MD5 secret key Key can be acquired through Alipay open platform.

III. Process Planning

  1. Plug-in Installation and Unloading Process

2. Payment process

3. Refund process

IV. Creating Projects

1. The new class library project, named DaBoLang.Nop.Plugin.Payments.AliPay, is located under Plugins.

2. Click the project shortcut Alt+Enter to enter the project properties.

Set the output path to. . . Presentation Nop. Web Plugins DaBoLang. Payments. AliPay\

3. Install packages: Create a new packages.config file in the project root directory, which reads as follows

  1 <?xml version="1.0" encoding="utf-8"?>
  2 <packages>
  3   <package id="Autofac" version="4.4.0" targetFramework="net451" />
  4   <package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net451" />
  5   <package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net451" />
  6   <package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net451" />
  7   <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net451" />
  8 </packages>

Open the Tool [NuGet Package Manager] [Package Manager Console],

Enter the following command to update the package: Update-Package-Project Name'DaBoLang.Nop.Plugin.Payments.AliPay'-Reinstall

Finally, add Nop.Core Nop.Data Nop.Services Nop.Web.FrameWork project reference

4. Create plug-in description file: Create a new Description.txt file in the root directory for plug-in description, which is written as follows:

  1 Group: Payment methods
  2 FriendlyName: Alipay
  3 SystemName: DaBoLang.Payments.AliPay
  4 Version: 1.00
  5 SupportedVersions: 3.90
  6 Author: Big Waves
  7 DisplayOrder: 1
  8 FileName: DaBoLang.Nop.Plugin.Payments.AliPay.dll
  9 Description: Alipay instant arrival plugin, support payment, refund

5. Create a project directory, if you have downloaded the plug-in project reference project directory as follows:

  • Alipay Alipay instant arrival related
  • Controllers Controllers Controller Folder
  • Data. Database correlation
  • Domain entity class
  • Models
  • Services Service Interface
  • Views
  • AliPayPaymentProcessor.cs Payment Plug-in Implementation Class
  • AliPayPaymentSettings.cs Alipay instant arrival account configuration class
  • Dependency Registrar. CS Dependency Injection Extension Class
  • Description.txt Plug-in Description File
  • RouteProvider.cs Route Registration Class

5. Creating a database

The project has been created. Note that we created payment and refund records to keep relevant records. nop uses the ORM framework as the Entity Framework framework, and we use the Code First pattern to create it.

Create in Domain folder PaymentInfo class is used to save payment information, RefundInfo class is used to save refund information.

Entity classes in nop need to inherit Nop.Core.BaseEntity Abstract methods.

  1 using Nop.Core;
  2 using Nop.Core.Domain.Customers;
  3 using Nop.Core.Domain.Orders;
  4 using System;
  5 using System.Collections.Generic;
  6 using System.Diagnostics;
  7 using System.Globalization;
  8 using System.Linq;
  9 
 10 namespace DaBoLang.Nop.Plugin.Payments.AliPay.Domain
 11 {
 12     /// <summary>
 13     /// Namespace: DaBoLang.Nop.Plugin.Payments.AliPay.Domain
 14     /// Name: PaymentInfo
 15     /// Function: Entity class
 16     /// Details: Payment Records
 17     /// Version: 1.0.0.0 
 18     /// Author: Big Wave
 19     /// Contact: http://www.cnblogs.com/yaoshangjin
 20     /// Description:
 21     /// </summary>
 22     public partial class PaymentInfo : BaseEntity
 23     {
 24         #region Properties
 25         public Guid PaymentGuid { get; set; }
 26         /// <summary>
 27         /// Order Number
 28         /// </summary>
 29         public int OrderId { get; set; }
 30         /// <summary>
 31         /// Plug-in SystemName
 32         /// </summary>
 33         public string Name { get; set; }
 34         /// <summary>
 35         /// Transaction Amount
 36         /// </summary>
 37         public decimal Total { get; set; }
 38         /// <summary>
 39         /// Order Number External Trading Number
 40         /// </summary>
 41         public string Out_Trade_No { get; set; }
 42         /// <summary>
 43         /// Description
 44         /// </summary>
 45         public string Note { get; set; }
 46         /// <summary>
 47         //Transaction number, internal transaction number, Alipay transaction number or WeChat transaction number.
 48         /// </summary>
 49         public string Trade_no { get; set; }
 50         /// <summary>
 51         /// Third party transaction status
 52         /// </summary>
 53         public string Trade_status { get; set; }
 54         /// <summary>
 55         /// Receiving unit email
 56         /// </summary>
 57         public string Seller_email { get; set; }
 58         /// <summary>
 59         /// Receiving unit id
 60         /// </summary>
 61         public string Seller_id { get; set; }
 62         /// <summary>
 63         /// Payment account id
 64         /// </summary>
 65         public string Buyer_id { get; set; }
 66         /// <summary>
 67         /// Payment account email
 68         /// </summary>
 69         public string Buyer_email { get; set; }
 70        /// <summary>
 71        /// Internal order creation time
 72        /// </summary>
 73         public DateTime CreateDateUtc { get; set; }
 74 
 75         #endregion
 76     }
 77 }
 78 
PaymentInfo
  1 using Nop.Core;
  2 using Nop.Core.Domain.Customers;
  3 using Nop.Core.Domain.Orders;
  4 using System;
  5 using System.Collections.Generic;
  6 using System.Diagnostics;
  7 using System.Globalization;
  8 using System.Linq;
  9 
 10 namespace DaBoLang.Nop.Plugin.Payments.AliPay.Domain
 11 {
 12     /// <summary>
 13     /// Namespace: DaBoLang.Nop.Plugin.Payments.AliPay.Domain
 14     /// Name: RefundInfo
 15     /// Function: Entity class
 16     /// Details: Refund Records
 17     /// Version: 1.0.0.0
 18     /// Author: Big Wave
 19     /// Contact: http://www.cnblogs.com/yaoshangjin
 20     /// Description:
 21     /// </summary>
 22     public partial class RefundInfo : BaseEntity
 23     {
 24 
 25         #region Properties
 26         public int OrderId { get; set; }
 27         /// <summary>
 28         /// Refund status
 29         /// </summary>
 30         public int RefundStatusId { get; set; }
 31         /// <summary>
 32         /// Amount of refund
 33         /// </summary>
 34         public decimal AmountToRefund { get; set; }
 35         public string Seller_Email { get; set; }
 36         public string Seller_Id { get; set; }
 37         /// <summary>
 38         //Transaction number, internal transaction number, Alipay transaction number or WeChat transaction number.
 39         /// </summary>
 40         public string Batch_no { get; set; }
 41         /// <summary>
 42         /// Order Number External Trading Number
 43         /// </summary>
 44         public string Out_Trade_No { get; set; }
 45         /// <summary>
 46         /// Creation time
 47         /// </summary>
 48         public DateTime CreateOnUtc { get; set; }
 49         /// <summary>
 50         /// Successful time for refund
 51         /// </summary>
 52         public DateTime? RefundOnUtc { get; set; }
 53 
 54         /// <summary>
 55         /// Callback ID
 56         /// </summary>
 57         public string Notify_Id { get; set; }
 58         /// <summary>
 59         /// Callback type
 60         /// </summary>
 61         public string Notify_Type { get; set; }
 62 
 63         public string Result_Details { get; set; }
 64         #endregion
 65 
 66         /// <summary>
 67         /// Order status
 68         /// </summary>
 69         public RefundStatus RefundStatus
 70         {
 71             get
 72             {
 73                 return (RefundStatus)this.RefundStatusId;
 74             }
 75             set
 76             {
 77                 this.RefundStatusId = (int)value;
 78             }
 79         }
 80 
 81     }
 82     public enum RefundStatus
 83     {
 84         /// <summary>
 85         /// Application for refund
 86         /// </summary>
 87         refunding = 10,
 88         /// <summary>
 89         /// Successful refund
 90         /// </summary>
 91         refund = 20,
 92         /// <summary>
 93         /// Cancellation of refunds
 94         /// </summary>
 95         cancel = 30,
 96         /// <summary>
 97         /// Reimbursement expires
 98         /// </summary>
 99         overtime = 40,
100         /// <summary>
101         /// Failure of refund
102         /// </summary>
103         error = 50,
104     }
105 }
106 
RefundInfo

2. Configuration of mapping relationship between creating entities and databases in Data folders

Mapping relation configuration in nop needs to inherit nop. Data. Mapping. NopEntityTypeConfiguration < T > interface, and T generics are mapping entity classes.

This interface also inherits the EntityTypeConfiguration < T > interface.

The PaymentInfoMap class associates the PaymentInfo entity class.

Specifying a database through this.ToTable("dbl_PaymentInfo") in the constructor indicates that this. HasKey (x => x.Id); specifies the primary key

  1 using DaBoLang.Nop.Plugin.Payments.AliPay.Domain;
  2 using Nop.Data.Mapping;
  3 
  4 namespace DaBoLang.Nop.Plugin.Payments.AliPay.Data
  5 {
  6     /// <summary>
  7     /// Namespace: DaBoLang.Nop.Plugin.Payments.AliPay.Data
  8     /// Name: PaymentInfoMap
  9     /// Function: Entity mapping
 10     /// Details: Payment Table Mapping
 11     /// Author: Big Wave
 12     /// </summary>
 13     public partial class PaymentInfoMap : NopEntityTypeConfiguration<PaymentInfo>
 14     {
 15         public PaymentInfoMap()
 16         {
 17             this.ToTable("dbl_PaymentInfo");
 18             this.HasKey(x => x.Id);
 19         }
 20     }
 21 }

RefundInfoMap associates RefundInfo entity classes with dbl_RefundInfo tables.

This. Ignore (x=> X. RefundStatus); indicates that the RefundStatus attribute is ignored and that the omitted attribute will not create the attribute field when creating data.

  1 using DaBoLang.Nop.Plugin.Payments.AliPay.Domain;
  2 using Nop.Data.Mapping;
  3 
  4 namespace DaBoLang.Nop.Plugin.Payments.AliPay.Data
  5 {
  6     /// <summary>
  7     /// Namespace: DaBoLang.Nop.Plugin.Payments.AliPay.Data
  8     /// Name: RefundInfoMap
  9     /// Function: Entity mapping
 10     /// Details: Refund record mapping
 11     /// </summary>
 12     public partial class RefundInfoMap : NopEntityTypeConfiguration<RefundInfo>
 13     {
 14         public RefundInfoMap()
 15         {
 16             this.ToTable("dbl_RefundInfo");
 17             this.HasKey(x => x.Id);
 18             this.Ignore(x=>x.RefundStatus);
 19         }
 20     }
 21 }

3. Creating database context

We have created entity classes and mapping relationships for two tables, and then we need to create the DbContext database context.

Create the AliPayObjectContext class under the Data directory, inherit the DbContext class and Nop.Data.IDbContext interface

Rewrite the OnModel Creating method and add the Map configuration to EF.

Tip: Nop.Data.NopObjectContext is the default context available for Nop. Reflection mechanism can also be used here to automatically add configuration. Of course, you need to extract the Map interface again. Interested friends expand themselves.

  1  protected override void OnModelCreating(DbModelBuilder modelBuilder)
  2         {
  3             modelBuilder.Configurations.Add(new PaymentInfoMap());
  4             modelBuilder.Configurations.Add(new RefundInfoMap());
  5 
  6             //disable EdmMetadata generation
  7             //modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
  8             base.OnModelCreating(modelBuilder);
  9         }

Add Install() method to create table, Uninstall() method to delete table.

  1        /// <summary>
  2         /// Installation
  3         /// </summary>
  4         public void Install()
  5         {
  6             //Create tables
  7             var dbScript = CreateDatabaseScript();
  8             Database.ExecuteSqlCommand(dbScript);
  9             SaveChanges();
 10         }
 11 
 12         /// <summary>
 13         /// Unloading
 14         /// </summary>
 15         public void Uninstall()
 16         {
 17             //Delete tables
 18             var tableName = this.GetTableName<PaymentInfo>();
 19             this.DropPluginTable(tableName);
 20             tableName = this.GetTableName<RefundInfo>();
 21             this.DropPluginTable(tableName);
 22         }

The complete code is as follows

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Data.Entity;
  4 using System.Data.Entity.Infrastructure;
  5 using Nop.Core;
  6 using Nop.Data;
  7 using DaBoLang.Nop.Plugin.Payments.AliPay.Domain;
  8 
  9 namespace DaBoLang.Nop.Plugin.Payments.AliPay.Data
 10 {
 11     /// <summary>
 12     /// Namespace: DaBoLang.Nop.Plugin.Payments.AliPay.Data
 13     /// Name: AliPayObjectContext
 14     /// Function: Database
 15     /// Details: Database Context
 16     /// Version: 1.0.0.0
 17     /// File name: AliPayObjectContext.cs
 18     /// Author: Big Wave
 19     /// Contact: http://www.cnblogs.com/yaoshangjin
 20     /// Description:
 21     /// </summary>
 22     public class AliPayObjectContext : DbContext, IDbContext
 23     {
 24         #region Ctor
 25 
 26         public AliPayObjectContext(string nameOrConnectionString)
 27             : base(nameOrConnectionString)
 28         {
 29             //((IObjectContextAdapter) this).ObjectContext.ContextOptions.LazyLoadingEnabled = true;
 30         }
 31 
 32         #endregion
 33 
 34         #region Utilities
 35 
 36         protected override void OnModelCreating(DbModelBuilder modelBuilder)
 37         {
 38             modelBuilder.Configurations.Add(new PaymentInfoMap());
 39             modelBuilder.Configurations.Add(new RefundInfoMap());
 40 
 41             //disable EdmMetadata generation
 42             //modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
 43             base.OnModelCreating(modelBuilder);
 44         }
 45 
 46         #endregion
 47 
 48         #region Methods
 49 
 50         public string CreateDatabaseScript()
 51         {
 52             return ((IObjectContextAdapter)this).ObjectContext.CreateDatabaseScript();
 53         }
 54 
 55         public new IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity
 56         {
 57             return base.Set<TEntity>();
 58         }
 59 
 60         /// <summary>
 61         /// Installation
 62         /// </summary>
 63         public void Install()
 64         {
 65             //create the table
 66             var dbScript = CreateDatabaseScript();
 67             Database.ExecuteSqlCommand(dbScript);
 68             SaveChanges();
 69         }
 70 
 71         /// <summary>
 72         /// Unloading
 73         /// </summary>
 74         public void Uninstall()
 75         {
 76             //Delete tables
 77             var tableName = this.GetTableName<PaymentInfo>();
 78             this.DropPluginTable(tableName);
 79             tableName = this.GetTableName<RefundInfo>();
 80             this.DropPluginTable(tableName);
 81         }
 82 
 83         /// <summary>
 84         /// Execute stores procedure and load a list of entities at the end
 85         /// </summary>
 86         /// <typeparam name="TEntity">Entity type</typeparam>
 87         /// <param name="commandText">Command text</param>
 88         /// <param name="parameters">Parameters</param>
 89         /// <returns>Entities</returns>
 90         public IList<TEntity> ExecuteStoredProcedureList<TEntity>(string commandText, params object[] parameters) where TEntity : BaseEntity, new()
 91         {
 92             throw new NotImplementedException();
 93         }
 94 
 95         /// <summary>
 96         /// Creates a raw SQL query that will return elements of the given generic type.  The type can be any type that has properties that match the names of the columns returned from the query, or can be a simple primitive type. The type does not have to be an entity type. The results of this query are never tracked by the context even if the type of object returned is an entity type.
 97         /// </summary>
 98         /// <typeparam name="TElement">The type of object returned by the query.</typeparam>
 99         /// <param name="sql">The SQL query string.</param>
100         /// <param name="parameters">The parameters to apply to the SQL query string.</param>
101         /// <returns>Result</returns>
102         public IEnumerable<TElement> SqlQuery<TElement>(string sql, params object[] parameters)
103         {
104             throw new NotImplementedException();
105         }
106 
107         /// <summary>
108         /// Executes the given DDL/DML command against the database.
109         /// </summary>
110         /// <param name="sql">The command string</param>
111         /// <param name="doNotEnsureTransaction">false - the transaction creation is not ensured; true - the transaction creation is ensured.</param>
112         /// <param name="timeout">Timeout value, in seconds. A null value indicates that the default value of the underlying provider will be used</param>
113         /// <param name="parameters">The parameters to apply to the command string.</param>
114         /// <returns>The result returned by the database after executing the command.</returns>
115         public int ExecuteSqlCommand(string sql, bool doNotEnsureTransaction = false, int? timeout = null, params object[] parameters)
116         {
117             throw new NotImplementedException();
118         }
119 
120         /// <summary>
121         /// Detach an entity
122         /// </summary>
123         /// <param name="entity">Entity</param>
124         public void Detach(object entity)
125         {
126             if (entity == null)
127                 throw new ArgumentNullException("entity");
128 
129             ((IObjectContextAdapter)this).ObjectContext.Detach(entity);
130         }
131 
132         #endregion
133 
134         #region Properties
135 
136         /// <summary>
137         /// Gets or sets a value indicating whether proxy creation setting is enabled (used in EF)
138         /// </summary>
139         public virtual bool ProxyCreationEnabled
140         {
141             get
142             {
143                 return this.Configuration.ProxyCreationEnabled;
144             }
145             set
146             {
147                 this.Configuration.ProxyCreationEnabled = value;
148             }
149         }
150 
151         /// <summary>
152         /// Gets or sets a value indicating whether auto detect changes setting is enabled (used in EF)
153         /// </summary>
154         public virtual bool AutoDetectChangesEnabled
155         {
156             get
157             {
158                 return this.Configuration.AutoDetectChangesEnabled;
159             }
160             set
161             {
162                 this.Configuration.AutoDetectChangesEnabled = value;
163             }
164         }
165 
166         #endregion
167     }
168 }
AliPayObjectContext

4. Add the EfStartUpTask class to initialize the initial database at startup

  1 using System.Data.Entity;
  2 using Nop.Core.Infrastructure;
  3 
  4 namespace DaBoLang.Nop.Plugin.Payments.AliPay.Data
  5 {
  6     /// <summary>
  7     /// Namespace: DaBoLang.Nop.Plugin.Payments.AliPay.Data
  8     /// Name: EfStartUpTask
  9     /// Function: Start Tasks
 10     /// Details: database initialization at startup never creates a database
 11     /// Version: 1.0.0.0
 12     /// Author: Big Wave
 13     /// Contact: http://www.cnblogs.com/yaoshangjin
 14     /// Description:
 15     /// </summary>
 16     public class EfStartUpTask : IStartupTask
 17     {
 18         public void Execute()
 19         {
 20             //It's required to set initializer to null (for SQL Server Compact).
 21             //otherwise, you'll get something like "The model backing the 'your context name' context has changed since the database was created. Consider using Code First Migrations to update the database"
 22             Database.SetInitializer<AliPayObjectContext>(null);
 23         }
 24 
 25         public int Order
 26         {
 27             //ensure that this task is run first 
 28             get { return 0; }
 29         }
 30     }
 31 }
 32 

At this point, the database related classes have been created, but can not be used yet. We need to register these classes into the dependency injection framework.

5. Add the Dependency Registrar class for dependency registration

  1 using Autofac;
  2 using Autofac.Core;
  3 using DaBoLang.Nop.Plugin.Payments.AliPay.Data;
  4 using DaBoLang.Nop.Plugin.Payments.AliPay.Domain;
  5 using DaBoLang.Nop.Plugin.Payments.AliPay.Services;
  6 using Nop.Core.Configuration;
  7 using Nop.Core.Data;
  8 using Nop.Core.Infrastructure;
  9 using Nop.Core.Infrastructure.DependencyManagement;
 10 using Nop.Data;
 11 using Nop.Web.Framework.Mvc;
 12 
 13 namespace DaBoLang.Nop.Plugin.Payments.AliPay
 14 {
 15     /// <summary>
 16     /// Namespace: DaBoLang.Nop.Plugin.Payments.AliPay
 17     /// Name: Dependency Registrar
 18     /// Functions: Framework
 19     /// Details: Registration
 20     /// Version: 1.0.0.0
 21     /// Author: Big Wave
 22     /// Contact: http://www.cnblogs.com/yaoshangjin
 23     /// Description:
 24     /// </summary>
 25     public class DependencyRegistrar : IDependencyRegistrar
 26     {
 27         /// <summary>
 28         /// Register services and interfaces
 29         /// </summary>
 30         /// <param name="builder">Container builder</param>
 31         /// <param name="typeFinder">Type finder</param>
 32         /// <param name="config">Config</param>
 33         public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, NopConfig config)
 34         {
 35             //Database context
 36             this.RegisterPluginDataContext<AliPayObjectContext>(builder, "nop_object_context_alipay");
 37 
 38             //Register database context for Repository
 39             builder.RegisterType<EfRepository<PaymentInfo>>()
 40                 .As<IRepository<PaymentInfo>>()
 41                 .WithParameter(ResolvedParameter.ForNamed<IDbContext>("nop_object_context_alipay"))
 42                 .InstancePerLifetimeScope();
 43 
 44             builder.RegisterType<EfRepository<RefundInfo>>()
 45                .As<IRepository<RefundInfo>>()
 46                .WithParameter(ResolvedParameter.ForNamed<IDbContext>("nop_object_context_alipay"))
 47                .InstancePerLifetimeScope();
 48 
 49 
 50             //Registered Payment Recording Service
 51             builder.RegisterType<PaymentInfoService>().As<IPaymentInfoService>().InstancePerLifetimeScope();
 52             //Registered Refund Recording Service
 53             builder.RegisterType<RefundInfoService>().As<IRefundInfoService>().InstancePerLifetimeScope();
 54         }
 55 
 56         /// <summary>
 57         /// Order of this dependency registrar implementation
 58         /// </summary>
 59         public int Order
 60         {
 61             get { return 1; }
 62         }
 63     }
 64 }
 65 

Good sample database related classes are completed.

Installation and uninstallation of plug-ins

Now we can write the payment plug-in class. First, we create the AliPayPaymentProcessor class, which inherits the BasePlugin abstract class and the IPaymentMethod interface.

The nop payment plug-in needs to inherit the Nop.Services.Payments.IpaymentMethod interface, which provides methods for payment-related purposes. See the code comment below for the interface instructions (please leave a message to correct the misunderstanding).

  1 namespace Nop.Services.Payments
  2 {
  3     /// <summary>
  4     /// Provides an interface for creating payment gateways and methods
  5     /// </summary>
  6     public partial interface IPaymentMethod : IPlugin
  7     {
  8         #region Methods
  9 
 10         /// <summary>
 11         /// Payment processing
 12         /// </summary>
 13         /// <param name="processPaymentRequest">Payment info required for an order processing</param>
 14         /// <returns>Process payment result</returns>
 15         ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest);
 16 
 17         /// <summary>
 18         /// Request payment process (URLs that need to be redirected to a third-party payment gateway)
 19         /// </summary>
 20         /// <param name="postProcessPaymentRequest">Payment info required for an order processing</param>
 21         void PostProcessPayment(PostProcessPaymentRequest postProcessPaymentRequest);
 22 
 23         /// <summary>
 24         /// Should payment methods be hidden, such as goods in shopping carts that do not need to be distributed?
 25         /// <param name="cart">Shoping cart</param>
 26         /// <returns>true - hide; false - display.</returns>
 27         bool HidePaymentMethod(IList<ShoppingCartItem> cart);
 28 
 29         /// <summary>
 30         /// Additional costs
 31         /// </summary>
 32         /// <param name="cart">Shoping cart</param>
 33         /// <returns>Additional handling fee</returns>
 34         decimal GetAdditionalHandlingFee(IList<ShoppingCartItem> cart);
 35 
 36         /// <summary>
 37         /// Follow-up payment
 38         /// </summary>
 39         /// <param name="capturePaymentRequest">Capture payment request</param>
 40         /// <returns>Capture payment result</returns>
 41         CapturePaymentResult Capture(CapturePaymentRequest capturePaymentRequest);
 42 
 43         /// <summary>
 44         /// Refund
 45         /// </summary>
 46         /// <param name="refundPaymentRequest">Request</param>
 47         /// <returns>Result</returns>
 48         RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequest);
 49 
 50         /// <summary>
 51         /// Voids a payment
 52         /// </summary>
 53         /// <param name="voidPaymentRequest">Request</param>
 54         /// <returns>Result</returns>
 55         VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest);
 56 
 57         /// <summary>
 58         /// Payment on a regular basis
 59         /// </summary>
 60         /// <param name="processPaymentRequest">Payment info required for an order processing</param>
 61         /// <returns>Process payment result</returns>
 62         ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentRequest processPaymentRequest);
 63 
 64         /// <summary>
 65         /// Cancellation of regular payments
 66         /// </summary>
 67         /// <param name="cancelPaymentRequest">Request</param>
 68         /// <returns>Result</returns>
 69         CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurringPaymentRequest cancelPaymentRequest);
 70 
 71         /// <summary>
 72         /// Does duplicate payment support after the order is created but the payment is unsuccessful?
 73         /// </summary>
 74         /// <param name="order">Order</param>
 75         /// <returns>Result</returns>
 76         bool CanRePostProcessPayment(Order order);
 77 
 78         /// <summary>
 79         /// Configuration routing
 80         /// </summary>
 81         /// <param name="actionName">Action name</param>
 82         /// <param name="controllerName">Controller name</param>
 83         /// <param name="routeValues">Route values</param>
 84         void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues);
 85 
 86         /// <summary>
 87         /// Payment Information Routing
 88         /// </summary>
 89         /// <param name="actionName">Action name</param>
 90         /// <param name="controllerName">Controller name</param>
 91         /// <param name="routeValues">Route values</param>
 92         void GetPaymentInfoRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues);
 93 
 94         Type GetControllerType();
 95 
 96         #endregion
 97 
 98         #region Properties
 99 
100         /// <summary>
101         /// Support tracking
102         /// </summary>
103         bool SupportCapture { get; }
104 
105         /// <summary>
106         /// Support partial refund
107         /// </summary>
108         bool SupportPartiallyRefund { get; }
109 
110         /// <summary>
111         /// Support for refunds
112         /// </summary>
113         bool SupportRefund { get; }
114 
115         /// <summary>
116         /// Invalid
117         /// </summary>
118         bool SupportVoid { get; }
119 
120         /// <summary>
121         /// Term of payment
122         /// </summary>
123         RecurringPaymentType RecurringPaymentType { get; }
124 
125         /// <summary>
126         /// Payment method
127         /// </summary>
128         PaymentMethodType PaymentMethodType { get; }
129 
130         /// <summary>
131         /// Whether to display the payment information page of the plug-in
132         /// </summary>
133         bool SkipPaymentInfo { get; }
134 
135         /// <summary>
136         /// Payment description will be displayed on Payment Method page
137         /// </summary>
138         string PaymentMethodDescription { get; }
139 
140         #endregion
141     }
142 }

Rewrite the installation and uninstallation methods, and the AliPayPaymentSettings class is used to save plug-in configurations

  1 #region plug-in installation/uninstallation
  2 
  3         public override void Install()
  4         {
  5             //To configure
  6             var settings = new AliPayPaymentSettings
  7             {
  8                 SellerEmail = "",
  9                 Key = "",
 10                 Partner = "",
 11                 AdditionalFee = 0,
 12             };
 13 
 14             _settingService.SaveSetting(settings);
 15 
 16             //Install data sheet
 17             _objectContext.Install();
 18 
 19             //Localization Resources
 20             this.AddOrUpdatePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.RedirectionTip", "You will be redirected to Alipay website to complete the order..");
 21             this.AddOrUpdatePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.SellerEmail", "Seller's mailbox");
 22             this.AddOrUpdatePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.SellerEmail.Hint", "Alipay seller e-mail.");
 23             this.AddOrUpdatePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.Key", "Key");
 24             this.AddOrUpdatePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.Key.Hint", "input key.");
 25             this.AddOrUpdatePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.Partner", "Partner");
 26             this.AddOrUpdatePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.Partner.Hint", "input partner.");
 27             this.AddOrUpdatePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.AdditionalFee", "additional costs");
 28             this.AddOrUpdatePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.AdditionalFee.Hint", "Customers will pay extra for choosing this payment method..");
 29             this.AddOrUpdatePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.PaymentMethodDescription", "Use Alipay to pay");
 30 
 31             base.Install();
 32         }
 33 
 34         public override void Uninstall()
 35         {
 36             //To configure
 37             _settingService.DeleteSetting<AliPayPaymentSettings>();
 38 
 39             //Localization Resources
 40             this.DeletePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.SellerEmail.RedirectionTip");
 41             this.DeletePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.SellerEmail");
 42             this.DeletePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.SellerEmail.Hint");
 43             this.DeletePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.Key");
 44             this.DeletePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.Key.Hint");
 45             this.DeletePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.Partner");
 46             this.DeletePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.Partner.Hint");
 47             this.DeletePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.AdditionalFee");
 48             this.DeletePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.AdditionalFee.Hint");
 49             this.DeletePluginLocaleResource("DaBoLang.Plugins.Payments.AliPay.PaymentMethodDescription");
 50 
 51             //Unloading data sheet
 52             _objectContext.Uninstall();
 53 
 54             base.Uninstall();
 55         }
 56 
 57         #endregion
Plug-in Installation/Unloading
  1 using Nop.Core.Configuration;
  2 
  3 namespace DaBoLang.Nop.Plugin.Payments.AliPay
  4 {
  5     /// <summary>
  6     /// Namespace: DaBoLang.Nop.Plugin.Payments.AliPay
  7     /// Name: AliPay Payment Settings
  8     /// Function: Configuration class
  9     //Details: Alipay configuration
 10     /// Version: 1.0.0.0
 11     /// File name: AliPayPaymentSettings.cs
 12     /// Author: Big Wave
 13     /// Contact: http://www.cnblogs.com/yaoshangjin
 14     /// Description:
 15     /// </summary>
 16     public class AliPayPaymentSettings : ISettings
 17     {
 18         /// <summary>
 19         /// Seller Email
 20         /// </summary>
 21         public string SellerEmail { get; set; }
 22         /// <summary>
 23         /// Key
 24         /// </summary>
 25         public string Key { get; set; }
 26         /// <summary>
 27         /// PID
 28         /// </summary>
 29         public string Partner { get; set; }
 30         /// <summary>
 31         /// Additional costs
 32         /// </summary>
 33         public decimal AdditionalFee { get; set; }
 34     }
 35 }
 36 
AliPayPaymentSettings

Finally, look at the installation and unloading process.

Plug-in Configuration

Next, we develop plug-in configuration and support multiple store settings. The GetConfiguration Route method in the plug-in class is used to return routing information. We define a route to

Routing under the Configure method of the AliPayController controller, which handles configuration.

The ConfigurationModel.cs class in the Models folder is a model class for communicating data between the controller and the view. There is no further discussion here.

Payment function

    

When we pay, we need to jump to Alipay page for operation, so AliPayPaymentProcessor class

PaymentMethodType returns PaymentMethodType.Redirection tells nop that we need to pay to a third party. _

  1  public PaymentMethodType PaymentMethodType
  2         {
  3             get
  4             {
  5                 return PaymentMethodType.Redirection;
  6             }
  7         }

The PostProcessPayment method is then implemented to process Alipay payments. The Alipay folder is a Alipay helper class.

  1  public void PostProcessPayment(PostProcessPaymentRequest postProcessPaymentRequest)
  2         {
  3             var partner = _aliPayPaymentSettings.Partner;
  4 
  5             if (string.IsNullOrEmpty(partner))
  6                 throw new Exception("Cooperative Identity ID Can't be empty");
  7 
  8             var key = _aliPayPaymentSettings.Key;
  9 
 10             if (string.IsNullOrEmpty(key))
 11                 throw new Exception("MD5 Key cannot be empty");
 12 
 13             var sellerEmail = _aliPayPaymentSettings.SellerEmail;
 14 
 15             if (string.IsNullOrEmpty(sellerEmail))
 16                 throw new Exception("seller Email Can't be empty");
 17 
 18             var customer = _workContext.CurrentCustomer;//Current User
 19             string username = customer.Username;
 20 
 21 
 22             //Merchant order number, the only order number in the order system of merchant website, must be filled in
 23             string out_trade_no = postProcessPaymentRequest.Order.Id.ToString().Trim();//Order Number
 24 
 25             //Order name, required
 26             string subject = _storeContext.CurrentStore.Name + ":Order" + out_trade_no;
 27 
 28             //Payment amount must be filled in
 29             string total_fee = postProcessPaymentRequest.Order.OrderTotal.ToString("0.00", CultureInfo.InvariantCulture);
 30 
 31             //Goods description, empty
 32             string body = _storeContext.CurrentStore.Name + ":user_" + username;
 33 
 34             //Payment configuration information
 35             var aliPayDirectConfig = new AlipayDirectConfig()
 36             {
 37                 key = _aliPayPaymentSettings.Key,
 38                 partner = _aliPayPaymentSettings.Partner,
 39                 seller_email = _aliPayPaymentSettings.SellerEmail,
 40                 notify_url = _webHelper.GetStoreLocation(false) + "Plugins/AliPay/Notify",
 41                 return_url = _webHelper.GetStoreLocation(false) + "Plugins/AliPay/Return",
 42                 sign_type = "MD5",
 43                 input_charset= "utf-8",
 44             };
 45             //Packing request parameters into arrays
 46             SortedDictionary<string, string> sParaTemp = new SortedDictionary<string, string>();
 47             sParaTemp.Add("service", aliPayDirectConfig.service);
 48             sParaTemp.Add("partner", aliPayDirectConfig.partner);
 49             sParaTemp.Add("seller_email", aliPayDirectConfig.seller_email);
 50             sParaTemp.Add("payment_type", aliPayDirectConfig.payment_type);
 51             sParaTemp.Add("notify_url", aliPayDirectConfig.notify_url);
 52             sParaTemp.Add("return_url", aliPayDirectConfig.return_url);
 53             sParaTemp.Add("_input_charset", aliPayDirectConfig.input_charset);
 54             sParaTemp.Add("out_trade_no", out_trade_no);
 55             sParaTemp.Add("subject", subject);
 56             sParaTemp.Add("body", body);
 57             sParaTemp.Add("total_fee", total_fee);
 58             //Create Alipay request
 59             var post = AlipaySubmit.BuildRequest(sParaTemp, aliPayDirectConfig, "POST");
 60             post.Post();
 61 
 62         }
PostProcessPayment

When calling the Alipay interface, you need to set up the notify_url address to receive the payment notice, and the return_url address will jump to the address after payment is successful.

  1 notify_url = _webHelper.GetStoreLocation(false) + "Plugins/AliPay/Notify",
  2 return_url = _webHelper.GetStoreLocation(false) + "Plugins/AliPay/Return",

The RouteProvider.cs class is used to register routes, where routes with the two addresses above are defined.

  1 using System.Web.Mvc;
  2 using System.Web.Routing;
  3 using Nop.Web.Framework.Mvc.Routes;
  4 
  5 namespace DaBoLang.Nop.Plugin.Payments.AliPay
  6 {
  7     /// <summary>
  8     /// Namespace: DaBoLang.Nop.Plugin.Payments.AliPay
  9     /// Name: RouteProvider
 10     /// Function: Routing
 11     /// Details: Define routing
 12     /// Version: 1.0.0.0
 13     /// File name: RouteProvider.cs
 14     /// Author: Big Wave
 15     /// Contact: http://www.cnblogs.com/yaoshangjin
 16     /// Description:
 17     /// </summary>
 18     public partial class RouteProvider : IRouteProvider
 19     {
 20         #region Methods
 21 
 22         public void RegisterRoutes(RouteCollection routes)
 23         {
 24             //Payment notification routing
 25             routes.MapRoute("DaBoLang.Plugin.Payments.AliPay.Notify",
 26                  "Plugins/AliPay/Notify",
 27                  new { controller = "AliPay", action = "Notify" },
 28                  new[] { "DaBoLang.Nop.Plugin.Payments.AliPay.Controllers" }
 29             );
 30 
 31             //Payment Page Skip Synchronization Notification Page
 32             routes.MapRoute("DaBoLang.Plugin.Payments.AliPay.Return",
 33                  "Plugins/AliPay/Return",
 34                  new { controller = "AliPay", action = "Return" },
 35                  new[] { "DaBoLang.Nop.Plugin.Payments.AliPay.Controllers" }
 36             );
 37 
 38             //Return notification routing
 39             routes.MapRoute("Plugin.Payments.AliPay.RefundNotify",
 40               "Plugins/AliPay/RefundNotify",
 41               new { controller = "AliPay", action = "RefundNotify" },
 42               new[] { "DaBoLang.Nop.Plugin.Payments.AliPay.Controllers" }
 43             );
 44         }
 45 
 46         #endregion
 47 
 48         #region Properties
 49 
 50         public int Priority
 51         {
 52             get
 53             {
 54                 return 0;
 55             }
 56         }
 57 
 58         #endregion
 59     }
 60 }
 61 
RouteProvider

Plugins/AliPay/Notify calls the Notify method of the AliPayController controller class for processing

Plugins/AliPay/Return calls the AliPayController controller class Return method for processing

The AliPayController->Notify method is used to receive the Alipay notification, which will be invoked when the payment is successful. The method will process the order payment status and add the payment record in the payment information table.

The AliPayController - > Return method defines the return location.

9. Refund function

To support full refund, the plug-in class SupportRefund attribute needs to return true, and the support part of refund needs SupportPartiallyRefund attribute to return true.

The refund needs to implement the Refund method. When the refund operation is done, nop will call the Refund method. The new refund information will be saved in the refund form and then redirected to Alipay to make a confidential refund.

Alipay interface also needs notify_url address, which is used for notification after successful refund. We have defined the refund notification routing in the front RouteProvider routing table, and AliPayController controller RefundNotify method.

RefundNotify method can change the order payment status, modify the order refund amount, modify the refund status in the refund record table and so on. See the source code for the specific implementation.

X. Services

Services folder for saving service classes .

IPaymentInfoService Interface: Used for processing payment records, such as checking the addition, deletion and alteration of payment forms.

IRefund InfoService Interface: Used for processing refund records, such as adding, deleting and modifying refund forms.

nop uses IRepository < T > for data processing encapsulation (Dao layer), T for entity class

  1 #region attribute
  2 private readonly IRepository<RefundInfo> _refundInfoRepository;
  3 #endregion
  4 #region structure
  5 public RefundInfoService(IRepository<RefundInfo> refundInfoRepository)
  6 {
  7      this._refundInfoRepository = refundInfoRepository;
  8 }
  9 #endregion

Next, create the interface implementation class, PaymentInfoService and RefundInfoService to implement business logic.

Finally, we need to register the interface and implementation classes in the Dependency Registrar file.

  1 //Registered Payment Recording Service
  2  builder.RegisterType<PaymentInfoService>().As<IPaymentInfoService>().InstancePerLifetimeScope();
  3 //Registered Refund Recording Service
  4 builder.RegisterType<RefundInfoService>().As<IRefundInfoService>().InstancePerLifetimeScope();

XI. Summary

Note: when debugging, the project must be deployed in the public network, so that Alipay can correctly call the notification address, otherwise the plug-in will fail.

Please correct any incorrect points in this article. If you think this article is helpful to you, please reprint and support it.

This article addresses: http://www.cnblogs.com/yaoshangjin/p/7290003.html

This article is originally created and reproduced by big waves. Please indicate the source.

Posted by Guardian-Mage on Fri, 07 Jun 2019 15:24:34 -0700