nopCommerce 3.9 wave series refundable Alipay plugin (next)
Keywords:
ASP.NET
Database
SQL
Attribute
xml
I. Review
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:
- Multi-Store Plug-in Configuration
- Payment function
- Refund function
Database support:
- Add dbl_PaymentInfo table to save payment records.
- Add dbl_RefundInfo table to save the refund record.
Other preparations:
- Alipay instant arrival PID and MD5 secret key Key can be acquired through Alipay open platform.

III. Process Planning
- 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
- This paper introduces the expansion of payment plug-in interface through a complete example.
- Implement IPaymentMethod interface for payment plug-in interface extension.
- The AliPayObjectContext database context is extended to manipulate database tables.
- Understand Alipay's immediate arrival payment and refund process.
- Route registration, dependency injection registration.
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